2013-04-18 6 views
7

NSInvocation-retainArguments 메서드는 NSInvocation을 즉시 실행하지 않고 나중에 수행 할 때 유용합니다. 이 시간 동안 유효하도록 객체 인수를 유지합니다.- [NSInvocation retainArguments]는 블록을 복사합니까?

우리 모두 알고 있듯이 차단 인수는 유지되는 대신 복사해야합니다. 내 질문은, -retainArguments 블록 형식의 인수를 유지하는 대신 복사 할 알고 있습니까? 설명서에는 해당 내용이 표시되어 있지는 않지만 쉽고 합리적인 것으로 보입니다.

업데이트 : 업데이트 : iOS 7에서 동작이 변경된 것 같습니다. iOS 6.1 이전 버전에서 -retainArguments은 블록 유형의 매개 변수를 복사하지 않았습니다. iOS 7 이상에서는 -retainArguments이 블록 유형의 매개 변수를 복사합니다. -retainArguments의 문서는 블록을 복사한다고 말하기 위해 업데이트되었지만 동작이 변경된시기는 말하지 않습니다 (이전 OS를 지원하는 사람들에게는 매우 위험합니다). 대답은 NSInvocation 블록을 복사 할만큼 똑똑이고, 예 경우

+0

업데이트 해 주셔서 감사합니다. – matt

답변

1

번호

이미지,이 같은 일을 수행해야합니다

for (/*every arguments*/) { 
    if (/*arg is object. i.e. @encode(arg) is '@'*/) { 
     if ([arg isKindOfClss:[NSBlock class]]) { 
      arg = [arg copy]; // copy block 
     } else { 
      [arg retain]; 
     } 
    } 
} 

을 문제가를 복사하는 동안 arg이 변경되었을 것입니다 이는 retainArguments을 호출하면 NSInvocation의 인수가 변경 될 수 있기 때문에 발생하지 않아야합니다. 이것은 이미 만들어진 많은 가정을 깨뜨릴 것입니다.


업데이트 (인수가 NSInvocation을 만드는 데 사용되는 즉, 인수가 동일해야합니다 NSInvocation에서 얻을)

답을 준수하는 테스트가 NO이지만, 내 이전 시점이었다 그랬던 잘못된 생각 ...

@interface Test : NSObject 

@end 

@implementation Test 

- (void)testMethodWithBlock:(void (^)(void))block obj:(id)obj cstr:(const char *)cstr { 
    NSLog(@"%p %p %p %@", block, obj, cstr, [block class]); 
} 

@end 

@implementation testTests 

- (void)test1 { 
    __block int dummy; 
    Test *t = [[Test alloc] init]; 
    NSMethodSignature *ms = [t methodSignatureForSelector:@selector(testMethodWithBlock:obj:cstr:)]; 
    NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:ms]; 
    void (^block)(void) =^{ 
     dummy++; // stop this become global block 
    }; 
    id obj = @"object"; 
    char *cstr = malloc(5); 
    strcpy(cstr, "cstr"); 


    NSLog(@"%@", [ms debugDescription]); 

    NSLog(@"%p %p %p %@", block, obj, cstr, [block class]); 

    [invocation setSelector:@selector(testMethodWithBlock:obj:cstr:)]; 
    [invocation setArgument:&block atIndex:2]; 
    [invocation setArgument:&obj atIndex:3]; 
    [invocation setArgument:&cstr atIndex:4]; 

    [invocation invokeWithTarget:t]; 

    [invocation retainArguments]; 

    [invocation invokeWithTarget:t]; 

    free(cstr); 
} 

@end 

출력, ARC가 비활성화 (추락) :

,
2013-04-18 19:49:27.616 test[94555:c07] 0xbfffe120 0x70d2254 0x7167980 __NSStackBlock__ 
2013-04-18 19:49:27.617 test[94555:c07] 0xbfffe120 0x70d2254 0x7167980 __NSStackBlock__ 
2013-04-18 19:49:27.618 test[94555:c07] 0xbfffe120 0x70d2254 0x736a810 __NSStackBlock__ 

는 ARC가 활성화 :

2013-04-18 19:51:03.979 test[95323:c07] 0x7101e10 0x70d2268 0x7101aa0 __NSMallocBlock__ 
2013-04-18 19:51:03.979 test[95323:c07] 0x7101e10 0x70d2268 0x7101aa0 __NSMallocBlock__ 
2013-04-18 19:51:03.980 test[95323:c07] 0x7101e10 0x70d2268 0xe0c1310 __NSMallocBlock__ 

당신이 볼 수 있듯이, C 문자열이 retainArguments하지만 블록으로 복사됩니다. 하지만 ARC가 활성화 된 상태에서 ARC가 어느 시점에서 사용자를 대신하여 복사 했으므로 문제가 없어집니다.

+0

블록을 복사해도 유형 시스템에서 고려해야하는 블록의 서명은 변경되지 않습니다. 물론, 그것은'__NSStackBlock__'에서'__NSHeapBlock__'으로 갈지 모릅니다. 그러나 그것은 블럭을 복사하는 것입니다 : 그것을 힙으로 옮겨서 수명을 연장하십시오. – CodaFi

+0

좋은 지적. 그러나'-retainArguments'는 또한 C 문자열을 복사합니다. 그리고 C 문자열을 복사하면 인수가 변경됩니다. – user102008

+0

@CodaFi 내 요점은'block! = [block copy]'입니다. 복사하면 문제가 발생할 수 있습니다. –

4

확실히 (필자가 직접 테스트하지는 않았지만). documentation에 따르면

retainArguments

수신기가 아직 수행하지 않은 경우, 대상 및 수신기와 복사합니다 C-문자열 인수 및 모든 블록을 모든 객체의 인수를 유지합니다.

  • (공극) retainArguments

이 메소드가 호출되기 전에 논의

는 NO를 리턴 argumentsRetained; 이후, YES를 리턴합니다.

효율적으로 새로 만든 NSInvocation 개체는 인수를 그대로 유지하거나 대상을 유지하거나 C 문자열을 복사하거나 관련된 블록을 복사하지 않습니다. 이 호출되기 전에 인수가 해제 될 수 있으므로 NSInvocation 개체에 캐시 할 예정이라면 인수를 유지하도록 지시해야합니다 ( ). NSTimer 객체는 타이머가 시작되기 전에 보통 지연이 있기 때문에 항상 에 대한 호출을 유도합니다.

+0

흥미 롭습니다. 설명서가 변경되었습니다. https://web.archive.org/web/20120826185131/http://developer.apple.com/library/ios/documentation/Cocoa/Reference/Foundation/Classes/NSInvocation_Class/Reference/Reference.html # // apple_ref/occ/instm/NSInvocation/retainArguments 그러나 비헤이비어가 변경된 경우와 변경 시점을 문서화하지 않습니다. iOS 6에서 1 년 전에 시도했을 때 블록은'retainArguments'에 의해 확실히 복사되지 않았습니다. – user102008

+1

방금 ​​테스트했는데 iOS 7에서는 복사되었지만 iOS 6.1에서는 복사되지 않으므로 변경되었습니다. – user102008

+0

변경 사항을 ios 7 업데이트로 문서화해야합니다. 항상 그런 식으로 보일 수 있습니다 ... 바보 같은 Apple, 트릭은 아이들을위한 것입니다! –