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

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

  Массив рисунка 1 В качестве примера

Основные принципы массива

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

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

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

NSMutableArray *myMutableArray = [NSMutableArray arrayWithArray:myArray];

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

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

Непостоянные массивы

В NSMutableArray, основные методы, упомянутые ниже, обеспечивают основание для его возможности добавить, заменить, и удалить элементы:

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

Другие методы в NSMutableArray обеспечьте удобные способы вставить объект в слот в массиве и удалить основанное на объектах на его идентификационных данных или позиции в массиве, как проиллюстрировано в Перечислении 1.

Перечисление 1  , Добавляющее к и удаляющее из массивов

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 now contains redColor and whiteColor

Используя массивы

Можно получить доступ к объектам в массиве индексом с помощью objectAtIndex: метод. Например, если у Вас есть массив NSString объекты, можно получить доступ к третьей строке в массиве следующим образом:

NSString *someString = [arrayOfStrings objectAtIndex:2];

NSArray методы objectEnumerator и reverseObjectEnumerator предоставьте последовательный доступ к элементам массива, отличаясь только в направлении перемещения через элементы. Точно так же NSArray методы makeObjectsPerformSelector: и makeObjectsPerformSelector:withObject: позвольте Вам отправить сообщения во все объекты в массиве. В большинстве случаев быстрое перечисление должно использоваться, поскольку это быстрее и более гибко, чем использование NSEnumerator или makeObjectsPerformSelector: метод. Для больше на перечислении, посмотрите Перечисление: Пересечение Элементов Набора.

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

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

Перечисление 2  , Ищущее объект в массиве

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 показывает массив, сортированный фамилией тогда имя. Какао обеспечивает удобные способы сортировать содержание массива, такое как дескрипторы вида, блоки и селекторы.

  Массивы Сортировки рисунка 2

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

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

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

  Создание перечисления 3 и сортировка массива словарей

//First create the array of dictionaries
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];
 
//Next we sort the contents of the array by last name then first name
 
// The results are likely to be shown to a user
// Note the use of the localizedCaseInsensitiveCompare: selector
NSSortDescriptor *lastDescriptor =
    [[NSSortDescriptor alloc] initWithKey:last
                               ascending:YES
                               selector:@selector(localizedCaseInsensitiveCompare:)];
NSSortDescriptor *firstDescriptor =
    [[NSSortDescriptor alloc] initWithKey:first
                               ascending:YES
                               selector:@selector(localizedCaseInsensitiveCompare:)];
 
NSArray *descriptors = [NSArray arrayWithObjects:lastDescriptor, firstDescriptor, nil];
sortedArray = [array sortedArrayUsingDescriptors:descriptors];

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

  Сортировка перечисления 4 именем, фамилией

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

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

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

  Сортировка перечисления 5 с функцией менее гибка

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];

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

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

  Блоки перечисления 6 упрощают пользовательскую сортировку массивов

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;
}];

Сортировка с функциями и селекторами

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

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

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];
// note: anArray is sorted
NSData *sortedArrayHint = [anArray sortedArrayHint];
 
[anArray insertObject:@"be" atIndex:5];
 
NSArray *sortedArray;
 
// sort using a selector
sortedArray =
        [anArray sortedArrayUsingSelector:@selector(localizedCaseInsensitiveCompare:)];
 
// sort using a function
BOOL reverseSort = NO;
sortedArray =
        [anArray sortedArrayUsingFunction:alphabeticSort context:&reverseSort];
 
// sort with a hint
sortedArray =
        [anArray sortedArrayUsingFunction:alphabeticSort
                                  context:&reverseSort
                                     hint:sortedArrayHint];

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

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

Перечисление 8  , Фильтрующее массивы с предикатами

NSMutableArray *array =
    [NSMutableArray arrayWithObjects:@"Bill", @"Ben", @"Chris", @"Melissa", nil];
 
NSPredicate *bPredicate =
    [NSPredicate predicateWithFormat:@"SELF beginswith[c] 'b'"];
NSArray *beginWithB =
    [array filteredArrayUsingPredicate:bPredicate];
// beginWithB contains { @"Bill", @"Ben" }.
 
NSPredicate *sPredicate =
    [NSPredicate predicateWithFormat:@"SELF contains[c] 's'"];
[array filterUsingPredicate:sPredicate];
// array now contains { @"Chris", @"Melissa" }

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

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

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

  Монопольное использование объекта Массива указателей рисунка 3

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

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

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

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

  Массив указателей перечисления 9 сконфигурирован для необъектных указателей

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

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

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

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