一直以為for循環(huán)和 for in 是一樣的,例如:
CFAbsoluteTime start = CFAbsoluteTimeGetCurrent();
NSMutableArray * arr = @[@1,@2,@3,@4,@5].mutableCopy;
for (NSNumber *obj in arr) {
NSLog(@"%@",obj);
}
CFAbsoluteTime end = CFAbsoluteTimeGetCurrent();
NSLog(@"for in cost: %0.3f",end - start);
CFAbsoluteTime startTime = CFAbsoluteTimeGetCurrent();
for (int i = 0; i < arr.count; i ++) {
NSLog(@"%@",arr[i]);
}
CFAbsoluteTime endTime = CFAbsoluteTimeGetCurrent();
NSLog(@"for cost: %0.3f",endTime - startTime);
但是偶然間寫了這么一段就崩潰了
for (NSString * obj in arr) {
if ([obj integerValue] == 2) {
[arr addObject:@"6"];
}
}
CFAbsoluteTime end = CFAbsoluteTimeGetCurrent();
NSLog(@"for in cost: %0.3f Arr:%@",end - start,arr);
但是如果寫成for循環(huán)就沒有問題,然后就去百度了一下發(fā)現(xiàn):如果在for in 循環(huán)里,對這個(gè)數(shù)組進(jìn)行了修改的話,無論是增挤土,刪,修改數(shù)組元素位置误算,都會扔一個(gè)異常出來仰美,枚舉的過程中數(shù)組發(fā)生了突變(<__NSArrayM: 0xa4fc000> was mutated while being enumerated.)
for in實(shí)際上是快速枚舉,跟for循環(huán)意義上還是有區(qū)別的儿礼。NSArray的枚舉操作中有一條需要注意:對于可變數(shù)組進(jìn)行枚舉操作時(shí)筒占,不能通過添加或刪除對象等這類操作來改變數(shù)組容器,否則就會報(bào)錯(cuò).而本身這種操作也是有問題的,數(shù)組容器已經(jīng)改變蜘犁,可能遍歷到?jīng)]有分配的位置翰苫,用for循環(huán)機(jī)器不能自己察覺,但是枚舉器可以察覺这橙。
enumerateKeysAndObjectsUsingBlock用法
NSDictionary * dic = [NSDictionary dictionaryWithObjectsAndKeys:@"obj1",@"key1",@"obj2",@"key2", nil];
[dic enumerateKeysAndObjectsUsingBlock:^(id key, id value, BOOL *stop) {
NSLog(@"value for key %@ is %@ ", key, value);
if ([@"key2" isEqualToString:key]) {
*stop = YES;
}
}];
NSDictionary有一個(gè)方法叫enumerateKeysAndObjectsUsingBlock奏窑,它就一個(gè)參數(shù)就是block,這個(gè)block攜帶了三個(gè)參數(shù)屈扎,這將要把dictionary里面的key和value每次一組傳遞到block埃唯,enumerateKeysAndObjectsUsingBlock會遍歷dictionary并把里面所有的key和value一組一組的展示給你,每組都會執(zhí)行這個(gè)block鹰晨。這其實(shí)就是傳遞一個(gè)block到另一個(gè)方法墨叛,在這個(gè)例子里它會帶著特定參數(shù)被反復(fù)調(diào)用止毕,直到找到一個(gè)key2的key,然后就會通過重新賦值那個(gè)BOOL *stop來停止運(yùn)行漠趁,停止遍歷同時(shí)停止調(diào)用block扁凛。
更詳細(xì)的用法
(http://blog.itpub.net/12231606/viewspace-1084119/)
enumerateObjectsWithOptions使用
NSArray *array = [[NSArray alloc]initWithObjects:@"a",@"b",@"c",@"d",@"e",@"f", nil];
//遍歷數(shù)組元素
[array enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
NSLog(@"obj=%@ idx=%ld",obj,idx);
}];
//如果指定了NSEnumerationConcurrent順序,那么底層通過GCD來處理并發(fā)執(zhí)行事宜闯传,具體實(shí)現(xiàn)可能會用到dispatch group谨朝。也就是說,這個(gè)會用多線程來并發(fā)實(shí)現(xiàn)甥绿,并不保證按照順序執(zhí)行
//NSEnumerationReverse 倒序排列
[array enumerateObjectsWithOptions:NSEnumerationReverse usingBlock:^(id obj, NSUInteger idx, BOOL * _Nonnull stop) {
NSLog(@"idx=%ld, id=%@", idx, obj);
//當(dāng)需要結(jié)束循環(huán)的時(shí)候,調(diào)用stop,賦予YES
if (idx ==3) {
*stop = YES;
}
}];
//NSIndexSet類代表一個(gè)不可變的獨(dú)特的無符號整數(shù)的集合,稱為索引,因?yàn)槭褂盟鼈兊姆绞阶直摇_@個(gè)集合被稱為索引集 唯一的,有序的共缕,無符號整數(shù)的集合
[NSIndexSet indexSetWithIndex:1];//創(chuàng)建一個(gè)索引集合洗出,根據(jù)索引值
[NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0,8)];//創(chuàng)建一個(gè)索引集合,根據(jù)一個(gè)NSRange對象
[array enumerateObjectsAtIndexes:[NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0,3)] options:NSEnumerationReverse usingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
NSLog(@"\n\n\nidx=%ld, id=%@", idx, obj);
}];
for in图谷、經(jīng)典for循環(huán)和EnumerateObjectsUsingBlock 的比較
- 對于集合中對象數(shù)很多的情況下共苛,for in 的遍歷速度非常之快,但小規(guī)模的遍歷并不明顯(還沒普通for循環(huán)快)
- Value查詢index的時(shí)候, 面對大量的數(shù)組推薦使用
enumerateObjectsWithOptions
的并行方法. - 遍歷字典類型的時(shí)候, 推薦使用
enumerateKeysAndObjectsUsingBlock
,block版本的字典遍歷可以同時(shí)取key和value(forin只能取key再手動(dòng)取value)
參考文章:
(http://www.reibang.com/p/ef3f1731a353)
(http://blog.sunnyxx.com/2014/04/30/ios_iterator/)