Mi piacerebbe chiamare ricorsivamente un blocco da se stesso. In un oggetto obj-c, usiamo "self", c'è qualcosa di simile a fare riferimento a un'istanza di blocco dal suo interno?Esiste un puntatore SELF per i blocchi?
risposta
Una storia divertente! I blocchi sono in realtà oggetti Objective-C. Detto questo, non ci sono API esposte per ottenere il puntatore dei blocchi self
.
Tuttavia, se si dichiarano blocchi prima di utilizzarli, è possibile utilizzarli in modo ricorsivo. In un ambiente non-garbage collection, si dovrebbe fare qualcosa di simile:
__weak __block int (^block_self)(int);
int (^fibonacci)(int) = [^(int n) {
if (n < 2) { return 1; }
return block_self(n - 1) + block_self(n - 2);
} copy];
block_self = fibonacci;
È necessaria per applicare il modificatore __block
-block_self
, perché altrimenti, il riferimento block_self
all'interno fibonacci
rimanda alla prima che viene assegnato (arresto anomalo del programma alla prima chiamata ricorsiva). Lo __weak
garantisce che il blocco non rilevi un riferimento forte a se stesso, il che causerebbe una perdita di memoria.
si deve dichiarare la variabile blocco come __block
:
typedef void (^MyBlock)(id);
__block MyBlock block = ^(id param) {
NSLog(@"%@", param);
block(param);
};
@Joe Blow ['__block' specificamente è una parola chiave] (http://developer.apple.com/library/ios/documentation/cocoa/Conceptual/Blocks/Articles/bxVariables.html#// apple_ref/doc/uid/TP40007502-CH6-SW6). –
Questo codice si diffonderà anche per lo stesso motivo del codice zneak. – Karl
Il seguente codice di blocco ricorsivo verrà compilare ed eseguire con ARC, GC, o la gestione manuale della memoria, senza andare in crash, che perde, o l'emissione di avvisi (analizzatore o normale):
typedef void (^CountdownBlock)(int currentValue);
- (CountdownBlock) makeRecursiveBlock
{
CountdownBlock aBlock;
__block __unsafe_unretained CountdownBlock aBlock_recursive;
aBlock_recursive = aBlock = [^(int currentValue)
{
if(currentValue >= 0)
{
NSLog(@"Current value = %d", currentValue);
aBlock_recursive(currentValue-1);
}
} copy];
#if !__has_feature(objc_arc)
[aBlock autorelease];
#endif
return aBlock;
}
- (void) callRecursiveBlock
{
CountdownBlock aBlock = [self makeRecursiveBlock];
// You don't need to dispatch; I'm doing this to demonstrate
// calling from beyond the current autorelease pool.
dispatch_async(dispatch_get_main_queue(),^
{
aBlock(10);
});
}
considerazioni importanti:
- È deve copiare il blocco sull'heap manualmente altrimenti tenterà di accedere a uno stack inesistente quando lo chiamate da un altro contesto (ARC lo fa di solito per te, ma non in tutti i casi. Meglio giocare sul sicuro).
- Sono necessari due riferimenti: uno per mantenere il riferimento forte al blocco e uno per contenere un riferimento debole per il blocco ricorsivo da chiamare (tecnicamente, questo è necessario solo per ARC).
- È necessario utilizzare il qualificatore __block in modo che il blocco non acquisisca il valore non ancora assegnato del riferimento del blocco.
- Se si esegue la gestione manuale della memoria, è necessario autorizzare automaticamente il blocco copiato.
Questo non funzionerebbe in ARC, ma per quanto riguarda la funzione "copia" autorelease] "' "invece di copiare, in modo da non dover chiamare il rilascio all'interno del blocco? Per ARC forse stai facendo '' 'aBlock = nil''' dopo aver chiamato' '' aBlock (10); '' '? –
In realtà, dopo aver rivisitato questa soluzione, risulta che mantenere il riferimento all'interno del blocco causerebbe una perdita se il blocco non veniva richiamato. Ora ho aggiornato la risposta in modo che funzioni correttamente se la chiami o meno. – Karl
Ho un problema che aggiunge un livello di complessità a questo, ma non sono del tutto sicuro che il mio problema sia risolvibile. Mi piacerebbe essere in grado di riprovare le chiamate API tramite AFNetworking. Penso che questo pastebin semplifica e illustra il problema. http://pastebin.com/xRPJuckZ Il blocco ricorsivo unsafe_unretained viene chiamato dall'interno di un altro blocco dentro di sé, e chiamandolo lì porta a un'eccezione di accesso errata. Avresti qualche idea di come risolvere questo? –
Non c'è ancora self
per blocchi. È possibile costruire uno come questo (supponendo ARC):
__block void (__weak ^blockSelf)(void);
void (^block)(void) = [^{
// Use blockSelf here
} copy];
blockSelf = block;
// Use block here
Il __block
è necessario in modo che possiamo impostare blockSelf
al blocco dopo aver creato il blocco. Il __weak
è necessario perché altrimenti il blocco avrebbe un forte riferimento a se stesso, il che causerebbe un forte ciclo di riferimento e quindi una perdita di memoria. È necessario lo copy
per assicurarsi che il blocco venga copiato nell'heap. Questo potrebbe non essere necessario con le versioni più recenti del compilatore, ma non farà alcun danno.
- 1. blocchi, self, conserva cicli
- 2. Memorizza puntatore debole a self
- 3. Esiste un modo elegante per elaborare un flusso in blocchi?
- 4. Esiste un uso pratico per un puntatore `volatile restrict`?
- 5. Blocchi oggettivi C: esiste un modo per evitare che il "sé" venga mantenuto?
- 6. Un modo semplice per assegnare i valori del puntatore int?
- 7. Il puntatore statico è un puntatore forte?
- 8. C'è un modo per rilevare i blocchi Flash?
- 9. C'è un modo per passare i metodi come blocchi?
- 10. Uso Delphi Self-Pointer
- 11. È possibile taggare i blocchi?
- 12. I blocchi C++ {} hanno un impatto negativo
- 13. iOS Tipo di puntatore a blocchi incompatibile problema
- 14. Esiste un costrutto come Java che inizializza i blocchi in C++?
- 15. puntatore al puntatore rispetto a un puntatore
- 16. Quali sono i motivi per lanciare un puntatore void?
- 17. Orgmode: come filtrare i blocchi per essere groviglio?
- 18. Può esserci un puntatore a un puntatore a un puntatore?
- 19. Esiste un contenitore stl per i dati del modello gerarchico?
- 20. PHPUnit - Usa $ this o self per i metodi statici?
- 21. In Python, "return self" restituisce una copia dell'oggetto o un puntatore?
- 22. - [NSinvocation retainArguments] copia i blocchi?
- 23. Come ottengo il valore int da object_getIvar (self, myIntVar) poiché restituisce un puntatore
- 24. I blocchi estratti in HyperLedger?
- 25. La migliore tecnica per sostituire i metodi delegati con i blocchi
- 26. Cercando di capire i blocchi su iOS
- 27. Come si recuperano i blocchi azzerati di un file sparse?
- 28. Esiste un metodo per disattivare i gesti per Windows8
- 29. SQL self documenting
- 30. Esiste un metodo convenzionale per invertire i valori NSColor?
Ottima risposta. il modificatore __block mi avrebbe richiesto un po 'per capire da solo. Grazie mille! Rep per te! –
Se lo passi a una funzione che finirà per copiarlo (come ad esempio 'dispatch_async()'), dovrai anche copiare il blocco nell'ambito del compito. –
Questo codice perde, anche se si dispone di una condizione di terminazione. Aggiungi una variabile per il conto alla rovescia ed eseguila attraverso il correttore di perdite di Strumenti per vedere.Inoltre, il compilatore emetterà il seguente avvertimento se hai attivato gli avvisi giusti: "Catturare 'myBlock' in questo blocco è probabile che porti a un ciclo di conservazione" – Karl