让我们假设我正在做
for (UserCollection * userCollection in [smth fetchUserCollections]) {
}
是否可以保证[user fetchUserCollection]在每个开头只调用一次?
或者我不应该指望它?
答案 0 :(得分:3)
嗯...
我不知道任何官方 Apple或clang文档,保证它只被调用一次。目标C语言没有规范。
另一方面......
你可以指望它只被召唤一次。这就是今天它的工作方式,反复调用它会是一种性能回归,它可能会打破很多今天有用的代码。
例如,您无法做到这一点:
for (Card *card in [deck shuffledArrayOfCards]) {
...
}
因为您在每次通话时都会收到新的随机排序。
在幕后,您的程序会在循环开始时调用[smth fetchUserCollections]
一次并保存结果。结果是一个实现NSFastEnumeration
协议的对象。然后,它会重复向countByEnumeratingWithState:objects:count:
对象发送NSFastEnumeration
,直到对象停止返回元素。循环向NSFastEnumeration
对象发送多条消息,但只向您的smth
对象发送一条消息。
答案 1 :(得分:1)
我同意rob mayoff关于NSFastEnumeration
。我自己通过下面的快速代码测试验证了它,并且我没有看到为什么for...in
结构会因为可枚举集合的任何其他实现而改变的原因。
另外值得注意的是 - 当我运行此测试并将大小设置为NSUIntegerMax
时,它引发了一个很好的例外:)
capacity (18446744073709551615) is ridiculous
代码:
#import <Foundation/Foundation.h>
@interface FastEnumer : NSObject
- (NSArray *)enumeratedArrayOfSize:(NSUInteger)size;
@end
@implementation FastEnumer
- (NSArray *)enumeratedArrayOfSize:(NSUInteger)size
{
// counts how many times this method is called
static NSUInteger calledCount = 0;
NSLog(@"(Enumerated) Called: %ld\n", ++calledCount);
// populates an array of NSStrings of alphabet letters to enumerate
static NSMutableArray *testArray = nil;
if (!testArray) {
testArray = [[NSMutableArray alloc] initWithCapacity:size];
NSArray *sample = @[@"A", @"B", @"C", @"D", @"E", @"F", @"G", @"H",
@"I", @"J", @"K", @"L", @"M", @"N", @"O", @"P",
@"Q", @"R", @"S", @"T", @"U", @"V", @"W", @"X",
@"Y", @"Z"];
for (NSUInteger i = 0; i < size; ++i) {
[testArray addObject:sample[i % sample.count]];
}
}
return testArray;
}
@end
int main(int argc, const char * argv[]) {
@autoreleasepool {
// flag to note loop behavior
BOOL started = NO;
// testing class for the 'for...in' fast enumeration
FastEnumer *myTest = [[FastEnumer alloc] init];
// set number of items in array and use Fast Enumeration construct
NSUInteger size = 1000000000; // 1 billion
for (NSString *letter in [myTest enumeratedArrayOfSize:size]) {
// show loop has begun
if (!started) {
NSLog(@"Started 'for...in' loop with %@", letter);
started = YES;
}
}
}
return 0;
}
输出:
2014-09-26 14:16:45.826 Scratchy[8222:303] (Enumerated) Called: 1
2014-09-26 14:17:40.346 Scratchy[8222:303] Started 'for...in' loop with A
Program ended with exit code: 0