2013-08-09 21 views
8

Sto lavorando con un'API basata su blocchi e sono incappato in uno scenario in cui stavo passando un parametro di blocco con una firma che non corrispondeva al parametro typedef'd il metodo si aspettava. Con mia sorpresa, il compilatore non sembrava preoccuparsi di questo, e l'app non si è bloccata. È questo comportamento previsto? Esempio:Passaggio del parametro di blocco che non corrisponde alla firma

typedef void(^MyBlock)(); 
typedef void(^MyBlockWithParam)(id param); 

- (void)doWork { 
    MyBlockWithParam block1 = ^(id param) { 
     NSLog(@"block1: %@", param); 
    }; 

    MyBlock block2 = ^{ 
     NSLog(@"block2"); 
    }; 

    [self loadData:block1]; 
    [self loadData:block2]; 
} 

- (void)loadData:(MyBlockWithParam)block { 
    block(@"foo"); 
} 
+3

Penso che se hai cambiato il primo a 'void (^ MyBlockType) (void)' avrai un reclamo. Il '()' vuoto indica argomenti non specificati, credo. – nielsbot

+0

Sì, questo ha costretto il compilatore a lamentarsi di ciò allora. Sai se questo è documentato dove (non l'ho visto se c'è)? Se vuoi pubblicare il tuo commento come risposta, lo accetto. Grazie – chinabuffet

+0

Non sono sicuro - ho ricevuto queste informazioni da un'altra risposta su un'altra domanda :) Lasciami guardare. – nielsbot

risposta

9

Fornendo una specifica argomenti vuoto come in

typedef void(^MyBlock)(); 

significa argomenti "non specificati" . Quindi i due tipi sono compatibili come scritti. La modifica della prima dichiarazione a

typedef void(^MyBlock)(void); 

specifica che il blocco non prende argomenti e si otterrà un errore.

K & R C specifica che un elenco di argomenti vuoto significa "non specificato". La specifica dei blocchi C indica che questo è non vero per le dichiarazioni del tipo di blocco (http://clang.llvm.org/docs/BlockLanguageSpec.html#block-variable-declarations) ma: sia GCC che Clang implementano il comportamento K & R come estensione della lingua.

3

Questa è una cosa di C. Un prototipo di funzione o di blocco con una lista di argomenti vuota significa "la funzione (o il blocco) accetta qualsiasi argomento che ti piace". Se si vuole trasmettere che il blocco dovrebbe avere nessun argomento, è necessario dirlo esplicitamente in modo simile a questo:

typedef void(^MyBlock)(void) 

Questo è in gran parte storica dai giorni prima ANSI quando non c'erano i prototipi di funzione e tutte le dichiarazioni di funzione (al contrario di definizioni) si presentava così:

some_type function(); 
4

Dalla specifica clang blocchi:

variadic ... argomenti sono supportati. [variadic.c] Un blocco che non accetta argomenti deve specificare void nell'elenco degli argomenti [voidarg.c]. Un elenco di parametri vuoto non rappresenta, come fornisce K & R, un elenco di argomenti non specificato. Nota: sia gcc che clang supportano lo stile K & R come comodità.

Fondamentalmente, si tratta di un'antica stranezza della sintassi C. In tempi antichi, la sintassi della dichiarazione della funzione C era piuttosto diversa e le parentesi vuote indicavano che la funzione poteva essere passata a un numero qualsiasi di argomenti. Per compatibilità con le versioni precedenti, i compilatori hanno generalmente consentito la sintassi della dichiarazione di funzione vecchio stile. E per qualche ragione, Apple ha deciso di rifiutare simultaneamente questa sintassi nello standard del blocco mentre in realtà permetteva di usarla con i blocchi sia in GCC che in Clang.

Quindi, per farla breve: Per dichiarare che un blocco non prende argomenti, è necessario digitare esplicitamente come void(^MyBlock)(void)

Problemi correlati