명백한 차이점 외에 :
enumerateObjectsUsingBlock
인덱스와 객체가 모두 필요할 때 사용(나는 이것에 대해 잘못했습니다. 범음의 대답을보십시오)enumerateObjectsUsingBlock
지역 변수를 수정해야 할 때 사용하지 마십시오
되어 enumerateObjectsUsingBlock
일반적으로 고려 좋든 나쁘 때 for (id obj in myArray)
것 또한 사용할 수 있습니까? 장점 / 단점은 무엇입니까 (예 : 성능이 다소 떨어짐)?
답변
궁극적으로 사용하려는 패턴을 사용하고 상황에 따라 자연스럽게 나오십시오.
for(... in ...)
매우 편리하고 구문 적으로 간단 하지만 enumerateObjectsUsingBlock:
흥미 롭거나 증명할 수없는 여러 가지 기능이 있습니다.
-
enumerateObjectsUsingBlock:
빠른 열거보다 빠르거나 빠릅니다 ( 지원을for(... in ...)
사용하여NSFastEnumeration
열거 구현). 빠른 열거는 빠른 열거를 위해 내부 표현에서 표현으로 변환해야합니다. 오버 헤드가 있습니다. 블록 기반 열거는 콜렉션 클래스가 기본 스토리지 형식의 가장 빠른 순회만큼 빠르게 컨텐츠를 열거 할 수있게합니다. 배열과 관련이 없지만 사전에 큰 차이가있을 수 있습니다. -
“로컬 변수를 수정해야 할 때 enumerateObjectsUsingBlock을 사용하지 마십시오”-사실이 아닙니다. 당신은 당신의 지역 주민을 선언 할 수
__block
있으며 블록에서 쓸 수 있습니다. -
enumerateObjectsWithOptions:usingBlock:
동시 또는 역 열거를 지원합니다. -
사전과 함께 블록 기반 열거는 키와 값을 동시에 검색하는 유일한 방법입니다.
개인적으로, 나는 개인의 선택 enumerateObjectsUsingBlock:
보다 더 자주 사용 for (... in ...)
합니다.
답변
간단한 열거의 경우 빠른 열거 (즉, for…in…
루프)를 사용하는 것이 관용적 인 옵션입니다. 블록 방법은 약간 빠를 수 있지만 대부분의 경우 중요하지 않습니다. 소수의 프로그램은 CPU에 바인딩되어 있으며 내부 계산 대신 루프 자체가 병목 현상을 일으키는 경우는 거의 없습니다.
간단한 루프도 더 명확하게 읽습니다. 두 버전의 상용구는 다음과 같습니다.
for (id x in y){
}
[y enumerateObjectsUsingBlock:^(id x, NSUInteger index, BOOL *stop){
}];
색인을 추적하기 위해 변수를 추가하더라도 간단한 루프를 쉽게 읽을 수 있습니다.
그래서 언제 사용해야 enumerateObjectsUsingBlock:
합니까? 나중에 또는 여러 곳에서 실행하기 위해 블록을 저장할 때. 실제로 루프 바디를 과도하게 대체하는 대신 블록을 일급 함수로 사용하는 경우에 좋습니다.
답변
이 질문은 오래되었지만 내용이 변경되지 않았지만 허용 된 답변이 잘못되었습니다.
enumerateObjectsUsingBlock
API는보다 우선 의미되지 않았다 for-in
하지만 완전히 다른 사용 사례 :
- 임의의 로컬이 아닌 논리를 적용 할 수 있습니다. 즉, 배열에서 블록을 사용하기 위해 블록이 무엇을하는지 알 필요가 없습니다.
- 대규모 수집 또는 대량 계산을위한 동시 열거 (
withOptions:
매개 변수 사용)
Fast Enumeration with with for-in
는 여전히 컬렉션을 열거하는 관용적 방법입니다.
빠른 열거 형은 코드의 간결성, 가독성 및 추가 최적화 를 통해 자연스럽게 빠릅니다. 오래된 C for-loop보다 빠릅니다!
빠른 테스트에 따르면 iOS 7의 2014 년에 enumerateObjectsUsingBlock
for-in보다 700 % 느리게 (100 개 항목 배열의 1mm 반복을 기준으로) 느립니다.
여기서 성능이 실질적인 관심사입니까?
드물지만 예외는 아닙니다.
요점은 실제로 정당한 이유없이 enumerateObjectsUsingBlock:
over 를 사용하면 이점이 거의 없음을 보여주는 것입니다 for-in
. 코드를 더 읽기 쉽게 또는 더 빠르거나 스레드로부터 안전하게 만들지는 않습니다. (또 다른 일반적인 오해).
선택은 개인 취향에 달려 있습니다. 나에게 관용적이고 읽기 쉬운 옵션이 이긴다. 이 경우에는를 사용하는 고속 열거 for-in
입니다.
기준:
NSMutableArray *arr = [NSMutableArray array];
for (int i = 0; i < 100; i++) {
arr[i] = [NSString stringWithFormat:@"%d", i];
}
int i;
__block NSUInteger length;
i = 1000 * 1000;
uint64_t a1 = mach_absolute_time();
while (--i > 0) {
for (NSString *s in arr) {
length = s.length;
}
}
NSLog(@"For-in %llu", mach_absolute_time()-a1);
i = 1000 * 1000;
uint64_t b1 = mach_absolute_time();
while (--i > 0) {
[arr enumerateObjectsUsingBlock:^(NSString *s, NSUInteger idx, BOOL *stop) {
length = s.length;
}];
}
NSLog(@"Enum %llu", mach_absolute_time()-b1);
결과 :
2014-06-11 14:37:47.717 Test[57483:60b] For-in 1087754062
2014-06-11 14:37:55.492 Test[57483:60b] Enum 7775447746
답변
성능에 관한 질문에 답하기 위해 성능 테스트 프로젝트를 사용하여 몇 가지 테스트를 수행했습니다 . 배열의 모든 객체에 메시지를 보내는 세 가지 옵션 중 가장 빠른 옵션을 알고 싶었습니다.
옵션은 다음과 같습니다.
1) makeObjectsPerformSelector
[arr makeObjectsPerformSelector:@selector(_stubMethod)];
2) 빠른 열거 및 일반 메시지 보내기
for (id item in arr)
{
[item _stubMethod];
}
3) enumerateObjectsUsingBlock 및 일반 메시지 전송
[arr enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop)
{
[obj _stubMethod];
}];
makeObjectsPerformSelector가 가장 느리다는 것이 밝혀졌습니다. 빠른 열거보다 두 배가 걸렸습니다. enumerateObjectsUsingBlock이 가장 빠르며 빠른 반복보다 약 15-20 % 빠릅니다.
따라서 최상의 성능에 대해 매우 우려되는 경우 enumerateObjectsUsingBlock을 사용하십시오. 그러나 어떤 경우에는 컬렉션을 열거하는 데 걸리는 시간이 각 객체가 실행하기를 원하는 코드를 실행하는 데 걸리는 시간에 비해 뒤쳐집니다.
답변
중첩 루프를 중단하려는 경우 enumerateObjectsUsingBlock을 외부 루프로 사용하는 것이 매우 유용합니다.
예 :
[array1 enumerateObjectsUsingBlock:^(id obj1, NSUInteger idx, BOOL * _Nonnull stop) {
for(id obj2 in array2) {
for(id obj3 in array3) {
if(condition) {
// break ALL the loops!
*stop = YES;
return;
}
}
}
}];
대안은 goto 문을 사용하는 것입니다.
답변
성능에 대한 포괄적 인 비교를 시작한 @bbum 및 @Chuck에게 감사합니다. 사소한 일임을 알게되어 기쁘다. 나는 함께 갔다 :
-
for (... in ...)
-내 기본 이동으로. IDE 자동 완성으로 인해 대부분의 데이터 구조에 대한 타이핑이 적습니다. -
enumerateObject...
-객체 및 색인에 대한 액세스가 필요한 경우 비 배열 또는 사전 구조에 액세스 할 때 (개인 선호도) -
for (int i=idx; i<count; i++)
-배열이 아닌 0이 아닌 인덱스에서 시작해야 할 때