ฉันจะส่งผ่านBlock
ไปยัง a Function
/ ได้Method
อย่างไร
ฉันพยายาม- (void)someFunc:(__Block)someBlock
โดยไม่มีประโยชน์
กล่าวคือ อะไรคือสิ่งที่ชนิดหาBlock
?
ฉันจะส่งผ่านBlock
ไปยัง a Function
/ ได้Method
อย่างไร
ฉันพยายาม- (void)someFunc:(__Block)someBlock
โดยไม่มีประโยชน์
กล่าวคือ อะไรคือสิ่งที่ชนิดหาBlock
?
คำตอบ:
ประเภทของบล็อกจะแตกต่างกันไปขึ้นอยู่กับอาร์กิวเมนต์และประเภทการส่งคืน ในกรณีทั่วไปประเภทบล็อกมีการประกาศในลักษณะเดียวกันประเภทตัวชี้ฟังก์ชันมี แต่แทนที่ด้วย*
^
วิธีหนึ่งในการส่งบล็อกไปยังเมธอดมีดังนี้:
- (void)iterateWidgets:(void (^)(id, int))iteratorBlock;
แต่อย่างที่คุณเห็นนั่นมันยุ่ง คุณสามารถใช้ a typedef
เพื่อสร้างประเภทบล็อกที่สะอาดขึ้นแทน:
typedef void (^ IteratorBlock)(id, int);
จากนั้นส่งผ่านบล็อกนั้นไปยังวิธีการดังนี้:
- (void)iterateWidgets:(IteratorBlock)iteratorBlock;
NSNumber *
หรือstd::string&
หรือสิ่งอื่นที่คุณสามารถผ่านเป็นอาร์กิวเมนต์ฟังก์ชั่น นี่เป็นเพียงตัวอย่าง (สำหรับบล็อกที่เทียบเท่ายกเว้นแทนที่id
ด้วยNSNumber
ที่typedef
จะtypedef void (^ IteratorWithNumberBlock)(NSNumber *, int);
.)
NS_NOESCAPE
แต่enumerateObjectsUsingBlock
ฉันบอกว่าไม่หนีเลย แต่ฉันไม่เห็นNS_NOESCAPE
ที่ใดก็ได้ในไซต์และไม่ได้กล่าวถึงในเอกสาร Apple คุณช่วยได้ไหม
คำอธิบายที่ง่ายที่สุดสำหรับคำถามนี้เป็นไปตามเทมเพลตเหล่านี้:
1. บล็อกเป็นพารามิเตอร์วิธี
แบบ
- (void)aMethodWithBlock:(returnType (^)(parameters))blockName {
// your code
}
ตัวอย่าง
-(void) saveWithCompletionBlock: (void (^)(NSArray *elements, NSError *error))completionBlock{
// your code
}
การใช้งานอื่น ๆ ของกรณี:
2. บล็อกเป็นคุณสมบัติ
แบบ
@property (nonatomic, copy) returnType (^blockName)(parameters);
ตัวอย่าง
@property (nonatomic,copy)void (^completionBlock)(NSArray *array, NSError *error);
3. บล็อกเป็นอาร์กิวเมนต์วิธี
แบบ
[anObject aMethodWithBlock: ^returnType (parameters) {
// your code
}];
ตัวอย่าง
[self saveWithCompletionBlock:^(NSArray *array, NSError *error) {
// your code
}];
4. บล็อกเป็นตัวแปรในเครื่อง
แบบ
returnType (^blockName)(parameters) = ^returnType(parameters) {
// your code
};
ตัวอย่าง
void (^completionBlock) (NSArray *array, NSError *error) = ^void(NSArray *array, NSError *error){
// your code
};
5. บล็อกเป็น typedef
แบบ
typedef returnType (^typeName)(parameters);
typeName blockName = ^(parameters) {
// your code
}
ตัวอย่าง
typedef void(^completionBlock)(NSArray *array, NSError *error);
completionBlock didComplete = ^(NSArray *array, NSError *error){
// your code
};
คุณสามารถทำสิ่งนี้ผ่านบล็อกเป็นพารามิเตอร์บล็อก:
//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);
อีกวิธีหนึ่งในการส่งบล็อกโดยใช้ฟังก์ชันсในตัวอย่างด้านล่าง ฉันได้สร้างฟังก์ชันเพื่อดำเนินการทุกอย่างในพื้นหลังและบนคิวหลัก
ไฟล์ blocks.h
void performInBackground(void(^block)(void));
void performOnMainQueue(void(^block)(void));
ไฟล์ 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);
}
กว่านำเข้า blocks.h เมื่อจำเป็นและเรียกใช้:
- (void)loadInBackground {
performInBackground(^{
NSLog(@"Loading something in background");
//loading code
performOnMainQueue(^{
//completion hadler code on main queue
});
});
}
นอกจากนี้คุณยังสามารถตั้งค่าการบล็อกเป็นคุณสมบัติง่าย ๆ ได้ถ้ามันเหมาะสมกับคุณ:
@property (nonatomic, copy) void (^didFinishEditingHandler)(float rating, NSString *reviewString);
ตรวจสอบให้แน่ใจว่าคุณสมบัติบล็อกคือ "คัดลอก"!
และแน่นอนคุณสามารถใช้ typedef:
typedef void (^SimpleBlock)(id);
@property (nonatomic, copy) SimpleBlock someActionHandler;
นอกจากนี้คุณเรียกหรือเรียกบล็อกในการใช้ไวยากรณ์ฟังก์ชั่นปกติ
-(void)iterateWidgets:(IteratorBlock)iteratorBlock{
iteratorBlock(someId, someInt);
}
ข้อมูลเพิ่มเติมเกี่ยวกับบล็อกที่นี่
ฉันมักจะลืมเกี่ยวกับไวยากรณ์บล็อก สิ่งนี้อยู่ในใจของฉันเสมอเมื่อฉันต้องการประกาศบล็อก ฉันหวังว่ามันจะช่วยให้ใครบางคน :)
ฉันเขียนส่วนที่เสร็จแล้วบล็อคสำหรับชั้นเรียนซึ่งจะคืนค่าลูกเต๋าหลังจากพวกเขาถูกเขย่า:
กำหนด typedef ด้วย returnType ( ประกาศ.h
ด้านบน@interface
)
typedef void (^CompleteDiceRolling)(NSInteger diceValue);
กำหนด a @property
สำหรับบล็อก ( .h
)
@property (copy, nonatomic) CompleteDiceRolling completeDiceRolling;
กำหนดวิธีการด้วยfinishBlock
( .h
)
- (void)getDiceValueAfterSpin:(void (^)(NSInteger diceValue))finishBlock;
แทรกวิธีที่กำหนดไว้ก่อนหน้าใน.m
ไฟล์และกระทำfinishBlock
เพื่อ@property
กำหนดไว้ก่อน
- (void)getDiceValueAfterSpin:(void (^)(NSInteger diceValue))finishBlock{
self.completeDiceRolling = finishBlock;
}
หากต้องการเรียกใช้งานcompletionBlock
VariType ที่กำหนดไว้ล่วงหน้าให้กับมัน (อย่าลืมตรวจสอบว่าcompletionBlock
มีอยู่จริงหรือไม่)
if( self.completeDiceRolling ){
self.completeDiceRolling(self.dieValue);
}
แม้จะมีคำตอบในหัวข้อนี้ แต่ฉันพยายามเขียนฟังก์ชั่นซึ่งจะใช้ Block เป็นฟังก์ชัน - และมีพารามิเตอร์ ในที่สุดนี่คือทางออกของฉัน
ฉันต้องการเขียนฟังก์ชันทั่วไปloadJSONthread
ซึ่งจะใช้ URL ของ JSON Web Service โหลดข้อมูล JSON บางส่วนจาก URL นี้บนเธรดพื้นหลังจากนั้นส่งคืนผลลัพธ์ NSArray * กลับไปที่ฟังก์ชันการโทร
โดยทั่วไปฉันต้องการเก็บความซับซ้อนของแบ็คกราวน์ของเธรดไว้ในฟังก์ชันที่ใช้ซ้ำได้ทั่วไป
นี่คือวิธีที่ฉันจะเรียกใช้ฟังก์ชันนี้:
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)
}
} ];
... และนี่คือสิ่งที่ฉันต้องดิ้นรนด้วย: จะประกาศอย่างไรและจะให้มันเรียกฟังก์ชัน Block อย่างไรเมื่อข้อมูลถูกโหลดและผ่านBlock
NSArray * ของระเบียนที่โหลด:
+(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);
});
});
}
คำถาม StackOverflow นี้เกี่ยวข้องกับวิธีการเรียกใช้ฟังก์ชันการส่งผ่าน Block เป็นพารามิเตอร์ดังนั้นฉันจึงทำให้โค้ดด้านบนง่ายขึ้นและไม่รวมloadJSONDataFromURL
ฟังก์ชั่น
แต่ถ้าคุณสนใจคุณสามารถค้นหาสำเนาของฟังก์ชั่นการโหลด JSON นี้ในบล็อกนี้: http://mikesknowledgebase.azurewebsites.net/pages/Services/WebServices-Page6.htm
หวังว่านี่จะช่วยนักพัฒนา XCode อื่น ๆ ! (อย่าลืมลงคะแนนคำถามนี้และคำตอบของฉันถ้ามัน!)
เทมเพลตเต็มดูเหมือนว่า
- (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 {
}