Sto tentando di passare argomenti del blocco a NSInvocation
, ma l'app si arresta in modo anomalo. L'invocazione effettua una richiesta di rete e chiama i blocchi di esito positivo o negativo. Penso che il problema è che i blocchi sono deallocati prima che la richiesta di rete finisca. Sono riuscito a farlo funzionare con alcuni hackery Block_copy
e non segnala alcuna perdita utilizzando strumenti.NSInvocazione con argomenti del blocco
Domande: - È possibile che la perdita ci sia anche se l'analizzatore statico o gli strumenti non lo segnalano? - Esiste un modo migliore per "mantenere" il blocco?
// Create the NSInvocation
NSMethodSignature *methodSignature = [target methodSignatureForSelector:selector];
NSInvocation* invoc = [NSInvocation invocationWithMethodSignature:methodSignature];
[invoc setTarget:target];
[invoc setSelector:selector];
// Create success and error blocks.
void (^successBlock)(id successResponse) = ^(id successResponse) {
// Some success code here ...
};
void (^errorBlock)(NSError *error) = ^(NSError *error) {
// Some failure code here ...
};
/*
Without the two Block_copy lines, the block gets dealloced too soon
and the app crashes with EXC_BAD_ACCESS
I tried [successBlock copy] and [failureBlock copy] instead,
but the app still crashes.
It seems like Block_copy is the only way to move the block to the heap in this case.
*/
Block_copy((__bridge void *)successBlock);
Block_copy((__bridge void *)errorBlock);
// Set the success and failure blocks.
[invoc setArgument:&successBlock atIndex:2];
[invoc setArgument:&errorBlock atIndex:3];
[invoc retainArguments]; // does not retain blocks
// Invoke the method.
[invoc invoke];
Aggiornamento: Ho aggiornato il codice di seguito. I blocchi sono NSMallocBlocks
, ma l'app si arresta ancora in modo anomalo.
// Create success and error blocks.
int i = 0;
void (^successBlock)(id successResponse) = ^(id successResponse) {
NSLog(@"i = %i", i);
// Some success code here ...
};
void (^errorBlock)(NSError *error) = ^(NSError *error) {
NSLog(@"i = %i", i);
// Some failure code here ...
};
/*** Both blocks are NSMallocBlocks here ***/
// Set the success and failure blocks.
void (^successBlockCopy)(id successResponse) = [successBlock copy];
void (^errorBlockCopy)(NSError *error) = [errorBlock copy];
/*** Both blocks are still NSMallocBlocks here - I think copy is a NoOp ***/
// Set the success and failure blocks.
[invoc setArgument:&successBlockCopy atIndex:2];
[invoc setArgument:&errorBlockCopy atIndex:3];
[invoc retainArguments]; // does not retain blocks
// Invoke the method.
[invoc invoke];
I blocchi vengono passate nella catena come segue:
NSInvocation
→ NSProxy
(NSInvocation
usando forwardInvocation:
) → method1
→ methodN
methodN
casualmente invita il blocco successo o il fallimento seconda del HTTP risposta.
Devo copiare il blocco in ogni fase? L'esempio precedente parlava del primo NSInvocation
. Ho anche bisogno di [invocation retainArguments];
ad ogni passo appropriato? Sto usando ARC.
Ho provato successBlock = [cop del successo y]; e errorBlock = [copia errorBlock]; ma ottengo lo stesso crash con questo errore: l'indirizzo non contiene una sezione che punta a una sezione in un file oggetto . Come ho già detto, l'aggiunta delle righe Block_copy come indicato impedisce l'arresto anomalo, ma non sono sicuro che perdano memoria. – pshah
Le 'Block_copy' che si usano attualmente non hanno alcun effetto documentato. Tutto quello che state vedendo è che i risultati indefiniti causati dal 'invoke problematico 'hanno un effetto indefinito diverso. Non è una soluzione reale. E anche gli zombi non ti aiuteranno a eseguire il debug qui, dal momento che non possono mantenere artificialmente in pila gli oggetti dello stack - una volta che lo stack si ingrandisce, li sovrascriverà. – Tommy
Ho avuto l'impressione che chiamare Block_copy imponga che il blocco venga salvato nell'heap anziché nello stack. E, ancora non riesco a capire perché passare in [copia di successoBlock] invece di successBlock all'invocazione non funziona. – pshah