NSArray
Syntax#
- NSArray *words; // Declaring immutable array
- NSMutableArray *words; // Declaring mutable array
- NSArray *words = [NSArray arrayWithObjects: @“one”, @“two”, nil]; // Array initialization syntax
- NSArray *words = @[@“list”, @“of”, @“words”, @123, @3.14]; // Declaring array literals
- NSArray *stringArray = [NSArray arrayWithObjects: [NSMutableArray array], [NSMutableArray array], [NSMutableArray array], nil]; // Creating multidimentional arrays
Creating Arrays
Creating immutable arrays:
NSArray *myColors = [NSArray arrayWithObjects: @"Red", @"Green", @"Blue", @"Yellow", nil];
// Using the array literal syntax:
NSArray *myColors = @[@"Red", @"Green", @"Blue", @"Yellow"];
For mutable arrays, see NSMutableArray.
Finding out the Number of Elements in an Array
NSArray *myColors = [NSArray arrayWithObjects: @"Red", @"Green", @"Blue", @"Yellow", nil];
NSLog (@"Number of elements in array = %lu", [myColors count]);
Accessing elements
NSArray *myColors = @[@"Red", @"Green", @"Blue", @"Yellow"];
// Preceding is the preferred equivalent to [NSArray arrayWithObjects:...]
Getting a single item
The objectAtIndex:
method provides a single object. The first object in an NSArray
is index 0. Since an NSArray
can be homogenous (holding different types of objects), the return type is id
(“any object”). (An id
can be assigned to a variable of any other object type.) Importantly, NSArray
s can only contain objects. They cannot contain values like int
.
NSUInteger idx = 2;
NSString *color = [myColors objectAtIndex:idx];
// color now points to the string @"Green"
Clang provides a better subscript syntax as part of its array literals functionality:
NSString *color = myColors[idx];
Both of these throw an exception if the passed index is less than 0 or greater than count - 1
.
First and Last Item
NSString *firstColor = myColors.firstObject;
NSString *lastColor = myColors.lastObject;
The firstObject
and lastObject
are computed properties and return nil
rather than crashing for empty arrays. For single element arrays they return the same object. Although, the firstObject
method was not introduced to NSArray
until iOS 4.0.
NSArray *empty = @[]
id notAnObject = empty.firstObject; // Returns `nil`
id kaboom = empty[0]; // Crashes; index out of bounds
Filtering Arrays With Predicates
NSArray *array = [NSArray arrayWithObjects:@"Nick", @"Ben", @"Adam", @"Melissa", nil];
NSPredicate *aPredicate = [NSPredicate predicateWithFormat:@"SELF beginswith[c] 'a'"];
NSArray *beginWithA = [array filteredArrayUsingPredicate:bPredicate];
// beginWithA contains { @"Adam" }.
NSPredicate *ePredicate = [NSPredicate predicateWithFormat:@"SELF contains[c] 'e'"];
[array filterUsingPredicate:ePredicate];
// array now contains { @"Ben", @"Melissa" }
More about
Apple doc : NSPredicate
Converting NSArray to NSMutableArray to allow modification
NSArray *myColors = [NSArray arrayWithObjects: @"Red", @"Green", @"Blue", @"Yellow", nil];
// Convert myColors to mutable
NSMutableArray *myColorsMutable = [myColors mutableCopy];
Sorting array with custom objects
Compare method
Either you implement a compare-method for your object:
- (NSComparisonResult)compare:(Person *)otherObject {
return [self.birthDate compare:otherObject.birthDate];
}
NSArray *sortedArray = [drinkDetails sortedArrayUsingSelector:@selector(compare:)];
NSSortDescriptor
NSSortDescriptor *sortDescriptor;
sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"birthDate"
ascending:YES];
NSArray *sortDescriptors = [NSArray arrayWithObject:sortDescriptor];
NSArray *sortedArray = [drinkDetails sortedArrayUsingDescriptors:sortDescriptors];
You can easily sort by multiple keys by adding more than one to the array. Using custom comparator-methods is possible as well. Have a look at the documentation.
Blocks
NSArray *sortedArray;
sortedArray = [drinkDetails sortedArrayUsingComparator:^NSComparisonResult(id a, id b) {
NSDate *first = [(Person*)a birthDate];
NSDate *second = [(Person*)b birthDate];
return [first compare:second];
}];
Performance
The -compare:
and block-based methods will be quite a bit faster, in general, than using NSSortDescriptor
as the latter relies on KVC. The primary advantage of the NSSortDescriptor
method is that it provides a way to define your sort order using data, rather than code, which makes it easy to e.g. set things up so users can sort an NSTableView
by clicking on the header row.
Converting between Sets and Arrays
NSSet *set = [NSSet set];
NSArray *array = [NSArray array];
NSArray *fromSet = [set allObjects];
NSSet *fromArray = [NSSet setWithArray:array];
Reverse an Array
NSArray *reversedArray = [myArray.reverseObjectEnumerator allObjects];
Looping through
NSArray *myColors = @[@"Red", @"Green", @"Blue", @"Yellow"];
// Fast enumeration
// myColors cannot be modified inside the loop
for (NSString *color in myColors) {
NSLog(@"Element %@", color);
}
// Using indices
for (NSUInteger i = 0; i < myColors.count; i++) {
NSLog(@"Element %d = %@", i, myColors[i]);
}
// Using block enumeration
[myColors enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL * stop) {
NSLog(@"Element %d = %@", idx, obj);
// To abort use:
*stop = YES
}];
// Using block enumeration with options
[myColors enumerateObjectsWithOptions:NSEnumerationReverse usingBlock:^(id obj, NSUInteger idx, BOOL * stop) {
NSLog(@"Element %d = %@", idx, obj);
}];
Using Generics
For added safety we can define the type of object that the array contains:
NSArray<NSString *> *colors = @[@"Red", @"Green", @"Blue", @"Yellow"];
NSMutableArray<NSString *> *myColors = [NSMutableArray arrayWithArray:colors];
[myColors addObject:@"Orange"]; // OK
[myColors addObject:[UIColor purpleColor]]; // "Incompatible pointer type" warning
It should be noted that this is checked during compilation time only.
Enumerating using blocks
NSArray *myColors = @[@"Red", @"Green", @"Blue", @"Yellow"];
[myColors enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
NSLog(@"enumerating object %@ at index %lu", obj, idx);
}];
By setting the stop
parameter to YES
you can indicate that further enumeration is not needed. to do this simply set &stop = YES
.
NSEnumerationOptions
You can enumerate the array in reverse and / or concurrently :
[myColors enumerateObjectsWithOptions:NSEnumerationConcurrent | NSEnumerationReverse
usingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
NSLog(@"enumerating object %@ at index %lu", obj, idx);
}];
Enumerating subset of array
NSIndexSet *indexSet = [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(1, 1)];
[myColors enumerateObjectsAtIndexes:indexSet
options:kNilOptions
usingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
NSLog(@"enumerating object %@ at index %lu", obj, idx);
}];
Comparing arrays
Arrays can be compared for equality with the aptly named isEqualToArray: method, which returns YES when both arrays have the same number of elements and every pair pass an isEqual: comparison.
NSArray *germanMakes = @[@"Mercedes-Benz", @"BMW", @"Porsche",
@"Opel", @"Volkswagen", @"Audi"];
NSArray *sameGermanMakes = [NSArray arrayWithObjects:@"Mercedes-Benz",
@"BMW", @"Porsche", @"Opel",
@"Volkswagen", @"Audi", nil];
if ([germanMakes isEqualToArray:sameGermanMakes]) {
NSLog(@"Oh good, literal arrays are the same as NSArrays");
}
The important thing is every pair must pass the isEqual: test. For custom objects this method should be implemented.It exists in the NSObject protocol.
Add objects to NSArray
NSArray *a = @[@1];
a = [a arrayByAddingObject:@2];
a = [a arrayByAddingObjectsFromArray:@[@3, @4, @5]];
These methods are optimized to recreate the new array very efficiently, usually without having to destroy the original array or even allocate more memory.