Thursday, February 21, 2013

Массивы: упорядоченные коллекции Cocoa

http://macbug.ru/cocoa/cdarray#.USY5C1pp5Xd

Массивы: упорядоченные коллекции

Cocoa

Массивы - упорядоченные коллекции любого вида объектов. Например, объекты, содержащиеся в массиве на рисунке 1 может быть любой комбинацией объектов для яблок и груш, если массив изменяемый, Вы можете добавить больше объектов собак. Коллекция не должна быть однородной.

Рисунок 1 массивы

cocoa array
Информация по производительности:
  • Доступ к элементу массива занимает постоянное время.
  • Присоединение и удаление элементов с обоих концов занимает постоянное время.
  • Замена элемента занимает постоянное время.
  • Вставка элемента в середину массива занимает линейное время.

Основы массивов

Объект NSArray управляет неизменным массивом, то есть после того как вы создаете массив, вы не можете добавлять, удалять или заменять объекты. Можно, однако, изменить отдельные элементы сами (если они поддерживают изменения). Изменчивость коллекции не влияет на изменчивость объектов в коллекции. Вы должны использовать массив неизменным, если массив редко изменяется или изменяется массово.

Объект NSMutableArray управляет изменяемым массивом, который позволяет добавлять и удалять записи в любое время, автоматически выделяя память по мере необходимости. Например, если NSMutableArray объект, который содержит только один объект яблоко, вы можете добавить еще одно яблоко или грушу, или любой другой объект. Вы можете также, как и объект NSArray, изменить имя яблока и в общем, все, что можно сделать с помощью NSArray объекта вы можете сделать с NSMutableArray объектом. Вы должны использовать изменяемый массив, если массив изменяется постепенно и очень большой, так как большие коллекции занимают больше времени для инициализации.

Вы можете легко создать экземпляр одного типа массива из другого, используя инициализатор initWithArray: или удобным конструктором arrayWithArray. Например, если у вас есть экземпляр NSArraymyАггау, вы можете создать изменяемую копию следующим образом:

NSMutableArray *myMutableArray = [NSMutableArray arrayWithArray:myArray];

В общем Вашему экземпляру массива посылается сообщение array... или NSArray или NSMutableArray класса. array... сообщение возвратит массив, содержащий элементы, переданные в качестве аргумента. Когда вы добавляете объект к NSMutableArray объект не копируется (если вы не передали YES в аргументе метода initWithArray:copyItems:). Скорее всего, объект добавляется непосредственно в массив. В среде управления памятью объект получает сообщение retain, когда добавляется к массиву. Когда массив освобождается, каждый элемент получает сообщение release. Для более подробной информации см. раздел "Копирование коллекций".

В NSArray, два основных метода: -count и objectAtIndex: -обеспечивает основу для всех других методов в интерфейсе:

count возвращает количество элементов в массиве.

objectAtIndex: обеспечивает доступ к элементам массива. Отсчет элементов начинается с индекса 0.

Изменяемые массивы

Основные методы в NSMutableArray, перечисленные ниже, служат основой для его способности добавлять, заменять и удалять элементы:
      addObject:      insertObject:atIndex:      removeLastObject      removeObjectAtIndex:      replaceObjectAtIndex:withObject:  

Если Вам не нужен объект для размещения по указанному индексу или удалить из середины коллекции, Вы должны использовать AddObject:,removeLastObject методы, потому что добавлять и удалять в конец массива быстрее, чем в середину.

другие методы в NSMutableArray обеспечивают удобный способ вставки объекта в слот в массиве и удаление объекта на основе его идентичности или позиции в массиве, как показано ниже:

NSMutableArray *array = [NSMutableArray array];  [array addObject:[NSColor blackColor]];  [array insertObject:[NSColor redColor] atIndex:0];  [array insertObject:[NSColor blueColor] atIndex:1];  [array addObject:[NSColor whiteColor]];  [array removeObjectsInRange:(NSMakeRange(1, 2))];  // array теперь содержит redColor и whiteColor  

В среде управления памятью, когда объект удаляется из массива, он получает сообщение release. Если этот объект принадлежал только этому массиву, то он будет уничтожен, после удаления из массива. Если вы хотите продолжать использовать этот объект, то вы должны послать ему сообщение retain перед удалением из массива.

Использование массивов

Вы можете получить доступ к элементу массива по индексу, используя метод objectAtIndex:

NSString *s=[arrayOfStrings objectAtIndex: 2]; // доступ к третьему элементу массива

Методы objectEnumerator и reverseObjectEnumerator предоставляют последовательный доступ к элементам массива, отличаясь только в направлении движения по элементам. Кроме того, методы makeObjectsPerformSelector: и makeObjectsPerformSelector:withObject: позволяет отправлять сообщения во все объекты в массиве. В большинстве случаев, следует использовать быстрое перечисление, поскольку это быстрее и гибче, чем при использовании NSEnumerator или метода makeObjectsPerformSelector:. Более подробную информацию о перечислении смотрите в разделе "Перечисление. Обход элементов коллекции".

Вы можете извлечь подмножество массива (subarrayWithRange:) или объединить элементы массива объекта NSString в одну строку (componentsJoinedByString:). Кроме того, вы можете сравнить два массива использованием методов isEqualToArray: иfirstObjectCommonWithArray:. Наконец, вы можете создать новый массив, который будет содержать объекты из существующего массива и один или несколько дополнительных объектов arrayByAddingObject: или arrayByAddingObjectsFromArray:.

Существуют два основных способа, которые можно использовать, чтобы определить, присутствует ли объект в массиве, indexOfObject: иindexOfObjectIdenticalTo:. Есть также два варианта, indexOfObject:inRange: и indexOfObjectIdenticalTo:inRange:, которые вы можете использовать для поиска в диапазоне, в пределах массива. Методы indexOfObject: для проверки на равенство, отправляют элементам в массиве сообщенияisEqual:; методы indexOfObjectIdenticalTo: испытывают на равенство с помощью указателя сравнения. Разница показана в листинге ниже:

NSString *yes0 = @"yes";  NSString *yes1 = @"YES";  NSString *yes2 = [NSString stringWithFormat:@"%@", yes1];    NSArray *yesArray = [NSArray arrayWithObjects: yes0, yes1, yes2, nil];    NSUInteger index;    index = [yesArray indexOfObject:yes2];  // index is 1 (эквивалентен)    index = [yesArray indexOfObjectIdenticalTo:yes2];  // index is 2 (равен)  

Сортировка массивов

Вам может понадобиться сортировка массива на основе некоторых критериев. Например, вам может потребоваться разместить несколько созданных пользователем строк в алфавитном порядке, либо вам потребуется разместить номера в убыванию или по возрастанию. На рисунке 2 показан массив отсортированный по фамилиям и именам. Cocoa обеспечивает удобные способы для сортировки содержимого массива, такие как своего рода дескрипторы,блоков и селекторов.

Рисунок 2 Сортировка массивов

Cocoa NSArray sorting

Сортировка с дескрипторами сортировки

Дескрипторы сортировки (экземпляры NSSortDescriptor) обеспечивают удобный и абстрактный способ описания порядка сортировки. Дескриптор сортировки предоставляет несколько полезных функций. Вы можете легко выполнять большинство операций сортировки с минимальным пользовательским кодом. Вы также можете использовать дескрипторы сортировки в сочетании с Cocoa bindings для сортировки содержимого, например, таблицы. Вы также можете использовать их с Core Data для сортировки результатов запроса выборки.

Если вы используете методы sortedArrayUsingDescriptors: или sortUsingDescriptors:, дескрипторы сортировки обеспечивают простой способ сортировки коллекций объектов, используя ряд их свойств. Учитывая множество словарей (пользовательские объекты работают таким же образом), вы можете отсортировать его содержимое по фамилии, имени. Следующий листинг показывает, как создать этот массив, а затем отсортировать с дескрипторами. (На рисунке 2 показан пример этого примера.)

//Сначала создадим массив из словарей  NSString *LAST = @"lastName";  NSString *FIRST = @"firstName";    NSMutableArray *array = [NSMutableArray array];  NSArray *sortedArray;    NSDictionary *dict;  dict = [NSDictionary dictionaryWithObjectsAndKeys:                     @"Jo", FIRST, @"Smith", LAST, nil];  [array addObject:dict];    dict = [NSDictionary dictionaryWithObjectsAndKeys:                     @"Joe", FIRST, @"Smith", LAST, nil];  [array addObject:dict];    dict = [NSDictionary dictionaryWithObjectsAndKeys:                     @"Joe", FIRST, @"Smythe", LAST, nil];  [array addObject:dict];    dict = [NSDictionary dictionaryWithObjectsAndKeys:                     @"Joanne", FIRST, @"Smith", LAST, nil];  [array addObject:dict];    dict = [NSDictionary dictionaryWithObjectsAndKeys:                     @"Robert", FIRST, @"Jones", LAST, nil];  [array addObject:dict];    //Далее сортируем содержимое массива по last name затем first name    // Результаты могут быть показаны пользователю  // Обратите внимание на использование localizedCaseInsensitiveCompare: selector    NSSortDescriptor *lastDescriptor =      [[[NSSortDescriptor alloc] initWithKey:LAST                ascending:YES                selector:@selector(localizedCaseInsensitiveCompare:)] autorelease];  NSSortDescriptor *firstDescriptor =      [[[NSSortDescriptor alloc] initWithKey:FIRST                ascending:YES                selector:@selector(localizedCaseInsensitiveCompare:)] autorelease];    NSArray *descriptors = [NSArray arrayWithObjects:lastDescriptor,                                     firstDescriptor, nil];  sortedArray = [array sortedArrayUsingDescriptors:descriptors];  

Направление и первый параметр сортировки легко изменить концептуально и программно, как показано ниже:

NSSortDescriptor *lastDescriptor =          [[[NSSortDescriptor alloc] initWithKey:LAST               ascending:NO               selector:@selector(localizedCaseInsensitiveCompare:)] autorelease];    NSSortDescriptor *firstDescriptor =      [[[NSSortDescriptor alloc] initWithKey:FIRST               ascending:NO               selector:@selector(localizedCaseInsensitiveCompare:)] autorelease];    NSArray *descriptors = [NSArray arrayWithObjects:firstDescriptor,               lastDescriptor, nil];  sortedArray = [array sortedArrayUsingDescriptors:descriptors];  

В частности, это несложно для создания подобных дескрипторов от пользовательского ввода.

В отличие от этого, ниже показана первая сортировка с помощью функции. Такой подход значительно менее гибкий.

NSInteger lastNameFirstNameSort(id person1, id person2, void *reverse)  {      NSString *name1 = [person1 valueForKey:LAST];      NSString *name2 = [person2 valueForKey:LAST];        NSComparisonResult comparison = [name1 localizedCaseInsensitiveCompare:name2];      if (comparison == NSOrderedSame) {          name1 = [person1 valueForKey:FIRST];          name2 = [person2 valueForKey:FIRST];          comparison = [name1 localizedCaseInsensitiveCompare:name2];      }        if (*(BOOL *)reverse == YES) {          return 0 - comparison;      }      return comparison;  }    BOOL reverseSort = YES;  sortedArray = [array sortedArrayUsingFunction:lastNameFirstNameSort      context:&reverseSort];  

Сортировка с блоками

Вы можете использовать блоки, чтобы отсортировать массив на основе пользовательских критериев. Метод NSArray sortedArrayUsingComparator:сортирует массив в новый массив, используя блок для сравнения объектов. Метод sortUsingComparator: класса NSMutableArray сортирует массив на месте, используя блок для сравнения объектов. Листинг ниже показывает, сортировку с блоком.

NSArray *sortedArray = [array sortedArrayUsingComparator: ^(id obj1, id obj2) {       if ([obj1 integerValue] > [obj2 integerValue]) {            return (NSComparisonResult)NSOrderedDescending;       }         if ([obj1 integerValue] < [obj2 integerValue]) {            return (NSComparisonResult)NSOrderedAscending;       }       return (NSComparisonResult)NSOrderedSame;  }];  

Сортировка с помощью функций и селекторов

Следующий листинг иллюстрирует использование методов sortedArrayUsingSelector:sortedArrayUsingFunction:context:, иsortedArrayUsingFunction:context:hint:. Самым сложным из этих методов является sortedArrayUsingFunction:context:hint:. Он наиболее эффективен, когда у вас есть большой массив (N записей), которые вам надо отсортировать раз и затем лишь слегка изменить (P добавлений и удалений, где P гораздо меньше, чем N). Вы можете использовать работу, которую вы сделали в оригинальнй сортировке, и сделать своего рода слияние между N "старых" предметов и Р "новых" предметов. Чтобы получить соответствующую подсказку, вы используете sortedArrayHint когда исходный массив был отсортирован, и держите его, пока вам это нужно (если вы хотите, отсортировать массив после того, как он был изменен).

NSInteger alphabeticSort(id string1, id string2, void *reverse)  {      if (*(BOOL *)reverse == YES) {          return [string2 localizedCaseInsensitiveCompare:string1];      }      return [string1 localizedCaseInsensitiveCompare:string2];  }    NSMutableArray *anArray =      [NSMutableArray arrayWithObjects:@"aa", @"ab",        @"ac", @"ad", @"ae", @"af", @"ag",        @"ah", @"ai", @"aj", @"ak", @"al", @"am", @"an",        @"ao", @"ap", @"aq", @"ar", @"as", @"at",        @"au", @"av", @"aw", @"ax", @"ay", @"az", @"ba",        @"bb", @"bc", @"bd", @"bf", @"bg", @"bh",        @"bi", @"bj", @"bk", @"bl", @"bm", @"bn", @"bo",        @"bp", @"bq", @"br", @"bs", @"bt", @"bu",        @"bv", @"bw", @"bx", @"by", @"bz", @"ca", @"cb",        @"cc", @"cd", @"ce", @"cf", @"cg", @"ch",        @"ci", @"cj", @"ck", @"cl", @"cm", @"cn", @"co",        @"cp", @"cq", @"cr", @"cs", @"ct", @"cu",        @"cv", @"cw", @"cx", @"cy", @"cz", nil];  // внимание: anArray отсортирован  NSData *sortedArrayHint = [anArray sortedArrayHint];    [anArray insertObject:@"be" atIndex:5];    NSArray *sortedArray;    // сортировка используя селектор  sortedArray =       [anArray sortedArrayUsingSelector:@selector(localizedCaseInsensitiveCompare:)];    // сортировка используя функцию  BOOL reverseSort = NO;  sortedArray =       [anArray sortedArrayUsingFunction:alphabeticSort context:&reverseSort];    // сортировка с подсказкой  sortedArray =       [anArray sortedArrayUsingFunction:alphabeticSort                                    context:&reverseSort                                       hint:sortedArrayHint];  

Важно: Если вы сортируете массив строк, который должен быть показан конечному пользователю, вы должны всегда использовать локализованные сравнения. На других языках или контекстах, правильный порядок в отсортированном массиве может быть различным.

Фильтрация массивов

Классы NSArray и NSMutableArray предоставляют методы для фильтрации содержимого массива. NSArray обеспечиваетfilteredArrayUsingPredicate:, который возвращает новый массив, содержащий объекты в приемнике, который соответствует указанному предикату.NSMutableArray добавляет filterUsingPredicate:, который оценивает содержимое получателя по отношению у указанному предикату и оставляет только те объекты, которые соответствуют. Эти методы показаны ниже. Более подробную информацию о предикатах см. в "Руководстве по программированию предикатов".

NSMutableArray *array =      [NSMutableArray arrayWithObjects:@"Bill", @"Ben", @"Chris", @"Melissa", nil];    NSPredicate *bPredicate =      [NSPredicate predicateWithFormat:@"SELF beginswith[c] 'b'"];  NSArray *beginWithB =      [array filteredArrayUsingPredicate:bPredicate];  // beginWithB содержит { @"Bill", @"Ben" }.    NSPredicate *sPredicate =      [NSPredicate predicateWithFormat:@"SELF contains[c] 's'"];  [array filterUsingPredicate:sPredicate];  // array теперь содержит { @"Chris", @"Melissa" }  

Вы можете также фильтровать массив, используя объект NSIndexSetNSArray обеспечивает objectsAtIndexes:, который возвращает новый массив, содержащий объекты на индексах в соответствующем индексном наборе. NSMutableArray добавляет removeObjectsAtIndexes:, который позволяет фильтровать массив на месте с помощью набора индексов. Для получения дополнительной информации об индексных наборах см. "Индексные наборы: Хранение индексов в массиве".

Массив указателей

IOS Примечание: класс NSPointerArray не доступен в IOS.

Класс NSPointerArray по умолчанию настраивается на распоряжение объектами также, как это делает NSMutableArray, кроме того, что он может содержать nilзначения и того, что метод count отражает эти нулевые значения. Он также позволяет дополнительные опции по хранению данных, которые вы можете приспособить для конкретных случаев, например, когда вам нужны расширенные возможности управления памятью, или если вы хотите распоряжаться определенным типом указателя. Например, массив указателей на рисунке 3 настроен на распоряжение слабыми (weak) ссылками на его содержимое. Вы также можете указать, хотите ли вы скопировать объекты, которые введены в массив.

Рисунок 3 Массив Указателей на объекты

Cocoa NSPointerArray

Вы можете использовать NSPointerArray объект, если вы хотите получить упорядоченный набор, который использует слабые (weak) ссылки в среде сборки мусора. Например, предположим, у вас есть глобальный массив, который содержит некоторые объекты. Поскольку глобальные объекты не собираются, ни один объект из его содержимого не может быть освобожден, если они проводятся слабо. Массив указателей настроен на слабое распоряжение объектами, не владея их содержимым. Если нет сильных (strong) ссылок на объекты в таком массиве указателей, эти объекты могут быть собраны сборщиком мусора. Например, массив указателей на рисунке 3 имеет слабые ссылки на содержимое. В течение следующего сбора, объекты D и E освобождаются (и их указатели устанавливаются в nil), а остальные объекты остаются. Если это должным образом не учесть, такая практика может привести к непредсказуемому поведению.

Для создания массива указателей, создайте или инициализируйте его с помощью pointerArrayWithOptions: или initWithOptions:, и соответствующими параметрами NSPointerFunctionsOptions. Альтернативно вы можете инициализировать его с помощью initWithPointerFunctions:, и соответствующих экземпляров NSPointerFunctions.

Класс NSPointerArray также определяет ряд удобных конструкторов для создания массива указателей с сильными или слабыми ссылками на его содержимое. Например, pointerArrayWithWeakObjects создает массив указателей, который содержит слабые ссылки на его содержимое. Эти удобства конструкторов должны использоваться только если вы храните объекты.

Для настройки массива указателей использующий произвольные указатели можно инициализировав его с опциями NSPointerFunctionsOpaqueMemory и NSPointerFunctionsOpaquePersonality. Например, вы можете добавить указатель на целочисленное значение, используя подход, показанный в листинге ниже:

NSPointerFunctionOptions options=(NSPointerFunctionsOpaqueMemory |       NSPointerFunctionsOpaquePersonality);     NSPointerArray *ptrArray=[NSPointerArray pointerArrayWithOptions: options];    [ptrArray addPointer: someIntPtr];  

Вы можете получить доступ к целым, как показано ниже.

NSLog(@" Index 0 contains: %i", *(int *) [ptrArray pointerAtIndex: 0] );

Когда используются настройки на использование произвольных указателей, массив указателей получает риски, связанные с использованием указателей. Например, если указатели ссылаются на стековые данные, созданные внутри функции, эти указатели не являются допустимыми за пределами функции, даже если указатели в массиве. Попытка получить доступ к ним приведет к неопределенному поведению.

Tuesday, February 19, 2013

how to work with UITableViewCellAccessoryDetailDisclosureButton

http://hghltd.yandex.net/yandbtm?src=F&text=how%20to%20work%20with%20UITableViewCellAccessoryDetailDisclosureButton&url=http%3A%2F%2Fchris-software.com%2Findex.php%2Ftag%2Fuitableview%2F&fmode=inject&mime=html&l10n=ru&sign=e6ad769521a97d36e9ada08c33ad50ed&keyno=0

how to work with UITableViewCellAccessoryDetailDisclosureButton

Tables

May 5th, 2009

Tables – strictly UITableView, are very often used in utilities, content managers, lists and more. There are many examples of tables in applications that came with every iPhone:

  • Phone application: Favourites, Recents, Contacts
  • SMS application: list of contacts you recently text messaged (not sure about the chat bubbles – it can be UIScrollView)
  • Calendar application: list of Calendars, List view of selected calendar
  • Photos application: list of Photo Albums
  • YouTube application: every tab contains UITableView
  • Weather application: flip-side view where you can add cities
  • Notes application: list of notes
  • Settings application: whole application
  • App Store application: every tab
  • Clock application: World Clock, Alarm, Stopwatch

tableview1 tableview2 tableview3 tableview4 tableview5

As you see UITableView is not only a white list with black text on it. Table (strictlyUITableViewCell) can be customized in many ways, it can not only have many sections, headers, footers, edit and reorder functionality but even a custom view.

Let's start

Create a UIViewController and View XIB. Name them all whatever you like (in my project I use:MyView.hMyView.mMyView.xib). In App Delegate add standard lines:

#import "MyView.h"    @class MyView;

and:

	MyView *viewController = [[MyView alloc] initWithNibName:@"MyView" bundle:[NSBundle mainBundle]];  	[window addSubview:[viewController view]];

Open MyView.xib and set that it's class is MyView, add UITableView and UIToolbar orUINavigationBar on top – might be important later. The view should look like this:

interfacetableprepare

Don't close Interface Builder and edit MyView.h in Xcode. Add two protocols to UIViewController:UITableViewDelegate (responsible for a lot of actions with tables) and UITableViewDataSource(providing data to be displayed in the table). Add also an IBOutlet of UITableView. Although almost everything will be passed to table you created in Interface Builder via protocols, but this object might be helpful in some cases I will discuss later.

MyView.h

  #import <UIKit/UIKit.h>    @interface MyView : UIViewController <UITableViewDelegate, UITableViewDataSource> {  	IBOutlet UITableView *myTable;  }    @end

Compile your project and return to Interface Builder and make connections. myTable withUITableViewview with View and click on UITableView again, and in Table View Connections, connect dataSource and delegate with File's Owner. Save MyView.xib.

Before you can debug your application you need to implement two method that are required to use UITableView:

  1. numberOfRowsInSection – how many rows each section has
  2. cellForRowAtIndexPath – creates cells – UITableViewCell

So you need to implement above methods in your class:

  - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {  	return 20; // every section has 5 rows  }
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {  	NSLog(@"cellForRowAtIndexPath called");  	static NSString *CellIdentifier = @"Cell";  	UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];  	if (cell == nil) { NSLog(@"new cell");  		cell = [[[UITableViewCell alloc] initWithFrame:CGRectZero reuseIdentifier:CellIdentifier] autorelease];  	}  	cell.text = [NSString stringWithFormat@"Cell #%i"indexPath.row];  	return cell;  }

simplestableview

If you Build & Go your project, you should get:

As you see numberOfRowsInSection method is quite obvious. In above example. I'm telling – preparing the table to display 8 rows in each section. As long as I didn't tell the table how many sections there are in the table it assumes that I want to have 1 section.cellForRowAtIndexPath is "a little bit" more complex. Go toDebugger Console (Command+Shift+R) to open logs. Inside this method I added two functions to log whenever the method was called and whenever the cell is empty object (nil). To better understand this change the numberOfRowsInSection to return 20 for example, Build & Go your project and study logs while scrolling theUITableViewConclusion: because of memory management and overall performance cellForRowAtIndexPath is only called to show the visible cells, and when you scroll back to see the cells that have been already loaded, cellForRowAtIndexPath is called again, but it remembers their settings and customization and reuse them instead of allocating again. If you don't understand this, treat it like a template you need to use in most cellForRowAtIndexPathmethod. indexPath gives you two information, what is the section of current cell (indexPath.section) and row (indexPath.row).

Dynamic data source

dynamicdatasimulatorIn this tutorial I will only show you simple examples of usingUITableView, but you could prepare NSMutableArray to be displayed in UITableView. To do so, first add an NSMutableArray in header of your class:

	NSMutableArray *dataForTable;

and in viewDidLoad method:

  - (void)viewDidLoad {  	dataForTable = [[NSMutableArray alloc] initWithObjects:  					@"First row",  					@"Second row",  					@"Third row",  					nil];  	[dataForTable retain];  	[super viewDidLoad];  }

Now, numberOfRowsInSection shouldn't return the static number 8, 20, or any other, but:

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {  	return [dataForTable count];  }

And cellForRowAtIndexPath shouldn't tell you what is the row's number, but the object (NSString) from NSMutableArray.

	cell.text = [dataForTable objectAtIndex:indexPath.row];

Please note: once you changed the objects in dataForTable you can call [myTable reloadData]; to redraw the table with new data.

Table Styles

tablestyleplaintablestylegrouped
There are two styles you can apply to UITableViewPlain (left, default) has "sticky headers",Grouped (right) has rounded edges and stripped, gray background. Altough, so far there was no headers displayed by your code you can compare these two styles in Phone and Settingsapplication. You can switch the style in Xcode, but as long as you are using Interface Builder, simply go to Table View Attributes and change the Style property.

Sections

By default there is one section in every UITableView. If you want more – seperate one group of rows from the other, you have to implement the numberOfSectionsInTableView method:

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {      return 2;  }

Above method will gave us one of these two results:

sectionsplain sectionsgrouped

You should notice two things. In grouped style the space between sections is clearly visible, but not in plain style as long as you don't provide headers' names. The second: both sections are identical, that's because numbersOfRowsInSection is returning always the same value and the same is with cellForRowAtIndexPath. You can easily change it. You could do it dynamicaly, as shown before, but I will use switch instruction:

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {  	switch (section) {  		case 0:  			return 5;  			break;  		case 1:  			return 2;  			break;  	}  	return 0;  }

customsectionsAnd (instead of cell.text = [NSString ...);

	switch (indexPath.section) {  		case 0:  			cell.text = [NSString stringWithFormat:@"Happy Cell #%i",indexPath.row];;  			break;  		case 1:  			cell.text = [NSString stringWithFormat:@"Sad Cell #%i",indexPath.row];;  			break;  	}

This code should be easily understandable for you. I've not done anything else but used switch instruction to return / assign different values for given cases. Since now, I'm going to skip switchinstructions in sample codes, you should implement them on your own easily.

Header and footer

headerfootergrouped headerfooterplain

As you see the grouped UITableView looks amazing with headers and footers, but for plain style, you should use only headers because it doesn't look good - header and footer look exactly the same. To achieve something like this you need to implement these two methods:

-(NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {  	return @"Section title";  }
- (NSString *)tableView:(UITableView *)tableView titleForFooterInSection:(NSInteger)section {  	return @"Footer title";  }

Please note: if you return nil header / footer won't be displayed

Section index

tableindexWhen you scroll the contact list, the small letters A-Z on the right are very helpful, aren't thay? It's very easy to implement something like this.

- (NSArray *)sectionIndexTitlesForTableView:(UITableView *)tableView {  	NSMutableArray *index = [[NSMutableArray alloc] initWithObjects:@"A",@"B",@"C",@"D",nil];  	return index;  }

In index array you have to provide that titles that will be displayed on the whole height of UITableView on the right. The titles don't have to be the same as the headers' titles (but their should, or be similar). If you provide more index titles than there are sections inUITableView, most of them will navigate to the bottom section.

Please note: sectionIndexTitlesForTableView should return aNSArray object, but you are returning NSMutableArray, don't worry,NSMutableArray is just a subclass of NSArray so this is acceptable and doesnn't cause any logical errors.

Please note: section index works only in plain style of UITableView.

Pressing the cell

cellpressedThe cell usually links to some actions. Here is the sample action to displays an alert with information what cell was selected.

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {  	UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Cell pressed" message:[NSString stringWithFormat:@"Cell #%i in section #%i",indexPath.row,indexPath.section] delegate:self cancelButtonTitle:@"OK" otherButtonTitles:nil];  	[alert show];  	[alert release];  }

And there is one "visual thing" you could add to maintain the nice aesthetics. Once cell (UITableViewCell) was pressed it stays selected - highlighted until you press any other cell or scroll theUITableView. Just add this line of code to above method to fix it:

	[tableView deselectRowAtIndexPath:indexPath animated:YES];

Accessory Buttons

accessorybuttonsAccessory Buttons are this nice tiny usually arrow-images on the right side of UITableViewCell with custom actions once tapped (only #2). There are 3 types of accessory buttons:

1. UITableViewCellAccessoryCheckmark
2. UITableViewCellAccessoryDetailDisclosureButton
3. UITableViewCellAccessoryDisclosureIndicator

- (UITableViewCellAccessoryType)tableView:(UITableView *)  tableView  accessoryTypeForRowWithIndexPath:(NSIndexPath *)indexPath {  	return UITableViewCellAccessoryCheckmark;    }

If you don't want to display any accessory button for some cells simply return UITableViewCellAccessoryNone for them. If you used DetailDisclosureButton (nice blue button with arrow) you can perform some tasks, once it was tapped:

- (void)tableView:(UITableView *)tableView accessoryButtonTappedForRowWithIndexPath:(NSIndexPath *)indexPath {  	UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Accessory Button pressed" message:[NSString stringWithFormat:@"Accessory Button for Cell #%i in section #%i",indexPath.row,indexPath.section] delegate:self cancelButtonTitle:@"OK" otherButtonTitles:nil];  	[alert show];  	[alert release];  }

Please note: above method works only with UITableViewCellAccessoryDetailDisclosureButton and it doesn't call any method connected with selecting a row.

Height and indent

sizeplain sizegrouped

If needed you can change the height of any cell or it's indend as shown screenshots above. By default height=45 and indent=0.

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {  	if (indexPath.row == 2) return 90;  	return 45;  }  - (NSInteger)tableView:(UITableView *)tableView indentationLevelForRowAtIndexPath:(NSIndexPath *)indexPath {  	if (indexPath.row == 3) return 2;  	return 0;  }

Custom Cell

customcellibAs you see there are many possibilities of customizing the cell, but it's not enough. You can create a new .xib file and aUITableViewCell controller and design the cell like any viewso far.

In Xcode add new class of type UITableViewCell and View XIB (name them CustomCell.*).

In CustomCell.h any any IBOutlets you need, labels, slider, switches... whatever.

Open CustomCell.xib and delete the View and add addUITableViewCell to CustomCell.xib. In Table View Cell Identity set class = CustomCell (not File's Owner this time). If you want you can adjust the size in Custom Cell Size...

customcellsize

or by dragging the bottom right triangle. Set it's features in Custom Cell Attributes, add some objects - treat it like a typical UIView.

Please note: this time, UITableViewCustomCell is a class of CustomCell, not File's Owner as usuall. So when you want to make connections go to Custom Cell Connections, forget about File's Owner this time.

OK, your custom cell is prepared right now, now it's time to show it in the UITableView. First you need to import CustomCell.h to your class that manages table (#import "CustomCell.h" and@class CustomCell).

Now you have to reorganize the table. Let's assume that your custom cell will be displayed only once in seperated section - in numberOfSectionsInTableView tell that there will be one more section and in numbersOfRowsInSection return 1 for a given section (add next case for existingswitch).

Hope above wasn't difficult because this will be: now it's time to extend cellForRowAtIndexPathmethod. I'm like many times before using switch and I assume that custom cell will be displayed in 4th section:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {  	// custom cell only  	if (indexPath.section == 3) {  		static NSString *CellIdentifier = @"CustomCell";  		CustomCell *cell = (CustomCell *) [tableView dequeueReusableCellWithIdentifier:CellIdentifier];  		if (cell == nil) {  			NSArray *outlets = [[NSBundle mainBundle] loadNibNamed:@"CustomCell" owner:self options:nil];  			for (id currentObject in outlets) {  				if ([currentObject isKindOfClass:[UITableViewCell class]]){  					cell =  (CustomCell *) currentObject;  					break;  				}  			}  		}  		cell.myLabel.text = @"Some text";  		return cell;  	}    	// other cells:  	// ...

So, when it comes to 4th section (indexPath.section == 3), the CustomCell nib (.xib) file is loaded, and in for loop, all it's objects are assigned as properties to cell. Although you set the size ofcustom cell in Interface Builder, but you must also tell UITableView to expect this by extendingheightForRowAtIndexPath method:

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {  	if (indexPath.row == 2) return 90;  	else if (indexPath.section == 3) return 95;  	return 45;  }

customcellsimulator

Please note:

you can read more about UITableView in documentation: check descriptions ofUITableViewDelegate and UITableViewDataSource protocols. You will find there more options and methods allowing you to modify the UITableView - delete, add, edit, reorder rows and more.

Conclusion:

That was pretty much for the one tutorial. Hope you understand everything. Don't worry, tables are something that young developers try to avoid, but they are not so difficult at all. I provided for you a sample project. Remember to change occasionally in Interface Builder the style of UITableView(plain / grouped). Some methods are disabled by comments, you can enable them by yourself.

xcodeproj

Download the project