6

What is the best way to know when I have reached the last object in an array when using fast enumeration? Is there a better way than incrementing an int and then comparing that to the length of the array?

Nic Hubbard
  • 41,587
  • 63
  • 251
  • 412

5 Answers5

15

If you are starting with an array get out the last element (there's a specific call for that) and compare each element you get in the enumerator against that. Something like:

id lastEl = [myArray lastObject];

for ( id anEl in myArray )
{
   if ( anEl == lastEl )
     .....  // do the last thing
}

The comparison cost is the same as with the counter, but then you don't have the cost of incrementing the counter or mistakes that invariably arise when you forget to increment the counter.

Kendall Helmstetter Gelner
  • 74,769
  • 26
  • 128
  • 150
  • I'd agree with this, but I believe it is "lastObject" not "lastElement". – slycrel Dec 27 '10 at 22:33
  • Well now you and I agree! That's what I get for not checking the SDK docs for the call. – Kendall Helmstetter Gelner Dec 27 '10 at 22:42
  • Great answer and just what I was looking for! – Nic Hubbard Dec 27 '10 at 22:44
  • 1
    Not totally robust. As the same object can appear twice in the array, you could incorrectly do your "last thing" twice. Consider that problem when using this solution. Getting the array count before entering the loop and using an index is safer. – Julien Dec 27 '10 at 23:06
  • That is a good point but generally you would have two distinct instances even if the objects equated to the same thing; but be aware that could be an issue in design. It's still safer from the standpoint of not getting a counter increment wrong in some way, as that is a lot more likely than putting two of the same object into an array. – Kendall Helmstetter Gelner Dec 28 '10 at 00:41
  • It might not be that uncommon. If the array represents a to-many relationship to complex objects, you're right. But if the array contains simple values (e.g. strings, numbers), you can definitely be bitten by the problem, even without realizing it, as Foundation can sometime "magically" uniquify some instances. – Julien Dec 28 '10 at 12:14
  • I'll grant that for NSNumber storage you could for sure have that issue. But for NSString, it still seems very unlikely for any group of strings someone would put in an array unless they were using only constant strings and then repeating the use of them in an array... – Kendall Helmstetter Gelner Dec 28 '10 at 23:46
2

Typically, fast enumeration means you are not using a counter...

http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/ObjectiveC/Articles/ocFastEnumeration.html

The other form is without a counter is...

NSEnumerator *enumerator = [objectSet objectEnumerator];
id setObject;
while ((setObject = [enumerator nextObject]) != nil)
{
    ...
}
jlujan
  • 1,188
  • 7
  • 10
1

If the performance test is accountable here, there is no much performance difference between fast enumeration and block enumeration. Or bbum said here "Block-based enumeration allows the collection class to enumerate contents as quickly as the fastest traversal of the native storage format. "

Then I will suggest to use block enumeration so you get index and object at the same time, and you can do the comparison.

Community
  • 1
  • 1
Qiulang
  • 10,295
  • 11
  • 80
  • 129
0

You can also use enumeration with blocks:

[myArray enumerateObjectsUsingBlock:^(id  _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
    BOOL isLastObject = idx == [myArray count]-1;
    if (isLastObject){
        //...
    }
}];

If you know which kind of objects your array contains it's better to replace id with the proper class.

andreacipriani
  • 2,519
  • 26
  • 23
0

I don't believe there's any (simple) way of doing this - it's one of the trade-offs of using fast enumeration. As such, when you need to be aware of the index of the item you're enumerating over, you'll need to create an integer as you suggest.

That said, you'll still benefit from the fact that you can't go out of bounds when using a fast enumerator, etc.

John Parker
  • 54,048
  • 11
  • 129
  • 129