Fast Enumeration Vs NSEnumerator in Objective-C

南笙酒味 提交于 2019-11-27 02:02:07

问题


I have seen this over and over, why exactly is it faster to use fast enumeration in loops rather than an NSEnumerator using nextObject:.


回答1:


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.




回答2:


  • 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;
}



回答3:


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.



来源:https://stackoverflow.com/questions/5163169/fast-enumeration-vs-nsenumerator-in-objective-c

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!