19

Il tipo IMP in Objective-C rappresenta un puntatore a funzione, per quanto possibile da capire. C'è un modo per fare un IMP da un puntatore a blocco? Grazie per le tue ideeCreazione di un IMP da un blocco Objective-C

+1

Ho aggiunto un gruppo di tag; 'oggettivo-c-runtime' non è un tag molto comunemente usato e questa [molto interessante] domanda era fuori nelle erbacce. – bbum

+0

Grazie per quello, bbum! –

+0

tuttavia, qual è l'obiettivo di ottenere l'IMP da un blocco? – user102008

risposta

27

Dato che questo è stato scritto, ora ci sono API in iOS e Mac OS X che consentono di trasformare Blocks in IMP direttamente. Ho scritto uno weblog post descrivendo l'API (imp_implementationWithBlock()).


Un blocco è effettivamente una struttura che contiene un po 'di metadati, un riferimento al codice contenuto all'interno del blocco e una copia dei dati const-copiati catturati nel blocco.

Quindi, no, non c'è modo di mappare direttamente tra uno IMP e un riferimento di blocco.

Quando una chiamata a un blocco viene compilata, il compilatore emette un trampolino che imposta lo stack frame e quindi salta al codice eseguibile all'interno del blocco.

Quello che puoi fare, però, è creare un IMP che si comporta come quel trampolino. Per quanto segue, sarà necessario un IMP specifico per ciascun set di argomenti & i tipi di ritorno da chiamare. Se è necessario rendere questo generico, è necessario utilizzare l'assembly.

Per questo, sto impostando istanze di blocco univoche per istanza della classe. Se si desidera avere un blocco generico che agisca su tutte le istanze, creare un hash di SEL -> blocco per classe.

(1) Associare blocchi per agire come IMP utilizzando il meccanismo di riferimento associato. Qualcosa di simile:

void (^implementingBlock)(id s, SEL _c, int v) = ^(id s, SEL _c, int v) { 
    // do something here 
} 

objc_setAssociatedObject(obj, SELToImp, [implementingBlock copy])); 

(2) implementare un trampolino IMP qualcosa di simile:

void void_id_sel_intTramp(id self, SEL _cmd, int value) { 
    int (^block)(id s, SEL _c, int v) = objc_getAssociatedObject(self, _cmd); 
    block(self, _cmd, value); 
} 

(3) riempire il trampolino sopra per qualsiasi selettore tramite API del runtime Objective-C (vedere method_setImplementation e simili)

Avvertenze:

  • questo è stato digitato in StackOverflow. Il codice reale sarà simile, ma probabilmente leggermente diverso.

  • la [executionBlock copy] è critica; Blocchi iniziano la vita sullo stack (di solito)

+0

Soluzione davvero interessante, grazie mille! Ci proverò. Ho finito per usare un hash di blocchi mappati contro selettori, ma l'ho memorizzato in una variabile di istanza 'NSMutableDictionary'. Non ho mai pensato di usare 'objc_setAssociatedObject', però. È geniale. –

+0

A proposito, pensi di poter elaborare l'intera faccenda dell'assemblaggio? Sono affascinato da questo, ma davvero non capisco molto bene come funzioni. –

+0

In iOS 4.3 e Mac OS X 10.7, c'è imp_implementationWithBlock(), [ma penso che tu lo sapessi già] (http://www.friday.com/bbum/2011/03/17/ios-4-3-imp_implementationwithblock /). – lemnar

10

Credo Mike Ash, con qualche aiuto da Landon Fuller, ha risolto questo per il caso generale, tra cui iOS, che è più difficile. Ha una classe su github che trasformerà un blocco in un puntatore a funzione.

Si potrebbe anche voler conferire il announcement e qualche interessante discussione di follow-up sul cacao-non legato.

AGGIORNAMENTO: E ora c'è imp_implementationWithBlock() come indicato sopra.

Problemi correlati