Come posso passare Blocka a Function/ Method?
Ho provato - (void)someFunc:(__Block)someBlocksenza alcun risultato.
vale a dire. Qual è il tipo per a Block?
Come posso passare Blocka a Function/ Method?
Ho provato - (void)someFunc:(__Block)someBlocksenza alcun risultato.
vale a dire. Qual è il tipo per a Block?
Risposte:
Il tipo di un blocco varia a seconda dei suoi argomenti e del suo tipo restituito. Nel caso generale, i tipi di blocco vengono dichiarati allo stesso modo dei tipi di puntatore a funzione, ma sostituendo *con a ^. Un modo per passare un blocco a un metodo è il seguente:
- (void)iterateWidgets:(void (^)(id, int))iteratorBlock;
Ma come puoi vedere, è disordinato. Puoi invece usare a typedefper rendere più puliti i tipi di blocco:
typedef void (^ IteratorBlock)(id, int);
E poi passa quel blocco a un metodo come questo:
- (void)iterateWidgets:(IteratorBlock)iteratorBlock;
NSNumber *o std::string&o qualsiasi altra cosa che potresti passare come argomento di funzione. Questo è solo un esempio. (Per un blocco che è equivalente, se non per la sostituzione idcon NSNumberla typedefsarebbe typedef void (^ IteratorWithNumberBlock)(NSNumber *, int);.)
NS_NOESCAPE, ma enumerateObjectsUsingBlockmi è stato detto che non è in fuga, ma non vedo da NS_NOESCAPEnessuna parte nel sito, né la fuga è menzionata affatto nei documenti di Apple. Puoi aiutare?
La spiegazione più semplice per questa domanda è seguire questi modelli:
1. Blocco come parametro del metodo
Modello
- (void)aMethodWithBlock:(returnType (^)(parameters))blockName {
// your code
}
Esempio
-(void) saveWithCompletionBlock: (void (^)(NSArray *elements, NSError *error))completionBlock{
// your code
}
Altro uso di casi:
2. Blocco come proprietà
Modello
@property (nonatomic, copy) returnType (^blockName)(parameters);
Esempio
@property (nonatomic,copy)void (^completionBlock)(NSArray *array, NSError *error);
3. Blocco come argomento del metodo
Modello
[anObject aMethodWithBlock: ^returnType (parameters) {
// your code
}];
Esempio
[self saveWithCompletionBlock:^(NSArray *array, NSError *error) {
// your code
}];
4. Blocco come variabile locale
Modello
returnType (^blockName)(parameters) = ^returnType(parameters) {
// your code
};
Esempio
void (^completionBlock) (NSArray *array, NSError *error) = ^void(NSArray *array, NSError *error){
// your code
};
5. Blocca come dattiloscritto
Modello
typedef returnType (^typeName)(parameters);
typeName blockName = ^(parameters) {
// your code
}
Esempio
typedef void(^completionBlock)(NSArray *array, NSError *error);
completionBlock didComplete = ^(NSArray *array, NSError *error){
// your code
};
Puoi fare così, passando il blocco come parametro di blocco:
//creating a block named "completion" that will take no arguments and will return void
void(^completion)() = ^() {
NSLog(@"bbb");
};
//creating a block namd "block" that will take a block as argument and will return void
void(^block)(void(^completion)()) = ^(void(^completion)()) {
NSLog(@"aaa");
completion();
};
//invoking block "block" with block "completion" as argument
block(completion);
Un altro modo per passare il blocco utilizzando le funzioni с nell'esempio seguente. Ho creato funzioni per eseguire qualsiasi cosa in background e nella coda principale.
file blocks.h
void performInBackground(void(^block)(void));
void performOnMainQueue(void(^block)(void));
file blocks.m
#import "blocks.h"
void performInBackground(void(^block)(void)) {
if (nil == block) {
return;
}
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), block);
}
void performOnMainQueue(void(^block)(void)) {
if (nil == block) {
return;
}
dispatch_async(dispatch_get_main_queue(), block);
}
Quindi importare blocks.h quando necessario e invocarlo:
- (void)loadInBackground {
performInBackground(^{
NSLog(@"Loading something in background");
//loading code
performOnMainQueue(^{
//completion hadler code on main queue
});
});
}
Puoi anche impostare il blocco come proprietà semplice se è applicabile per te:
@property (nonatomic, copy) void (^didFinishEditingHandler)(float rating, NSString *reviewString);
assicurarsi che la proprietà del blocco sia "copia"!
e ovviamente puoi anche usare typedef:
typedef void (^SimpleBlock)(id);
@property (nonatomic, copy) SimpleBlock someActionHandler;
Inoltre invochi o chiami un blocco usando la solita sintassi della funzione c
-(void)iterateWidgets:(IteratorBlock)iteratorBlock{
iteratorBlock(someId, someInt);
}
Maggiori informazioni sui blocchi qui
Tendo sempre a dimenticare la sintassi dei blocchi. Mi viene sempre in mente quando devo dichiarare un blocco. Spero che aiuti qualcuno :)
Ho scritto un completamento Block per una classe che restituirà i valori dei dadi dopo che sono stati scossi:
Definire typedef con returnType ( .hsopra la @interfacedichiarazione)
typedef void (^CompleteDiceRolling)(NSInteger diceValue);Definisci a @propertyper il blocco ( .h)
@property (copy, nonatomic) CompleteDiceRolling completeDiceRolling;Definire un metodo con finishBlock ( .h)
- (void)getDiceValueAfterSpin:(void (^)(NSInteger diceValue))finishBlock;Inserisci il metodo precedentemente definito in .m file e confermare finishBlockcon @propertydefinito in precedenza
- (void)getDiceValueAfterSpin:(void (^)(NSInteger diceValue))finishBlock{
self.completeDiceRolling = finishBlock;
}Per innescare completionBlockpassa la variabile predefinitaType ad esso (non dimenticare di verificare se completionBlockesiste)
if( self.completeDiceRolling ){
self.completeDiceRolling(self.dieValue);
}Nonostante le risposte fornite su questo thread, ho davvero avuto difficoltà a scrivere una funzione che avrebbe preso un blocco come funzione - e con un parametro. Alla fine, ecco la soluzione che mi è venuta in mente.
Volevo scrivere una funzione generica loadJSONthread, che prenderebbe l'URL di un servizio Web JSON, caricare alcuni dati JSON da questo URL su un thread in background, quindi restituire un NSArray * di risultati alla funzione chiamante.
Fondamentalmente, volevo tenere nascosta tutta la complessità del thread in background in una generica funzione riutilizzabile.
Ecco come chiamerei questa funzione:
NSString* WebServiceURL = @"http://www.inorthwind.com/Service1.svc/getAllCustomers";
[JSONHelper loadJSONthread:WebServiceURL onLoadedData:^(NSArray *results) {
// Finished loading the JSON data
NSLog(@"Loaded %lu rows.", (unsigned long)results.count);
// Iterate through our array of Company records, and create/update the records in our SQLite database
for (NSDictionary *oneCompany in results)
{
// Do something with this Company record (eg store it in our SQLite database)
}
} ];
... e questo è il bit con cui ho lottato: come dichiararlo e come farlo chiamare la funzione Block una volta caricati i dati e passare Blockun NSArray * di record caricati:
+(void)loadJSONthread:(NSString*)urlString onLoadedData:(void (^)(NSArray*))onLoadedData
{
__block NSArray* results = nil;
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_async(queue, ^{
// Call an external function to load the JSON data
NSDictionary * dictionary = [JSONHelper loadJSONDataFromURL:urlString];
results = [dictionary objectForKey:@"Results"];
dispatch_async(dispatch_get_main_queue(), ^{
// This code gets run on the main thread when the JSON has loaded
onLoadedData(results);
});
});
}
Questa domanda StackOverflow riguarda come chiamare le funzioni, passando un blocco come parametro, quindi ho semplificato il codice sopra e non ho incluso la loadJSONDataFromURLfunzione.
Ma, se sei interessato, puoi trovare una copia di questa funzione di caricamento JSON su questo blog: http://mikesknowledgebase.azurewebsite.net/pages/Services/WebServices-Page6.htm
Spero che questo aiuti alcuni altri sviluppatori XCode! (Non dimenticare di votare questa domanda e la mia risposta, se lo fa!)
Sembra il modello completo
- (void) main {
//Call
[self someMethodWithSuccessBlock:^{[self successMethod];}
withFailureBlock:^(NSError * error) {[self failureMethod:error];}];
}
//Definition
- (void) someMethodWithSuccessBlock:(void (^) (void))successBlock
withFailureBlock:(void (^) (NSError*))failureBlock {
//Execute a block
successBlock();
// failureBlock([[NSError alloc]init]);
}
- (void) successMethod {
}
- (void) failureMethod:(NSError*) error {
}