2010-04-17 6 views
19

Sto cercando di capire i blocchi. Ottengo come usarli normalmente, quando passati direttamente a un metodo. Mi interessa ora prendere un blocco, memorizzarlo (diciamo) in una variabile di istanza e chiamarlo in seguito.Copia di blocchi (es .: copiandoli in variabili di istanza) in Objective-C

La guida alla programmazione dei blocchi fa sembrare che possa farlo, utilizzando Block_copy/retain per copiare il blocco, ma quando provo a eseguirlo, il programma si blocca.

- (void) setupStoredBlock 
{ 
    int salt = 42; 
    m_storedBlock = ^(int incoming){ return 2 + incoming + salt; }; 
    [m_storedBlock retain]; 
} 

provo a chiamare in un secondo momento:

- (void) runStoredBlock 
{ 
    int outputValue = m_storedBlock(5); 
    NSLog(@"When we ran our stored blockwe got back: %d", outputValue); 
    [m_storedBlock release]; 
} 

Qualcuno ha qualche intuizioni? (Oppure, c'è qualcosa che non sto ottenendo con i blocchi?)

Grazie mille!

+0

ho potuto riprodurre questo in un'applicazione di test: https://bitbucket.org/boredzo/block-retention-test/ –

risposta

30

Avrai voglia di fare questo, invece:

- (void) setupStoredBlock 
{ 
    int salt = 42; 
    m_storedBlock = Block_copy(^(int incoming){ return 2 + incoming + salt; }); 
} 
+0

Questo mi sembra un bug, sia in blocchi o nella documentazione. Argomenti di programmazione dei blocchi (http://developer.apple.com/mac/library/documentation/cocoa/Conceptual/Blocks/Articles/bxUsing.html#//apple_ref/doc/uid/TP40007502-CH5-SW2) dice 'retain' dovrebbe funzionare. Nei miei test, il mantenimento di un blocco si comportava normalmente (ovvero non restituisce una copia), ma quando si assegna il blocco a una variabile di istanza, chiamandolo da un messaggio successivo si blocca come descritto nella domanda. La modifica della conservazione in una copia (utilizzando 'copia' o' Block_copy') corregge l'arresto anomalo. –

+8

Ah. Nessun bug Ecco bbum sul suo blog: "Per un blocco che non è stato copiato, -retain non ha senso. Non fa nulla. Avrebbe potuto essere implementato per restituire una copia del blocco, ma sarebbe stata una biforcazione del contratto -retain oltre accettabile. "Http://www.friday.com/bbum/2009/08/29/blocks-tips -tricks/Quindi, sì, è necessario copiarlo-'retain' non funzionerà qui. –

+0

@Peter si, è una configurazione interessante. Vorrei che '-retain' avesse la stessa semantica con i blocchi a cui siamo abituati con gli oggetti, ma ci sono occasionali trucchi, come questo. :( –

6

copiare un blocco quando si desidera che rimanga in giro. Autorelease o rilasciarlo quando hai finito con esso. Conservalo se hai bisogno di un lungo cammino per scrivere lo /* NOP */.

@interface Foo : FooSuper {} 
@property(copy) int (^storedBlock)(int); 
@end 

@implementation Foo 
@synthesize storedBlock = mStoredBlock; 

- (void)setupStoredBlock { 
    self.storedBlock = ^{/*...*/}; 
    // or: mStoredBlock = [^{/*...*/} copy]; 
    // but this simple implementation violates the atomicity contract 
} 

- (void)runStoredBlock { 
    int result = self.storedBlock(5); 
    NSLog(@"%s: result = %d", __func__, result); 
} 
@end 
+2

retain è solo no-op su blocchi stack Per i blocchi heap, mantengono il valore – user102008

4

C'è stata una presentazione molto bella su questo argomento sul recente WWDC (2010). Ha descritto come sono stati implementati i blocchi e perché è necessario utilizzare Block_copy. È possibile scaricare un film dalla presentazione a: http://developer.apple.com/itunes/?destination=adc.apple.com.4092414566 Il film si chiama: "Advanced Objective-C e garbage collection"

+0

In realtà il video consiglia di utilizzare il metodo di copia, non Block_copy. Quote da circa 23:50: "Esistono anche funzioni C per copiare e cancellare blocchi (ad esempio Block_copy). C, puoi invece usare quelle funzioni C. Ma preferisci usare i metodi invece delle funzioni, specialmente se usi la garbage collection. " – DougW

5

• Come tutte le variabili locali, un blocco non statica esiste nello stack e sarà spuntato dallo stack, come qualsiasi altra variabile locale che non è stata dichiarata statica.

• Block_copy() copia il blocco dallo stack sull'heap, in cui sono presenti tutte le istanze di malloc. E come tutti i metodi new/copy, Block_copy() restituisce un oggetto allocato dell'heap con un conteggio dei ritardi di 1. Un blocco è un oggetto objectiveC ma non è conforme come un oggetto normale. Pertanto, non dovrebbe esserci differenza tra Block_Release() e il metodo di rilascio obiettivo.

• Questo esempio utilizza il metodo di copia di un'istanza di blocco. Perché assegnare il risultato di un Block_copy() a un ID richiede un cast di tipo che non voglio sbagliare. Il metodo di copia consente di assegnare direttamente la variabile di blocco a un ID.

- (void) setupStoredBlock 
{ 
    int zStackLocalVariable = 42; 
    iHeapAllocatedVariable = [^int(int aMore){ return zStackLocalVariable + aMore; } copy]; 
} 

• Per dichiarare un oggetto statico è quello di richiedere di essere fisicamente allocato con il codice stesso. Un blocco dichiarato statico impedisce al compilatore di accedere a variabili esterne al proprio ambito. A causa dei requisiti di una dichiarazione di blocco statico, suppongo che il blocco sullo stack sia in qualche modo diverso dal blocco che si trova nell'heap.

• Un blocco è un oggetto obiettivo c la cui classe il cui nome classe e altre informazioni associate non ho ancora tentato di recuperare, ma, come Protocollo, Oggetto e altre classi hiddenCove nascoste, non è conforme a NSObject. Come tutti gli oggetti objectiveC, tuttavia, deve essere conforme al mantenimento/rilascio. ARC estende anche le equivalenze di mantenimento/rilascio negli oggetti di Core Foundation, e probabilmente, se non ora, alla fine, in allocazioni malloc/free.

• Attendo la vera motivazione per un'esplorazione approfondita di mikeash.com, poiché a Apple piace tenerci tutti su un piano iper-teorico di scarso significato fisico, anche se tutto ciò che è significativo è fisico.

ARC and blocks also discussed here

+1

Nice answer r. Per quanto riguarda il punto 2, sarebbe esatto dire che un blocco è un oggetto Objective-C ma non è una sottoclasse 'NSObject'? Oppure, cosa intendi per "non conformarsi come un normale oggetto"? Inoltre, ho difficoltà a capire le diverse dimensioni fisiche, e la frase "i blocchi possono accedere solo ai propri parametri ..." non è chiara neanche per me. C'è un riferimento che posso guardare o puoi metterlo in un modo diverso? –

+0

"ma anche tutte le variabili di stack esterne al blocco utilizzate nel blocco stesso" No, le variabili esterne vengono copiate quando il blocco viene creato, non quando viene copiato. – newacct

Problemi correlati