Differences between [NSArray arrayWithArray:] and [NSArray copy] - objective-c

lately I work much with arrays and I'm wonder.. what's diffrences between those two lines.
NSArray *array = [NSArray arrayWithArray:someArray];
and
NSArray *array = [someArray copy];
Which of it is faster? What in case we have NSMutableArray and mutableCopy?

Which of it is faster?
Don't worry about it. Premature optimization.
The main difference: the first approach results in an autoreleased "copy" that you don't own and don't have to release, while you do own the object created on the second line.
Both arrays will be immutable, by the way.

In addition to the other answers, also note, that when someArray is nil,
the first line will make array point to an empty array and the second will make
it point to nil. This might be an important difference, especially in mutable arrays.

The difference between the two is that the latter will be retained. The former will be autoreleased.
Both versions make a shallow copy of the array.
NSMutableArray *notMutableReally = [NSArray arrayWithArray:aMutableArray];
Should give you a compiler warning as you will be trying to assign a NSArray to a NSMutableArray.
Use.
NSMutableArray *mutableArrayCopy = [NSMutableArray arrayWithArray:aMutableArray];
Which is faster? Dont worry, they are all far faster than the rest of the stuff you will be doing. Check with Instruments if you really care.

The main difference is that -copy knows better how to copy itself (can do it more efficiently and maybe use a more adapted subclass of NSArray) while +arrayWithArray: will create a new instance of NSArray (well, in fact the concrete class used by Foundation for arrays) and feed it with the same list of objects from the initial object. Also it will add an extra autorelease.
So -copy is (very very) likely more efficient.
In fact for immutable NSArrays, -copy is just doing -retain, so it does not even bother creating a new instance.

NSMutableArray *arr = [NSMutableArray array];
for ( int i = 0; i < 10000; i ++)
{
[arr addObject:#(i*1000000ULL)];
}
// MARK
// arr = (id)[NSArray arrayWithArray:arr];
NSTimeInterval t = [NSDate timeIntervalSinceReferenceDate];
NSArray *res = nil;
for ( int i = 0; i < 10000; i ++)
{
res = [arr copy];
}
NSLog(#"time A: %f", [NSDate timeIntervalSinceReferenceDate] - t);
t = [NSDate timeIntervalSinceReferenceDate];
for ( int i = 0; i < 10000; i ++)
{
res = [NSArray arrayWithArray:arr];
}
NSLog(#"time B: %f", [NSDate timeIntervalSinceReferenceDate] - t);
time A: 1.572795, time B: 1.539150, B [NSArray arrayWithArray:] always faster but time difference very small. But if we uncomment "MARK" and get copy from NSArray instead NSMutableArray we will have other runtime A: 0.000473 time B: 1.548400 result: ~3200x times faster

One of them is probably faster. Run them a million times and see if anyone wins.
In case of NSArray vs NSMutableArray, an immutable array being copied does not have to actually return a copy since it can't change. However, if you have a mutable array, it would need to be copied since you could change the original. And of course doing a mutable copy always needs to return a new object.
In your entire app, the speed and memory difference is probably not going to matter compared to everything else that's going on.

In Swift, it's very different. Thanks to the new open-source Foundation for Swift, we know that whereas init(array:) creates a new array with the items given (if any), copy() simply returns self.
public override func copy() -> AnyObject {
return copyWithZone(nil)
}
public func copyWithZone(zone: NSZone) -> AnyObject {
return self
}
https://github.com/apple/swift-corelibs-foundation/blob/master/Foundation/NSArray.swift#L82
public convenience init(array: [AnyObject]) {
self.init(array: array, copyItems: false)
}
public convenience init(array: [AnyObject], copyItems: Bool) {
let optionalArray : [AnyObject?] =
copyItems ?
array.map { return Optional<AnyObject>(($0 as! NSObject).copy()) } :
array.map { return Optional<AnyObject>($0) }
// This would have been nice, but "initializer delegation cannot be nested in another expression"
// optionalArray.withUnsafeBufferPointer { ptr in
// self.init(objects: ptr.baseAddress, count: array.count)
// }
let cnt = array.count
let buffer = UnsafeMutablePointer<AnyObject?>.alloc(cnt)
buffer.initializeFrom(optionalArray)
self.init(objects: buffer, count: cnt)
buffer.destroy(cnt)
buffer.dealloc(cnt)
}
https://github.com/apple/swift-corelibs-foundation/blob/master/Foundation/NSArray.swift#L116
So, obviously, copy() is faster, and now you know how they both work! (Just only in Swift)

Related

How to efficiently access large objects in Obj-C using objectForKey and objectAtIndex?

If I have a large NSDirectory typically from a parsed JSON-object I can access this object with code like so:
[[[[[obj objectForKey:#"root"] objectForKey:#"key1"] objectAtIndex:idx] objectForKey:#"key2"] objectAtIndex:idz];
The line might be a lot longer than this.
Can I optimize this code in any way? At least make it easier to read?
This line will also generate a runtime-error if the object does not correspond, what is the most efficient way to avoid that?
If you were using -objectForKey: for everything you could use -valueForKeyPath:, as in
[obj valueForKeyPath:#"key1.key2.key3.key4"]
However, this doesn't work when you need to use -objectAtIndex:. I don't think there's any good solution for you. -valueForKeyPath: also wouldn't solve the problem of the runtime errors.
If you truly want a simple way to do this you could write your own version of -valueForKeyPath: (call it something else) that provides a syntax for specifying an -objectAtIndex: instead of a key, and that does the appropriate dynamic checks to ensure the object actually responds to the method in question.
If you want easier to read code you can split the line into several lines like this
MyClass *rootObject = [obj objectForKey:#"root"];
MyClass *key1Object = [rootObject objectForKey:#"key1"];
MyClass *myObject = [key1Object objectAtIndex:idx];
...
and so forth.
I think, you can create some array, that will contain full "path" to your object. The only thing, you need to store your indexes somehow, maybe in NSNumber, in this case you cannot use NSNumber objects as keys in your dictionaries. Then create a method, that will return needed object for this given "path". smth like
NSMutableArray* basePath = [NSMutableArray arrayWithObjects: #"first", [NSNumber numberWithInt:index], nil];
id object = [self objectForPath:basePath inContainer:container];
- (id) objectForPath:(NSMutableArray*)basePath inContainer:(id)container
{
id result = nil;
id pathComponent = [basePath objectAtIndex: 0];
[basePath removeObjectAtIndex: 0];
// check if it is a number with int index
if( [pathComponent isKindOfClass:[NSNumber class]] )
{
result = [container objectAtIndex: [pathComponent intValue]];
}
else
{
result = [container objectForKey: pathComponent];
}
assert( result != nil );
// check if it is need to continue searching object
if( [basePath count] > 0 )
{
return [self objectForPath:basePath inContainer: result];
}
else
{
return result;
}
}
this is just an idea, but I hope you understand what I mean. And as Kevin mentioned above, if you don't have indexes, you can use key-value coding.
Don't know if it can suit you, but you could also give a try to blocks, I always find them very convenient. At least they made code much more readable.
NSArray *filter = [NSArray arrayWithObjects:#"pathToFind", #"pathToFind2",nil];
NSPredicate *filterBlock = [NSPredicate predicateWithBlock: ^BOOL(id obj, NSDictionary *bind){
NSArray *root = (NSArray*)obj;
// cycle the array and found what you need.
// eventually implementing some sort of exit strategy
}];
[rootObject filteredArrayUsingPredicate:filterBlock];

How to perform binary search on NSArray?

What is the simplest way to do a binary search on an (already) sorted NSArray?
Some potential ways I have spotted so far include:
The use of CFArrayBSearchValues (mentioned here) - would this work on an NSArray?
The method indexOfObject:inSortedRange:options:usingComparator: of NSArray assumes the array is sorted and takes an opts param of type NSBinarySearchingOptions - does this mean it performs a binary search? The docs just say:
Returns the index, within a specified range, of an object compared with elements in the array using a given NSComparator block.
Write my own binary search method (something along the lines of this).
I should add that I am programming for iOS 4.3+
Thanks in advance.
The second option is definitely the simplest. Ole Begemann has a blog entry on how to use the NSArray's indexOfObject:inSortedRange:options:usingComparator: method:
NSArray *sortedArray = ... // must be sorted
id searchObject = ...
NSRange searchRange = NSMakeRange(0, [sortedArray count]);
NSUInteger findIndex = [sortedArray indexOfObject:searchObject
inSortedRange:searchRange
options:NSBinarySearchingFirstEqual
usingComparator:^(id obj1, id obj2)
{
return [obj1 compare:obj2];
}];
See NSArray Binary Search
1 and 2 will both work. #2 is probably easier; it certainly doesn't make sense for that method to do anything other than a binary search (if the range is above a certain size, say). You could verify on a large array that it only does a small number of comparisons.
I'm surprised that nobody mentioned the use of NSSet, which [when it contains objects with a decent hash, such as most Foundation data types] performs constant time lookups. Instead of adding your objects to an array, add then to a set instead (or add them to both if you need to retain a sorted order for other purposes [or alternatively on iOS 5.0 or Mac OS X 10.7 there is NSOrderedSet]).
To determine whether an object exists in a set:
NSSet *mySet = [NSSet setWithArray:myArray]; // try to do this step only once
if ([mySet containsObject:someObject])
{
// do something
}
Alternatively:
NSSet *mySet = [NSSet setWithArray:myArray]; // try and do this step only once
id obj = [mySet member:someObject];
// obj is now set to nil if the object doesn't exist or it is
// set to an object that "isEqual:" to someObject (which could be
// someObject itself).
It is important to know that you will lose any performance benefit if you convert the array to a set each time you do a lookup, ideally you will be using a preconstructed set containing the objects you want to test.
//Method to pass array and number we are searching for.
- (void)binarySearch:(NSArray *)array numberToEnter:(NSNumber *)key{
NSUInteger minIndex = 0;
NSUInteger maxIndex = array.count-1;
NSUInteger midIndex = array.count/2;
NSNumber *minIndexValue = array[minIndex];
NSNumber *midIndexValue = array[midIndex];
NSNumber *maxIndexValue = array[maxIndex];
//Check to make sure array is within bounds
if (key > maxIndexValue || key < minIndexValue) {
NSLog(#"Key is not within Range");
return;
}
NSLog(#"Mid indexValue is %#", midIndexValue);
//If key is less than the middleIndexValue then sliceUpArray and recursively call method again
if (key < midIndexValue){
NSArray *slicedArray = [array subarrayWithRange:NSMakeRange(minIndex, array.count/2)];
NSLog(#"Sliced array is %#", slicedArray);
[self binarySearch:slicedArray numberToEnter:key];
//If key is greater than the middleIndexValue then sliceUpArray and recursively call method again
} else if (key > midIndexValue) {
NSArray *slicedArray = [array subarrayWithRange:NSMakeRange(midIndex+1, array.count/2)];
NSLog(#"Sliced array is %#", slicedArray);
[self binarySearch:slicedArray numberToEnter:key];
} else {
//Else number was found
NSLog(#"Number found");
}
}
//Call Method
#interface ViewController ()
#property(nonatomic)NSArray *searchArray;
#end
- (void)viewDidLoad {
[super viewDidLoad];
//Initialize the array with 10 values
self.searchArray = #[#1,#2,#3,#4,#5,#6,#7,#8,#9,#10];
//Call Method and search for any number
[self binarySearch:self.searchArray numberToEnter:#5];
// Do any additional setup after loading the view, typically from a nib.
}
CFArrayBSearchValues should work—NSArray * is toll-free bridged with CFArrayRef.

NSMutableArray insert object at index

I have an empty mutable array. Is it possible to insert object at index 2 for example, while there's nothing at index 0 and 1? I mean to increase capacity dynamically or something like that. .Regards.
NSMutableArray is not a sparse array; it does not allow empty slots that can be filled in later. initWithCapacity: just hints to the array that it will be filled to a certain amount; it isn't generally necessary in practice and, unless you know exactly how many items you are going to shove in the array, don't bother calling it (just use init).
A mutable array will quite efficiently grow in size as objects are added.
If you need a data structure that supports "holes", then either use something else or put a placeholder object in the slots that are supposed to be empty.
I.e. if you wanted an array with 10 slots, you might do:
NSMutableArray *a = [NSMutableArray array];
for(int i = 0; i<10; i++) [a addObject: [NSNull null]];
You can then check if the retrieved object isEqual: [NSNull null] to know if the slot is empty or not. And you can use replaceObjectAtIndex:withObject: to stick an object at a specific index.
Or you could use a different data structure; a dictionary with the indices as the keys would work, for example.
You can use a NSPointerArray for that.
NSPointerArray is a mutable collection
modeled after NSArray but it can also
hold NULL values, which can be
inserted or extracted (and which
contribute to the object’s count).
Moreover, unlike traditional arrays,
you can set the count of the array
directly.
NSPointerArray is available in OS X v10.5 and later and iOS 6.0 and later. If you target a lower OS version you can, for example:
Use a NSMutableDictionary, wrap you indices into NSNumbers and use these as keys.
Use a NSMutableArray and fill the "holes" with NSNull objects.
Write yourself a SparseArray class using an underlying NSMutableDictionary. Something like this (minimal code, barely tested, but it should give you the idea).
#interface SparseArray : NSObject {
#private
NSMutableDictionary* _dict;
int count;
}
-(SparseArray*)initWithCapacity:(NSUInteger)anInt;
-(id)objectAtIndex:(int)anIndex;
-(void)insertObject:(id)anObject atIndex:(int)anIndex;
- (void)removeObjectAtIndex:(int)anIndex;
-(int)count;
#implementation SparseArray
-(SparseArray*)initWithCapacity:(NSUInteger)anInt {
if ((self = [super init])) {
_dict = [[NSMutableDictionary dictionaryWithCapacity:anInt] retain];
count = 0;
}
return self;
}
-(id)objectAtIndex:(int)anIndex {
NSNumber* key = [NSNumber numberWithInt:anIndex];
id object = [_dict objectForKey:key];
return object;
}
-(void)insertObject:(id)anObject atIndex:(int)anIndex {
NSNumber* key = [NSNumber numberWithInt:anIndex];
[_dict setObject:anObject forKey:key];
count++;
}
- (void)removeObjectAtIndex:(int)anIndex {
NSNumber* key = [NSNumber numberWithInt:anIndex];
id object = [_dict objectForKey:key];
if (object) {
[_dict removeObjectForKey:key];
count--;
}
}
-(int)count {
return count;
}
-(void)dealloc {
[_dict release];
[super dealloc];
}
#end

How to manage int when it's incremented inside another loop?

I have a simple loop with an int counter that gets incremented inside a while loop when a special case exists. My question is simply - how should I manage memory inside this function with regards to the int specifically? I've been using NSNumber almost exclusively and what little time I've spent with int seems to make me think I'm not doing releasing it correctly.
Any other improvements are also welcome but I'm very interested in the int question
- (NSArray *)parseJson:(NSArray *) items
{
NSMutableArray* hats = [[NSMutableArray alloc] init];
NSEnumerator *enumerator = [items objectEnumerator];
NSDictionary* item;
int counterz = 0;
while (item = (NSDictionary*)[enumerator nextObject]) {
Hat* hat = [[Hat alloc] init];
hat.addr = [item objectForKey:#"Address"];
BOOL* hasHat = [item objectForKey:#"HasHat"];
if ([hasHat boolValue]) {
if (counterz < 10) {
[hats addObject:hat];
counterz++;
}
}
}
return hats;
}
Thank you in advance!
You don't need to release a "normal" (i.e.: non-object based) int - it'll happily life out its (brief, tragic) life on the stack until it falls out of scope.
You've got a couple unnecessary things and some memory leaks...
- (NSArray *)parseJson:(NSArray *) items {
NSMutableArray *hats = [NSMutableArray array];
int counter = 0;
for (NSDictionary *item in items) {
Hat *hat = [[Hat alloc] init];
[hat setAddr:[item objectForKey:#"Address"]];
BOOL hasHat = [[item objectForKey:#"HasHat"] boolValue];
if (hasHat && counter < 10) {
[hats addObject:hat];
counter++;
}
[hat release];
}
return hats;
}
And heck, once you reach a counter of 10, you could break out of the loop, because you're never going to do anything useful once 10 is reached.
Some other comments:
The name of the method is wrong. Nothing about this method has to do with parsing JSON. At best you're interpreting an array of dictionaries that happened to originate from a JSON string, but there's nothing about the nature of this code that says "this is parsing JSON".
-[NSDictionary objectForKey:] returns an object. A BOOL is not an object, it's a primitive (like an int or char). Appending * to the type does not make it an object either. :)
Since the method name does not begin with new or alloc and does not contain the word copy, you're supposed to return an autoreleased object from it. The method in the question was returning an owned object (+1 retain count), since you invoked alloc, but never autorelease. Using the convenience constructor +array fixes this.
In your loop, you allocated a Hat object, but never released it. This is a classic memory leak.

Best way to remove from NSMutableArray while iterating?

In Cocoa, if I want to loop through an NSMutableArray and remove multiple objects that fit a certain criteria, what's the best way to do this without restarting the loop each time I remove an object?
Thanks,
Edit: Just to clarify - I was looking for the best way, e.g. something more elegant than manually updating the index I'm at. For example in C++ I can do;
iterator it = someList.begin();
while (it != someList.end())
{
if (shouldRemove(it))
it = someList.erase(it);
}
For clarity I like to make an initial loop where I collect the items to delete. Then I delete them. Here's a sample using Objective-C 2.0 syntax:
NSMutableArray *discardedItems = [NSMutableArray array];
for (SomeObjectClass *item in originalArrayOfItems) {
if ([item shouldBeDiscarded])
[discardedItems addObject:item];
}
[originalArrayOfItems removeObjectsInArray:discardedItems];
Then there is no question about whether indices are being updated correctly, or other little bookkeeping details.
Edited to add:
It's been noted in other answers that the inverse formulation should be faster. i.e. If you iterate through the array and compose a new array of objects to keep, instead of objects to discard. That may be true (although what about the memory and processing cost of allocating a new array, and discarding the old one?) but even if it's faster it may not be as big a deal as it would be for a naive implementation, because NSArrays do not behave like "normal" arrays. They talk the talk but they walk a different walk. See a good analysis here:
The inverse formulation may be faster, but I've never needed to care whether it is, because the above formulation has always been fast enough for my needs.
For me the take-home message is to use whatever formulation is clearest to you. Optimize only if necessary. I personally find the above formulation clearest, which is why I use it. But if the inverse formulation is clearer to you, go for it.
One more variation. So you get readability and good performace:
NSMutableIndexSet *discardedItems = [NSMutableIndexSet indexSet];
SomeObjectClass *item;
NSUInteger index = 0;
for (item in originalArrayOfItems) {
if ([item shouldBeDiscarded])
[discardedItems addIndex:index];
index++;
}
[originalArrayOfItems removeObjectsAtIndexes:discardedItems];
This is a very simple problem. You just iterate backwards:
for (NSInteger i = array.count - 1; i >= 0; i--) {
ElementType* element = array[i];
if ([element shouldBeRemoved]) {
[array removeObjectAtIndex:i];
}
}
This is a very common pattern.
Some of the other answers would have poor performance on very large arrays, because methods like removeObject: and removeObjectsInArray: involve doing a linear search of the receiver, which is a waste because you already know where the object is. Also, any call to removeObjectAtIndex: will have to copy values from the index to the end of the array up by one slot at a time.
More efficient would be the following:
NSMutableArray *array = ...
NSMutableArray *itemsToKeep = [NSMutableArray arrayWithCapacity:[array count]];
for (id object in array) {
if (! shouldRemove(object)) {
[itemsToKeep addObject:object];
}
}
[array setArray:itemsToKeep];
Because we set the capacity of itemsToKeep, we don't waste any time copying values during a resize. We don't modify the array in place, so we are free to use Fast Enumeration. Using setArray: to replace the contents of array with itemsToKeep will be efficient. Depending on your code, you could even replace the last line with:
[array release];
array = [itemsToKeep retain];
So there isn't even a need to copy values, only swap a pointer.
You can use NSpredicate to remove items from your mutable array. This requires no for loops.
For example if you have an NSMutableArray of names, you can create a predicate like this one:
NSPredicate *caseInsensitiveBNames =
[NSPredicate predicateWithFormat:#"SELF beginswith[c] 'b'"];
The following line will leave you with an array that contains only names starting with b.
[namesArray filterUsingPredicate:caseInsensitiveBNames];
If you have trouble creating the predicates you need, use this apple developer link.
I did a performance test using 4 different methods. Each test iterated through all elements in a 100,000 element array, and removed every 5th item. The results did not vary much with/ without optimization. These were done on an iPad 4:
(1) removeObjectAtIndex: -- 271 ms
(2) removeObjectsAtIndexes: -- 1010 ms (because building the index set takes ~700 ms; otherwise this is basically the same as calling removeObjectAtIndex: for each item)
(3) removeObjects: -- 326 ms
(4) make a new array with objects passing the test -- 17 ms
So, creating a new array is by far the fastest. The other methods are all comparable, except that using removeObjectsAtIndexes: will be worse with more items to remove, because of the time needed to build the index set.
Either use loop counting down over indices:
for (NSInteger i = array.count - 1; i >= 0; --i) {
or make a copy with the objects you want to keep.
In particular, do not use a for (id object in array) loop or NSEnumerator.
For iOS 4+ or OS X 10.6+, Apple added passingTest series of APIs in NSMutableArray, like – indexesOfObjectsPassingTest:. A solution with such API would be:
NSIndexSet *indexesToBeRemoved = [someList indexesOfObjectsPassingTest:
^BOOL(id obj, NSUInteger idx, BOOL *stop) {
return [self shouldRemove:obj];
}];
[someList removeObjectsAtIndexes:indexesToBeRemoved];
Nowadays you can use reversed block-based enumeration. A simple example code:
NSMutableArray *array = [#[#{#"name": #"a", #"shouldDelete": #(YES)},
#{#"name": #"b", #"shouldDelete": #(NO)},
#{#"name": #"c", #"shouldDelete": #(YES)},
#{#"name": #"d", #"shouldDelete": #(NO)}] mutableCopy];
[array enumerateObjectsWithOptions:NSEnumerationReverse usingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
if([obj[#"shouldDelete"] boolValue])
[array removeObjectAtIndex:idx];
}];
Result:
(
{
name = b;
shouldDelete = 0;
},
{
name = d;
shouldDelete = 0;
}
)
another option with just one line of code:
[array filterUsingPredicate:[NSPredicate predicateWithFormat:#"shouldDelete == NO"]];
In a more declarative way, depending on the criteria matching the items to remove you could use:
[theArray filterUsingPredicate:aPredicate]
#Nathan should be very efficient
Here's the easy and clean way. I like to duplicate my array right in the fast enumeration call:
for (LineItem *item in [NSArray arrayWithArray:self.lineItems])
{
if ([item.toBeRemoved boolValue] == YES)
{
[self.lineItems removeObject:item];
}
}
This way you enumerate through a copy of the array being deleted from, both holding the same objects. An NSArray holds object pointers only so this is totally fine memory/performance wise.
Add the objects you want to remove to a second array and, after the loop, use -removeObjectsInArray:.
this should do it:
NSMutableArray* myArray = ....;
int i;
for(i=0; i<[myArray count]; i++) {
id element = [myArray objectAtIndex:i];
if(element == ...) {
[myArray removeObjectAtIndex:i];
i--;
}
}
hope this helps...
Why don't you add the objects to be removed to another NSMutableArray. When you are finished iterating, you can remove the objects that you have collected.
How about swapping the elements you want to delete with the 'n'th element, 'n-1'th element and so on?
When you're done you resize the array to 'previous size - number of swaps'
If all objects in your array are unique or you want to remove all occurrences of an object when found, you could fast enumerate on an array copy and use [NSMutableArray removeObject:] to remove the object from the original.
NSMutableArray *myArray;
NSArray *myArrayCopy = [NSArray arrayWithArray:myArray];
for (NSObject *anObject in myArrayCopy) {
if (shouldRemove(anObject)) {
[myArray removeObject:anObject];
}
}
benzado's anwser above is what you should do for preformace. In one of my applications removeObjectsInArray took a running time of 1 minute, just adding to a new array took .023 seconds.
I define a category that lets me filter using a block, like this:
#implementation NSMutableArray (Filtering)
- (void)filterUsingTest:(BOOL (^)(id obj, NSUInteger idx))predicate {
NSMutableIndexSet *indexesFailingTest = [[NSMutableIndexSet alloc] init];
NSUInteger index = 0;
for (id object in self) {
if (!predicate(object, index)) {
[indexesFailingTest addIndex:index];
}
++index;
}
[self removeObjectsAtIndexes:indexesFailingTest];
[indexesFailingTest release];
}
#end
which can then be used like this:
[myMutableArray filterUsingTest:^BOOL(id obj, NSUInteger idx) {
return [self doIWantToKeepThisObject:obj atIndex:idx];
}];
A nicer implementation could be to use the category method below on NSMutableArray.
#implementation NSMutableArray(BMCommons)
- (void)removeObjectsWithPredicate:(BOOL (^)(id obj))predicate {
if (predicate != nil) {
NSMutableArray *newArray = [[NSMutableArray alloc] initWithCapacity:self.count];
for (id obj in self) {
BOOL shouldRemove = predicate(obj);
if (!shouldRemove) {
[newArray addObject:obj];
}
}
[self setArray:newArray];
}
}
#end
The predicate block can be implemented to do processing on each object in the array. If the predicate returns true the object is removed.
An example for a date array to remove all dates that lie in the past:
NSMutableArray *dates = ...;
[dates removeObjectsWithPredicate:^BOOL(id obj) {
NSDate *date = (NSDate *)obj;
return [date timeIntervalSinceNow] < 0;
}];
Iterating backwards-ly was my favourite for years , but for a long time I never encountered the case where the 'deepest' ( highest count) object was removed first. Momentarily before the pointer moves on to the next index there ain't anything and it crashes.
Benzado's way is the closest to what i do now but I never realised there would be the stack reshuffle after every remove.
under Xcode 6 this works
NSMutableArray *itemsToKeep = [NSMutableArray arrayWithCapacity:[array count]];
for (id object in array)
{
if ( [object isNotEqualTo:#"whatever"]) {
[itemsToKeep addObject:object ];
}
}
array = nil;
array = [[NSMutableArray alloc]initWithArray:itemsToKeep];