[objective-c] enumerateObjectsUsingBlock과 for를 사용하는 경우

명백한 차이점 외에 :

  • 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:합니까? 나중에 또는 여러 곳에서 실행하기 위해 블록을 저장할 때. 실제로 루프 바디를 과도하게 대체하는 대신 블록을 일급 함수로 사용하는 경우에 좋습니다.


답변

이 질문은 오래되었지만 내용이 변경되지 않았지만 허용 된 답변이 잘못되었습니다.

enumerateObjectsUsingBlockAPI는보다 우선 의미되지 않았다 for-in하지만 완전히 다른 사용 사례 :

  • 임의의 로컬이 아닌 논리를 적용 할 수 있습니다. 즉, 배열에서 블록을 사용하기 위해 블록이 무엇을하는지 알 필요가 없습니다.
  • 대규모 수집 또는 대량 계산을위한 동시 열거 ( withOptions:매개 변수 사용)

Fast Enumeration with with for-in는 여전히 컬렉션을 열거하는 관용적 방법입니다.

빠른 열거 형은 코드의 간결성, 가독성 및 추가 최적화 를 통해 자연스럽게 빠릅니다. 오래된 C for-loop보다 빠릅니다!

빠른 테스트에 따르면 iOS 7의 2014 년에 enumerateObjectsUsingBlockfor-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이 아닌 인덱스에서 시작해야 할 때


답변