Bagaimana saya bisa meneruskan Block
ke Function
/ Method
?
Saya mencoba - (void)someFunc:(__Block)someBlock
tanpa hasil.
yaitu. Apa jenis untuk Block
?
Bagaimana saya bisa meneruskan Block
ke Function
/ Method
?
Saya mencoba - (void)someFunc:(__Block)someBlock
tanpa hasil.
yaitu. Apa jenis untuk Block
?
Jawaban:
Jenis blok bervariasi tergantung pada argumen dan jenis kembalinya. Dalam kasus umum, tipe blok dideklarasikan dengan cara yang sama dengan tipe pointer fungsi, tetapi mengganti *
dengan a ^
. Salah satu cara untuk meneruskan blok ke metode adalah sebagai berikut:
- (void)iterateWidgets:(void (^)(id, int))iteratorBlock;
Tapi seperti yang Anda lihat, itu berantakan. Anda bisa menggunakan a typedef
untuk membuat pembersih jenis blok:
typedef void (^ IteratorBlock)(id, int);
Dan kemudian meneruskan blok itu ke metode seperti:
- (void)iterateWidgets:(IteratorBlock)iteratorBlock;
NSNumber *
atau std::string&
atau apa pun yang Anda bisa berikan sebagai argumen fungsi. Ini hanya sebuah contoh. (Untuk blok yang setara kecuali untuk diganti id
dengan NSNumber
, typedef
akan menjadi typedef void (^ IteratorWithNumberBlock)(NSNumber *, int);
.)
NS_NOESCAPE
, tetapi enumerateObjectsUsingBlock
saya diberi tahu tidak melarikan diri, namun saya tidak melihat NS_NOESCAPE
di mana pun di situs, juga tidak melarikan diri disebutkan sama sekali dalam dokumen Apple. Bisakah kamu menolong?
Penjelasan termudah untuk pertanyaan ini adalah ikuti templat ini:
1. Blok sebagai parameter metode
Templat
- (void)aMethodWithBlock:(returnType (^)(parameters))blockName {
// your code
}
Contoh
-(void) saveWithCompletionBlock: (void (^)(NSArray *elements, NSError *error))completionBlock{
// your code
}
Penggunaan kasus lainnya:
2. Blokir sebagai Properti
Templat
@property (nonatomic, copy) returnType (^blockName)(parameters);
Contoh
@property (nonatomic,copy)void (^completionBlock)(NSArray *array, NSError *error);
3. Blokir sebagai argumen metode
Templat
[anObject aMethodWithBlock: ^returnType (parameters) {
// your code
}];
Contoh
[self saveWithCompletionBlock:^(NSArray *array, NSError *error) {
// your code
}];
4. Blokir sebagai variabel lokal
Templat
returnType (^blockName)(parameters) = ^returnType(parameters) {
// your code
};
Contoh
void (^completionBlock) (NSArray *array, NSError *error) = ^void(NSArray *array, NSError *error){
// your code
};
5. Blokir sebagai typedef
Templat
typedef returnType (^typeName)(parameters);
typeName blockName = ^(parameters) {
// your code
}
Contoh
typedef void(^completionBlock)(NSArray *array, NSError *error);
completionBlock didComplete = ^(NSArray *array, NSError *error){
// your code
};
Anda dapat melakukannya seperti ini, melewati blok sebagai parameter blok:
//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);
Satu lagi cara untuk melewatkan blok menggunakan fungsi с pada contoh di bawah ini. Saya sudah membuat fungsi untuk melakukan apa saja di latar belakang dan antrian utama.
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);
}
Dari impor blok. H bila perlu dan aktifkan:
- (void)loadInBackground {
performInBackground(^{
NSLog(@"Loading something in background");
//loading code
performOnMainQueue(^{
//completion hadler code on main queue
});
});
}
Anda juga dapat mengatur blok sebagai properti sederhana jika itu berlaku untuk Anda:
@property (nonatomic, copy) void (^didFinishEditingHandler)(float rating, NSString *reviewString);
pastikan bahwa properti blok adalah "salin"!
dan tentu saja Anda juga dapat menggunakan typedef:
typedef void (^SimpleBlock)(id);
@property (nonatomic, copy) SimpleBlock someActionHandler;
Anda juga memanggil atau memanggil blok menggunakan sintaks fungsi c biasa
-(void)iterateWidgets:(IteratorBlock)iteratorBlock{
iteratorBlock(someId, someInt);
}
Info lebih lanjut tentang blok di sini
Saya selalu cenderung lupa tentang sintaks blok. Ini selalu muncul di pikiran saya ketika saya harus mendeklarasikan blok. Saya harap ini membantu seseorang :)
Saya menulis sebuahlockBlock untuk kelas yang akan mengembalikan nilai-nilai dadu setelah mereka diguncang:
Tentukan typedef dengan returnType ( deklarasi di .h
atas @interface
)
typedef void (^CompleteDiceRolling)(NSInteger diceValue);
Tentukan a @property
untuk blok ( .h
)
@property (copy, nonatomic) CompleteDiceRolling completeDiceRolling;
Tetapkan metode dengan finishBlock
( .h
)
- (void)getDiceValueAfterSpin:(void (^)(NSInteger diceValue))finishBlock;
Masukkan metode yang didefinisikan sebelumnya dalam .m
file dan komit finishBlock
untuk @property
didefinisikan sebelumnya
- (void)getDiceValueAfterSpin:(void (^)(NSInteger diceValue))finishBlock{
self.completeDiceRolling = finishBlock;
}
Untuk memicu completionBlock
lulus Variabel jenis yang telah ditentukan sebelumnya (Jangan lupa untuk memeriksa apakah completionBlock
ada)
if( self.completeDiceRolling ){
self.completeDiceRolling(self.dieValue);
}
Terlepas dari jawaban yang diberikan pada utas ini, saya benar-benar berjuang untuk menulis suatu fungsi yang akan mengambil Blok sebagai fungsi - dan dengan parameter. Akhirnya, inilah solusi yang saya buat.
Saya ingin menulis fungsi umum loadJSONthread
, yang akan mengambil URL Layanan Web JSON, memuat beberapa data JSON dari URL ini di utas latar belakang, lalu mengembalikan hasil NSArray * kembali ke fungsi pemanggilan.
Pada dasarnya, saya ingin menyembunyikan semua kompleksitas background-thread dalam fungsi generik yang dapat digunakan kembali.
Inilah cara saya memanggil fungsi ini:
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)
}
} ];
... dan ini adalah bagian yang saya perjuangkan: cara mendeklarasikannya, dan cara membuatnya memanggil fungsi Blok begitu data dimuat, dan meneruskan Block
NSArray * dari catatan yang dimuat:
+(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);
});
});
}
Pertanyaan StackOverflow ini menyangkut cara memanggil fungsi, melewati Blok sebagai parameter, jadi saya menyederhanakan kode di atas, dan tidak termasuk loadJSONDataFromURL
fungsi.
Tetapi, jika Anda tertarik, Anda dapat menemukan salinan fungsi pemuatan JSON ini di blog ini: http://mikesknowledgebase.azurewebsites.net/pages/Services/WebServices-Page6.htm
Semoga ini bisa membantu beberapa pengembang XCode lainnya! (Jangan lupa memilih pertanyaan ini dan jawaban saya, jika ya!)
Templat lengkapnya terlihat seperti
- (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 {
}