Tag Archives: NSArray

How to test if an NSArray or NSSet contains an object

There’s a handy method in the NSArray class that lets us check if an array contains a particular object or not. The containsObject method returns a BOOL for us to evaluate.

Consider this:

// create an array
NSArray *array = @[@"Apples", @"Pears" , @"Bananas"];

// check if Pears are in the array
if ([array containsObject:@"Pears"]) {
    NSLog(@"We have Pears.");
}

Likewise, we can check if our array does not contain a particular object by testing the opposite:

// check if Grapes are not in the array
if (![array containsObject:@"Grapes"]) {
    NSLog(@"But we don't have Grapes.");
}

Both the NSMutableArray and NSSet classes has the same method, so we can check for the (un-)presence of our objects in mutable arrays and sets the same way.





How to use Arrays in Swift

Swift has its own built-in Array class. Although it’s bridged to NSArray, a Swift Array is something entirely different. Swift Arrays do not work with such trusted methods like addObject anymore.

Because I will probably have forgotten most of this by tomorrow, here’s a quick lowdown on how to play with Swift Arrays.

// create an empty array [type in square brackets]
var emptyArray = [String]()

// create an array with inferred values
var array = ["one", "two", "three"]

// loop through the array
for value in array {
    print("The value is \(value)")
}

// insert new value at a particular index
array.insert("two and a half", atIndex: 2)
var value = array[2]

// add something to the end of our array
array += ["new value"]
// or
array.append("another value")

// grab the last entry in our array
value = array.last!

// add another array
let anotherArray = ["four", "five", "six"]
array += anotherArray

// how many entries does our array have?
print(array.count)

// remove the last item in the array
array.removeLast()

// remove an item at a particular index
array.removeAtIndex(3)

Swift Arrays and Lazy Initialisation

Swift Arrays don’t like being initialised with a closure. God only knows why. We can however solve this puzzle with a simple function that returns our initialised values:

    lazy var data: [String] = self.initData()
    
    func initData() -> [String] {
        
        // initialize data array and return it
        var data = [String]()
        
        let formatter = NSNumberFormatter()
        formatter.numberStyle = .SpellOutStyle
        
        for var i = 0; i < 30; i++ {
            let number = NSNumber.init(integer: i)
            data.append(formatter.stringFromNumber(number)!)
        }
        return data
    }

For everything else about Swift Arrays, check out the Collection Types section of The Swift Programming Language:





What is the difference between NSSet, NSArray and NSDictionary

Bottle CollectionAll three are collection objects that can hold any number of other Objective C objects. I’m sure you’re familiar with the NSArray class, but the other two may sound a bit exotic. Let me explain them all here.

To do this I’m using NSString objects, but all three can pretty much hold any NSObject you encounter – you can even mix object types. For example, you can mix NSString and NSDate objects in the same collection.

NSArray

An NSArray can hold objects in a sorted order. So object1 is always object1, and object2 is always object2. You can retrieve the first and last object from the array.

Here’s how to create one:

// create an array with some values
NSArray *array = @[@"One", @"Two", @"Three", @"Four", @"Five", @"Six"];

// loop through the array
for (NSString *thisString in array) {
    NSLog(@"%@", thisString);
}

This will print all elements in order:

2014-04-07 19:58:14.541 SetTest[542:303] One
2014-04-07 19:58:14.543 SetTest[542:303] Two
2014-04-07 19:58:14.543 SetTest[542:303] Three
2014-04-07 19:58:14.544 SetTest[542:303] Four
2014-04-07 19:58:14.544 SetTest[542:303] Five
2014-04-07 19:58:14.544 SetTest[542:303] Six

NSSet

An NSSet is much like an NSArray, the only difference is that the objects it holds are not ordered. So when you retrieve them they may come back in any random order, based on how easy it is for the system to retrieve them.

You would typically use a set when access speed is of the essence and order doesn’t matter, or is determined by other means (through a predicate or sort descriptor). Core Data for example uses sets when managed objects are accessed via a to-many relationship.

You can turn NSSets into NSArrays and back, and you can fast-enumerate an NSSet too:

// create an array with some values
NSArray *array = @[@"One", @"Two", @"Three", @"Four", @"Five", @"Six"];

// turn them into a set
NSSet *mySet = [[NSSet alloc]initWithArray:array];

// loop through the set
for (NSString *thisString in mySet) {
    NSLog(@"%@", thisString);
}

// turn the set back into an array
NSArray *newArray = [mySet allObjects];

This may print something like this:

2014-04-07 19:42:59.123 SetTest[477:303] Five
2014-04-07 19:42:59.123 SetTest[477:303] Six
2014-04-07 19:42:59.124 SetTest[477:303] One
2014-04-07 19:42:59.124 SetTest[477:303] Three
2014-04-07 19:42:59.124 SetTest[477:303] Four
2014-04-07 19:42:59.125 SetTest[477:303] Two

NSDictionary

The NSDictionary class is a bit of a magical one: it stores objects as key value pairs. Objects are not ordered, but can be retrieved simply by addressing them with an arbitrary string value.

Here we create one with three keys and values, then loop through it:

// create an array with some values
NSDictionary *dictionary = @{@"name": @"Chuck Norris",
                             @"title": @"Movie Star",
                             @"tvShow": @"Walker, Texas Ranger"
                             };

// loop through the set
for (NSString *key in dictionary) {
    
    NSString *value = [dictionary valueForKey:key];
    NSLog(@"%@: %@", key, value);
}

This will print:

2014-04-07 20:12:52.100 SetTest[580:303] name: Chuck Norris
2014-04-07 20:12:52.102 SetTest[580:303] title: Movie Star
2014-04-07 20:12:52.103 SetTest[580:303] tvShow: Walker, Texas Ranger





How to test the size of an NSDictionary (in bytes)

The NSDictionary class doesn’t have a length property that can tell us how much memory is being used for storing the whole lot. Usually we don’t really care how big our variables grow – but if you’re storing that dictionary somewhere with potentially limited space (such as iCloud Key/Value storage), it may well be of interest.

You can however turn the dictionary into data and test its size like this:

NSMutableDictionary *dictionary = [[NSMutableDictionary alloc]init];
for (int i = 0; i <= 1000; i++) {
        
    NSString *key = [[NSString alloc]initWithFormat:@"Key%i", i];
    [dictionary setObject:@47 forKey:key];
}
NSData * data = [NSPropertyListSerialization dataFromPropertyList:dictionary format:NSPropertyListBinaryFormat_v1_0 errorDescription:NULL];

NSLog(@"Size in bytes: %lu - Entries: %lu", (unsigned long)[data length], (unsigned long)dictionary.count);

Here we setup a loop that generates a dictionary and adds 1001 entries with an NSNumber literal of 47. This will give us the following information:

Size in bytes: 12954 – Entries: 1001

Note that the above only works if your dictionary has “serialisable” data such as NSNumber, NSDate, NSArray, NSDictionary, NSString or NSData (anything that can be written to a .plist file basically) – but it will not work with custom objects.





How to loop through every element in an NSArray

We can use something called Fast Enumeration for this, using a modified for loop:

// build an array
NSArray *myArray = [[NSArray alloc]initWithObjects:@"One", @"Two", @"Three", @"Four", nil];

// loop through every element (dynamic typing)
for (id tempObject in myArray) {
    NSLog(@"Single element: %@", tempObject);
}

You don’t have to use dynamic typing if you know the types of objects you’re using. In our example this would work just as well:

// build an array
NSArray *myArray = [[NSArray alloc]initWithObjects:@"One", @"Two", @"Three", @"Four", nil];

// loop through every element (static typing)
for (NSString *tempObject in myArray) {
    NSLog(@"Single element: %@", tempObject);
}

Fast Enumeration also works with NSDictionaries of course:

// build a dictionary
NSDictionary *myDictionary = [[NSDictionary alloc]initWithObjectsAndKeys:@"One", @"1", @"Two",@"2", @"Three", @"3",nil];

// loop through it (dynamic typing)
for (id tempObject in myDictionary) {
    NSLog(@"Object: %@, Key: %@", [myDictionary objectForKey:tempObject], tempObject);
}




How to convert an NSArray into an NSMutableArray

There’s a handy function called arrayWithArray that we can use:

NSMutableArray *myNewArray = [[NSMutableArray alloc]init];
myNewArray = [NSMutableArray arrayWithArray:myOldArray];

Likewise we can convert a mutable array into a standard one:

NSArray *myStandardArray = [[NSArray alloc]init];
myStandardArray = [NSArray arrayWithArray:myMutableArray];