2013-04-18 17 views
7

Il metodo -retainArguments è utile quando non si esegue immediatamente NSInvocation, ma lo si fa in un secondo momento; mantiene gli argomenti dell'oggetto in modo che rimangano validi durante questo periodo.- [NSinvocation retainArguments] copia i blocchi?

Come tutti sappiamo, gli argomenti di blocco devono essere copiati anziché conservati. La mia domanda è: è possibile copiare -retainArguments invece di mantenere un argomento quando è di tipo blocco? La documentazione non indica che lo faccia, ma sembra una cosa facile e ragionevole da fare.

Update: Il comportamento sembra essere cambiato in iOS 7. Ho appena provato questo, e in iOS 6.1 e prima, -retainArguments non averlo copiato parametri del tipo di blocco. In iOS 7 e versioni successive, -retainArguments copia i parametri del tipo di blocco. La documentazione di -retainArguments è stata aggiornata per dire che copia i blocchi, ma non dice quando il comportamento è cambiato (il che è molto pericoloso per le persone che supportano i vecchi SO).

+0

Grazie per il mantenimento di questo aggiornamento! – matt

risposta

1

No.

immagine, se la risposta è sì, dove NSInvocation è abbastanza intelligente da copiare blocco, dovrebbe fare qualcosa di simile:

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]; 
     } 
    } 
} 

il problema è che arg viene modificato durante la copia del blocco, che non dovrebbe accadere perché questo significa chiamare retainArguments può cambiare gli argomenti nel NSInvocation. questo interromperà molte ipotesi già fatte. (Cioè argomenti ricevono da NSInvocation dovrebbe essere lo stesso come argomenti usati per creare il NSInvocation) Aggiornamento


appena fatto il test di conformarsi la risposta è NO, ma il mio punto precedente era non corretta anche se ...

@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 

uscita, ARC disabilitato (e si è schiantato):

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 abilitato:

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__ 

come si può vedere, c stringa vengono copiati da retainArguments ma non blocca. ma con ARC abilitato, il problema dovrebbe andare via perché ARC lo ha copiato per te a un certo punto.

+0

La copia di un blocco non cambia a cosa interessa il sistema di tipi, la firma del blocco. Certo, può andare da un "__NSStackBlock__' a un' __NSHeapBlock__', ma questo è il punto di copiare un blocco: spostarlo nell'heap per estenderne la durata. – CodaFi

+0

Buon punto. Tuttavia, '-retainArguments' copia anche le stringhe C. E copiare stringhe C cambia anche gli argomenti. – user102008

+0

@CodaFi il mio punto è 'block! = [Block copy]' quindi può causare problemi se viene copiato –

4

Si suppone certamente (anche se non l'ho provato personalmente). Secondo il documentation:

retainArguments

Se il ricevitore non vi abbia già provveduto, conserva la bersaglio e tutti gli argomenti oggetto del ricevitore e copia tutti i suoi argomenti C-string e blocchi.

  • (nulli) retainArguments

discussione

Prima di questo metodo viene richiamato, ritorna argumentsRetained NO; dopo, restituisce SÌ.

Per l'efficienza, gli oggetti appena creati NSInvocation non mantengono o copiare le loro argomentazioni e non se ne conservano i loro obiettivi, Copia C stringhe, o copiare qualsiasi blocchi associati. È necessario istruire un oggetto NSInvocation per mantenere i suoi argomenti se si intende inserirlo nella cache, perché gli argomenti potrebbero altrimenti essere rilasciati prima che venga invocata la chiamata . Gli oggetti NSTimer indicano sempre che le loro invocazioni su mantengono i loro argomenti, ad esempio, perché di solito c'è un ritardo prima che un timer scoppi.

+0

Interessante. La documentazione è cambiata: 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 Ma non documenta se e quando il comportamento è cambiato. I blocchi non sono stati sicuramente copiati da 'retainArguments' quando l'ho provato su iOS 6 un anno fa. – user102008

+1

L'ho appena testato e viene copiato in iOS 7 ma non in iOS 6.1, quindi è cambiato. – user102008

+0

Avrebbero dovuto documentare la modifica come un aggiornamento iOS 7 invece di far sembrare che fosse sempre stato così ... sciocco Apple, i trucchi sono per bambini! –

Problemi correlati