快速枚举是一种语言特性,让我们可以高效并且安全的使用简明的语法来迭代集合的内容。
快速枚举的语法定义如下
for ( Type newVariable in expression ) { statements } |
或者
Type existingItem; |
for ( existingItem in expression ) { statements } |
在上述两种情况中,表达式生成了一个遵循 NSFastEnumeration
协议的对象 (参见 “Adopting Fast Enumeration”). 迭代的变量在每次循环中为声明的对象设置 。当循环结束时,迭代的变量被设为 nil
。要是循环提前结束,那么迭代变量被遗弃,指向最后迭代的对象。
使用快速枚举的好处:
枚举相比其它方式更加高效,例如 NSEnumerator
.
语法更加简明
枚举的使用是“安全的”—枚举器有一个突变守卫,因此当你在枚举进行中试图驱修改集合时,就会有一个异常被抛出。
因为迭代过程中的对象的改变是禁止的,故此你可以并发的执行多个迭代。
另一方面,这个特性的行为很像一个标准的 for
循环。你可以使用 break
来终止迭代或者使用 continue
来跳出本次循环跳到下个元素。
如果一个类的实例提供了访问其它对象集合的方法,那么这个类就可以采用 NSFastEnumeration
协议. 在 Foundation 框架中的集合类—NSArray
, NSDictionary
以及 NSSet
—就采用了这个协议,就像 NSEnumerator
. 很显然,在 NSArray
和 NSSet
中,枚举是针对它们的内容。对于其它的类,响应的文档应当明确哪个属性是用来迭代的。例如,NSDictionary
以及 Core Data 类, NSManagedObjectModel
提供了对快速迭代的支持; NSDictionary
枚举它的键, NSManagedObjectModel
枚举它的实体。
下面的例子向我们展示了如何 NSArray
和 NSDictionary
对象是如何使用快速枚举的.
NSArray *array = [NSArray arrayWithObjects: |
@"one", @"two", @"three", @"four", nil]; |
|
for (NSString *element in array) { |
NSLog(@"element: %@", element); |
} |
|
NSDictionary *dictionary = [NSDictionary dictionaryWithObjectsAndKeys: |
@"quattuor", @"four", @"quinque", @"five", @"sex", @"six", nil]; |
|
NSString *key; |
for (key in dictionary) { |
NSLog(@"English: %@, Latin: %@", key, [dictionary objectForKey:key]); |
} |
你也可以使用 NSEnumerator
对象来做快速枚举
NSArray *array = [NSArray arrayWithObjects: |
@"one", @"two", @"three", @"four", nil]; |
|
NSEnumerator *enumerator = [array reverseObjectEnumerator]; |
for (NSString *element in enumerator) { |
if ([element isEqualToString:@"three"]) { |
break; |
} |
} |
|
NSString *next = [enumerator nextObject]; |
// next = "two" |
如果你想要使用下标,那么你定义一个变量,然后在枚举里自增计数就好了
NSArray *array = <#Get an array#>; |
NSUInteger index = 0; |
|
for (id element in array) { |
NSLog(@"Element at index %u is: %@", index, element); |
index++; |
} |
Fast enumeration is a language feature that allows you to efficiently and safely enumerate over the contents of a collection using a concise syntax.
The syntax for fast enumeration is defined as follows:
for ( Type newVariable in expression ) { statements } |
or
Type existingItem; |
for ( existingItem in expression ) { statements } |
In both cases, expression yields an object that conforms to the NSFastEnumeration
protocol (see “Adopting Fast Enumeration”). The iterating variable is set to each item in the returned object in turn, and the code defined bystatements
is executed. The iterating variable is set to nil
when the loop ends by exhausting the source pool of objects. If the loop is terminated early, the iterating variable is left pointing to the last iteration item.
There are several advantages to using fast enumeration:
The enumeration is considerably more efficient than, for example, using NSEnumerator
directly.
The syntax is concise.
Enumeration is “safe”—the enumerator has a mutation guard so that if you attempt to modify the collection during enumeration, an exception is raised.
Because mutation of the object during iteration is forbidden, you can perform multiple enumerations concurrently.
In other respects, the feature behaves like a standard for
loop. You can use break
to interrupt the iteration andcontinue
to advance to the next element.
Any class whose instances provide access to a collection of other objects can adopt the NSFastEnumeration
protocol. The collection classes in the Foundation framework—NSArray
, NSDictionary
, and NSSet
—adopt this protocol, as does NSEnumerator
. It should be obvious that in the cases of NSArray
and NSSet
the enumeration is over their contents. For other classes, the corresponding documentation should make clear what property is iterated over—for example, NSDictionary
and the Core Data class NSManagedObjectModel
provide support for fast enumeration; NSDictionary
enumerates its keys, and NSManagedObjectModel
enumerates its entities.
The following code example illustrates using fast enumeration with NSArray
and NSDictionary
objects.
NSArray *array = [NSArray arrayWithObjects: |
@"one", @"two", @"three", @"four", nil]; |
|
for (NSString *element in array) { |
NSLog(@"element: %@", element); |
} |
|
NSDictionary *dictionary = [NSDictionary dictionaryWithObjectsAndKeys: |
@"quattuor", @"four", @"quinque", @"five", @"sex", @"six", nil]; |
|
NSString *key; |
for (key in dictionary) { |
NSLog(@"English: %@, Latin: %@", key, [dictionary objectForKey:key]); |
} |
You can also use NSEnumerator
objects with fast enumeration, as illustrated in this example:
NSArray *array = [NSArray arrayWithObjects: |
@"one", @"two", @"three", @"four", nil]; |
|
NSEnumerator *enumerator = [array reverseObjectEnumerator]; |
for (NSString *element in enumerator) { |
if ([element isEqualToString:@"three"]) { |
break; |
} |
} |
|
NSString *next = [enumerator nextObject]; |
// next = "two" |
For collections or enumerators that have a well-defined order—such as an NSArray
or an NSEnumerator
instance derived from an array—the enumeration proceeds in that order, so simply counting iterations gives you the proper index into the collection if you need it.
NSArray *array = <#Get an array#>; |
NSUInteger index = 0; |
|
for (id element in array) { |
NSLog(@"Element at index %u is: %@", index, element); |
index++; |
} |