Does fast enumeration in Objective-C guarantee the order of iteration? - objective-c

Can I expect it to go from the start of an array to the end in order? Can't find anything in the docs about this.
i.e. is
for (id val in array)
{
NSLog(#"%#", val);
}
always going to print out the same as
for (int i = 0; i < [array count]; ++i)
{
NSLog(#"%#", [array objectAtIndex:i]);
}

From Apples' Objective-C documentation on fast enumeration:
For collections or enumerators that have a well-defined order—such as NSArray or NSEnumerator instance derived from an array—the enumeration proceeds in that order, so simply counting iterations will give you the proper index into the collection if you need it.

Once again I've found the answer right after posting. My old reference didn't mention the order of iteration, but the online one did. The array is indeed iterated in order.

Related

CLISTs in Objective C

I have cpp code where the struct objects are put into the CLISTS. I am porting this code into Objective C.
CLIST is similar to a doubly linked list with .RemoveAt , .GetAt , .InsertBefore , .GetNext , .GetHeadPosition functions.
How to implement the same in Objective C.
Do I need to implement doubly linked list in Objective C.Is there any other predefined methods to use it.
A CLIST is presumably circular? Hence the GetHeadPosition?
In any case, NSArray (or, NSMutableArray in this case, since you want to be inserting) is the normal way to keep ordered lists in Objective-C.
For RemoveAt, use removeObjectAtIndex:. For GetAt, use objectAtIndex:. For InsertBefore you're probably going to want to write a little something like:
- (void)insert:(id)objectToInsert before:(id)referenceObject
{
int index = [array indexOfObject:referenceObject];
if(index == NSNotFound) return; // or whatever you'd expect.
// Maybe object is just inserted at the end?
index = index - 1;
if(index < 0) index = [array count];
[array insertObject:objectToInsert atIndex:index];
}
(which would probably go better in an NSArray category, but you get the point)
For GetNext and GetHeadPosition you probably want to keep your array position in a separate variable. So for GetNext:
arrayPosition = (arrayPosition + 1)%[array count];
return [array objectAtIndex:arrayPosition];
And for GetHeadPosition, just:
return arrayPosition;
EDIT: for iterating through an NSArray, the easiest way is actually to ignore anything explicit and just use:
for(ObjectType *object in array)
{
/* do something with object */
}
That generally means you don't really need an analogue of GetNext, but you can't mutate the array while in that loop so it's not always usable.

Fast Enumeration Vs NSEnumerator in Objective-C

I have seen this over and over, why exactly is it faster to use fast enumeration in loops rather than an NSEnumerator using nextObject:.
NSEnumerator is the old way to enumerate over collections. It involves creating an object to represent the enumeration, then calling a method on it for every single iteration. While this was perfectly serviceable for many years, it's not terribly efficient, as it involves at least one message send for every iteration of the loop. NSFastEnumeration is the more modern approach, which leverages native language support to provide a much more efficient enumeration. The way it works under the hood is it creates a struct that represents the current enumeration state and repeatedly calls -countByEnumeratingWithState:objects:count: on the collection. This method returns a C array of objects in the objects out-param as well as a counter in the count out-param. This allows the caller to then iterate over the C array. In essence, this means one message call per chunk of objects, which, depending on the collection, could be as efficient as a single message call to get all objects.
If you have a bit of code that looks like
for (id obj in myArray) {
[obj doSomething];
}
This gets translated by the compiler into something roughly equivalent to
NSFastEnumerationState __enumState = {0};
id __objects[MAX_STACKBUFF_SIZE];
NSUInteger __count;
while ((__count = [myArray countByEnumeratingWithState:&__enumState objects:__objects count:MAX_STACKBUFF_SIZE]) > 0) {
for (NSUInteger i = 0; i < __count; i++) {
id obj = __objects[i];
[obj doSomething];
}
}
The actual variables used are hidden, and the maximum size of the object buffer is also implementation-dependent, but the basic idea is there. It translates iteration over an obj-c collection into iteration over a C array.
GCC 8.9.4 Fast enumeration
protocol
GNUstep libs/base/trunk/Source/NSEnumerator.m countByEnumeratingWithState:objects:count:
It is not same as Apple's implementation but it is helpful to understand.
- (NSUInteger) countByEnumeratingWithState: (NSFastEnumerationState*)state
objects: (id*)stackbuf
count: (NSUInteger)len
{
IMP nextObject = [self methodForSelector: #selector(nextObject)];
int i;
state->itemsPtr = stackbuf;
state->mutationsPtr = (unsigned long*)self;
for (i = 0; i < len; i++)
{
id next = nextObject(self, #selector(nextObject));
if (nil == next)
{
return i;
}
*(stackbuf+i) = next;
}
return len;
}
NSArray *array = something;
array = { {1,2}, {2,3}, {3,4} }
that means array is an array of array. so how can you access all the arrays and their values.
we can use for loop like this
for (int i = 0; i < array.count; i++)
{
NSArray x = [array objectAtIndex:i];
}
or a fast enum works like this
for(NSArray array2 in array)
{
// do what ever you want with this new array2.
}
this is a sample example.
PS. I forgot how the array looks in console.

Removing object from NSMutableArray

I stumbled across the following shortcut in setting up a for loop (shortcut compared to the textbook examples I have been using):
for (Item *i in items){ ... }
As opposed to the longer format:
for (NSInteger i = 0; i < [items count]; i++){ ... } //think that's right
If I'm using the shorter version, is there a way to remove the item currently being iterated over (ie 'i')? Or do I need to use the longer format?
You cannot remove objects from array while fast-enumerating it:
numeration is “safe”—the enumerator
has a mutation guard so that if you
attempt to modify the collection
during enumeration, an exception is
raised.
Anyway why do you need to change you container while enumerating it? Consider storing elements that need to be deleted and remove them from your container using removeObjectsInArray: or removeObjectsAtIndexes: method.
Just add keyword break; after removing the item...
for(id item in items) {
if([item isEqual:itemToDelete]) {
[items removeObject:item];
break; // A very important line 🛑
}
}
An Objective-C collection must not be modified during enumeration.
You may use this variant to delete objects from collection:
for (NSInteger i = items.count - 1; i >= 0 ; i--) {
[items removeObjectAtIndex:i];
}
The former loop is a "for-each" loop in Objective C.
*i is a pointer to the direct item in the items-Array (most of the time this will be NSMutableArray).
This way you can operate directly on the item:
[items removeObject: i];
This (should) work - I am currently not working on my Mac and can't check it.
However it might be that Objective-C Prevents removing objects while iterating over the collection (that is quite common in most languages).
I use this code for this:
for (NSUInteger i = [items count] - 1; ; i--) {
[items removeObjectAtIndex:i];
}

Replacing multiple array contents with a single object?

I have an NSMutableArray with contents I want to replace with NSNull objects.
This is what I do:
NSMutableArray* nulls = [NSMutableArray array];
for (NSInteger i = 0; i < myIndexes.count; i++)
[nulls addObject:[NSNull null]];
[stageMap replaceObjectsAtIndexes:myIndexes withObjects:nulls];
How can I do this more efficiently?
Is there a way to enumerate an NSIndexSet, so I can replace the array content one by one?
Solved
Suggested method turns out to be 2x faster (avg 0.000565s vs 0.001210s):
if (myIndex.count > 0)
{
NSInteger index = [myIndex firstIndex];
for (NSInteger i = 0; i < myIndex.count; i++)
{
[stageMap replaceObjectAtIndex:index withObject:[NSNull null]];
index = [myIndex indexGreaterThanIndex:index];
}
}
You can use a for loop. Start with the first index, use indexGreaterThanIndex: to get the next index, and stop after you hit the last index.
Don't forget to account for an empty index set. Both the first and last index will be NSNotFound in that case. The easiest way is to test the index set's count; if it's zero, don't loop.
Also, what Jason Coco said about profiling. Don't worry too much about efficiency until your program works, and don't go optimizing things until you have run Shark (or Instruments, if that's your thing) and found exactly what is slow.
I realise this is a very old question but I'm posting here in case anyone else finds this question you could use:
[indexes enumerateIndexesUsingBlock:^(NSUInteger idx, BOOL *stop) {
NSLog(#"index: %d", idx);
[objectArray replaceObjectAtIndex:idx
withObject:newObject];
}];
Which is a lot more succinct.

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