一直以為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);
但是偶然間寫(xiě)了這么一段就崩潰了
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);
但是如果寫(xiě)成for循環(huán)就沒(méi)有問(wèn)題,然后就去百度了一下發(fā)現(xiàn):如果在for in 循環(huán)里畏纲,對(duì)這個(gè)數(shù)組進(jìn)行了修改的話稚晚,無(wú)論是增远搪,刪裤纹,修改數(shù)組元素位置永毅,都會(huì)扔一個(gè)異常出來(lái)把跨,枚舉的過(guò)程中數(shù)組發(fā)生了突變(<__NSArrayM: 0xa4fc000> was mutated while being enumerated.)
for in實(shí)際上是快速枚舉,跟for循環(huán)意義上還是有區(qū)別的沼死。NSArray的枚舉操作中有一條需要注意:對(duì)于可變數(shù)組進(jìn)行枚舉操作時(shí)着逐,不能通過(guò)添加或刪除對(duì)象等這類操作來(lái)改變數(shù)組容器,否則就會(huì)報(bào)錯(cuò).而本身這種操作也是有問(wèn)題的,數(shù)組容器已經(jīng)改變意蛀,可能遍歷到?jīng)]有分配的位置耸别,用for循環(huán)機(jī)器不能自己察覺(jué),但是枚舉器可以察覺(jué)县钥。
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會(huì)遍歷dictionary并把里面所有的key和value一組一組的展示給你吩翻,每組都會(huì)執(zhí)行這個(gè)block。這其實(shí)就是傳遞一個(gè)block到另一個(gè)方法锥咸,在這個(gè)例子里它會(huì)帶著特定參數(shù)被反復(fù)調(diào)用狭瞎,直到找到一個(gè)key2的key,然后就會(huì)通過(guò)重新賦值那個(gè)BOOL *stop來(lái)停止運(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順序,那么底層通過(guò)GCD來(lái)處理并發(fā)執(zhí)行事宜雪侥,具體實(shí)現(xiàn)可能會(huì)用到dispatch group碗殷。也就是說(shuō),這個(gè)會(huì)用多線程來(lái)并發(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ú)特的無(wú)符號(hào)整數(shù)的集合,稱為索引,因?yàn)槭褂盟鼈兊姆绞叫科蕖_@個(gè)集合被稱為索引集? ? 唯一的,有序的旬牲,無(wú)符號(hào)整數(shù)的集合
[NSIndexSet indexSetWithIndex:1];//創(chuàng)建一個(gè)索引集合仿粹,根據(jù)索引值
[NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0,8)];//創(chuàng)建一個(gè)索引集合,根據(jù)一個(gè)NSRange對(duì)象
[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 的比較
對(duì)于集合中對(duì)象數(shù)很多的情況下吭历,for in 的遍歷速度非常之快,但小規(guī)模的遍歷并不明顯(還沒(méi)普通for循環(huán)快)
Value查詢index的時(shí)候, 面對(duì)大量的數(shù)組推薦使用enumerateObjectsWithOptions的并行方法.
遍歷字典類型的時(shí)候, 推薦使用enumerateKeysAndObjectsUsingBlock,block版本的字典遍歷可以同時(shí)取key和value(forin只能取key再手動(dòng)取value)