Reputation: 1035
I know we could just use a NSMutableArray
for the object, but what if that's not an option and we need to add new elements to an NSArray
. How would we go about doing this?
My immediate answer would be to create a NSMutableArray
with the original NSArray
, add the new elements to it, then cast the NSMutableArray
back to the original NSArray
.
I was asked this in an interview and am curious what a correct solution might be, besides just use a NSMutableArray
in the first place.
Upvotes: 4
Views: 12332
Reputation: 1034
I was wondering what the performance difference would be between using arrayByAddingObject
and creating a mutable copy and then adding one element.
I found that it doesn't matter.
Here's what I used
- (IBAction)doTest
{
for(int n = 0; n < 7; n++){
[self runTestWithExponent:n];
}
NSLog(@"done");
}
- (void)runTestWithExponent:(double)exponent
{
int arraySize = pow(10.0, exponent);
NSMutableArray *originalMutableArray = [NSMutableArray arrayWithCapacity:arraySize];
for(int i = 0; i < arraySize; i++){
[originalMutableArray addObject:@(i)];
}
NSArray *originalArray = [NSArray arrayWithArray:originalMutableArray];
originalMutableArray = nil;
//test first time
NSDate *now = [NSDate date];
NSArray *newArray = [originalArray arrayByAddingObject:@(-1)];
NSTimeInterval time1 = [[NSDate date] timeIntervalSinceDate:now];
newArray = nil;
//test second time
now = [NSDate date];
NSMutableArray *mutable = [originalArray mutableCopy];
[mutable addObject:@(-1)];
NSTimeInterval time2 = [[NSDate date] timeIntervalSinceDate:now];
mutable = nil;
NSString *winner = (time1 == time2) ? @"same" : ((time1 < time2) ? @"arrayByAdding" : @"mutable");
NSLog(@"%i : %f --- %f : %@ %f%%", arraySize, time1, time2, winner, (time1/time2 * 100));
}
As you can see, I test different array sizes. Sizes of 1, 10, 100 ... 1,000,000. I found regardless of size, the times are very similar to each other. For any given length, sometimes one method is faster, and others, the other. I'm guessing internally they do the same thing.
Here's the output of three runs:
1 : 0.000026 --- 0.000034 : arrayByAdding 76.491228%
10 : 0.000011 --- 0.000011 : same 100.000000%
100 : 0.000021 --- 0.000024 : arrayByAdding 87.344913%
1000 : 0.000228 --- 0.000260 : arrayByAdding 87.689133%
10000 : 0.001458 --- 0.001406 : mutable 103.696638%
100000 : 0.015396 --- 0.015625 : arrayByAdding 98.534393%
1000000 : 0.158018 --- 0.162849 : arrayByAdding 97.033438%
done
1 : 0.000011 --- 0.000012 : arrayByAdding 92.039801%
10 : 0.000012 --- 0.000014 : arrayByAdding 85.531915%
100 : 0.000020 --- 0.000025 : arrayByAdding 79.952267%
1000 : 0.000185 --- 0.000144 : mutable 128.435430%
10000 : 0.001397 --- 0.001437 : arrayByAdding 97.216807%
100000 : 0.014448 --- 0.014132 : mutable 102.235803%
1000000 : 0.145622 --- 0.149862 : arrayByAdding 97.170746%
done
1 : 0.000013 --- 0.000012 : mutable 107.920792%
10 : 0.000011 --- 0.000013 : arrayByAdding 84.862385%
100 : 0.000025 --- 0.000029 : arrayByAdding 86.036961%
1000 : 0.000165 --- 0.000135 : mutable 122.207506%
10000 : 0.001547 --- 0.001470 : mutable 105.242884%
100000 : 0.014817 --- 0.014337 : mutable 103.347954%
1000000 : 0.146554 --- 0.148468 : arrayByAdding 98.710857%
done
Keep in mind that this was only tested for adding one element. I suspect that (for example) adding 500 elements to the 1,000 sized array will probably be faster using the second method, but I leave such experiments to someone else.
Upvotes: 1
Reputation: 9414
This is simply a trick question. NSArrays
are immutable and cannot be altered without creating a new NSArray
or NSMutableArray
from the previous array, plain and simple.
Upvotes: 0
Reputation: 122391
NSArray
objects are immutable so they cannot be modified. The only option is to create a new NSArray
(via an intermediate NSMutableArray
object perhaps) and put this new array back into the owning object (if it allows it).
Upvotes: 3
Reputation: 77641
NSArray *array = [NSArray arrayWithObjects:@"One", @"Two", nil];
array = [array arrayByAddingObject:@"Three"];
or
NSArray *newArray = [NSArray arrayWithObjects:@"Three", @"Four", nil];
array = [array arrayByAddingObjectsFromArray:newArray];
Upvotes: 11
Reputation: 5520
You can use mutableCopy
on your NSArray
object to return an NSMutableArray
containing the previous objects.
Upvotes: 3