IOS/Objective-C: 从异步方法中获取回调
IOS/Objective-C: Get call back from asynchronous method
在我的应用程序中的某个时刻,我调用了 superclass 中的一个方法来向服务器进行身份验证。在这个方法的最后,我想 运行 一些特定于调用它的 class 的代码。这是在调用附加代码之前等待 superclass 响应的最佳方式吗?
[super authenticateWithServer^(BOOL success, NSError *error) {
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(@"heard back from method");
if (success==YES) {
//RUN MY CODE HERE
}
});
}];
如果是这样,该方法会是什么样子?像下面这样的东西?
-(BOOL)authenticateWithServer (
//if fail {
return NO;
}
else {
return YES;
}
}
BOOL return 类型不与异步操作混合。相反,您需要将服务器身份验证的结果传递到完成块中,并让您的调用者检查它。我强烈建议您查看 http://goshdarnblocksyntax.com 以获得正确的块语法。
我很确定这与您尝试做的很接近(在此处添加了一个假延迟以模拟服务器请求):
@interface ViewController ()
@property (strong, nullable) IBOutlet UILabel *resultLabel;
- (void)authenticateWithServer:(void (^_Nullable)(BOOL success, NSError *_Nullable error))completion;
- (void)_fakeUrlRequestToServerWithCompletion:(void(^_Nullable)(BOOL successFromServer, NSError *_Nullable errorFromServer))serverCompletion;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
}
- (IBAction)authWithServerButton:(id)sender {
// call to authenticate with the results in the callback (not returning BOOL)
[self authenticateWithServer:^(BOOL success, NSError * _Nullable error) {
// callback will probably come in off the main queue so if you're doing some UI updates jump back on the main queue
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
self.resultLabel.text = [NSString stringWithFormat:@"Result = %@\nError = %@",success == 1 ? @"SUCCESS" : @"FAILURE", error == nil ? @"No Error" : error];
}];
}];
}
- (void)authenticateWithServer:(void (^_Nullable)(BOOL success, NSError *error))completion {
// put this on the background queue so it doesn't hug
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
// call the fakeUrlRequestToServer method to simulate your async request
[self _fakeUrlRequestToServerWithCompletion:^(BOOL successFromServer, NSError * _Nullable errorFromServer) {
// completion block that was passed into the method, callback and pass along the success and error results
completion(successFromServer, errorFromServer);
}];
});
}
- (void)_fakeUrlRequestToServerWithCompletion:(void(^_Nullable)(BOOL successFromServer, NSError *errorFromServer))serverCompletion {
// fake sleep here for 2 seconds just to simulate waiting for the callback
// never call sleep in your own code
sleep(2);
NSError *fakeError = nil;
// just a fake auth success or failure
BOOL fakeSuccess = arc4random() % 2 == 1 ? YES : NO;
if (fakeSuccess == NO) {
// fake error
fakeError = [NSError errorWithDomain:@"FakeErrorDomain" code:22 userInfo:nil];
}
// completion block that was passed into the method, call back with the success and error params passed in
serverCompletion(fakeSuccess, fakeError);
}
@end
这是一个实际应用的例子:
编辑: 因为在我给出的示例中完成块可以为空,所以您需要先检查是否传入了一个。
即
if (completion) {
completion(success, error);
}
在我的应用程序中的某个时刻,我调用了 superclass 中的一个方法来向服务器进行身份验证。在这个方法的最后,我想 运行 一些特定于调用它的 class 的代码。这是在调用附加代码之前等待 superclass 响应的最佳方式吗?
[super authenticateWithServer^(BOOL success, NSError *error) {
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(@"heard back from method");
if (success==YES) {
//RUN MY CODE HERE
}
});
}];
如果是这样,该方法会是什么样子?像下面这样的东西?
-(BOOL)authenticateWithServer (
//if fail {
return NO;
}
else {
return YES;
}
}
BOOL return 类型不与异步操作混合。相反,您需要将服务器身份验证的结果传递到完成块中,并让您的调用者检查它。我强烈建议您查看 http://goshdarnblocksyntax.com 以获得正确的块语法。
我很确定这与您尝试做的很接近(在此处添加了一个假延迟以模拟服务器请求):
@interface ViewController ()
@property (strong, nullable) IBOutlet UILabel *resultLabel;
- (void)authenticateWithServer:(void (^_Nullable)(BOOL success, NSError *_Nullable error))completion;
- (void)_fakeUrlRequestToServerWithCompletion:(void(^_Nullable)(BOOL successFromServer, NSError *_Nullable errorFromServer))serverCompletion;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
}
- (IBAction)authWithServerButton:(id)sender {
// call to authenticate with the results in the callback (not returning BOOL)
[self authenticateWithServer:^(BOOL success, NSError * _Nullable error) {
// callback will probably come in off the main queue so if you're doing some UI updates jump back on the main queue
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
self.resultLabel.text = [NSString stringWithFormat:@"Result = %@\nError = %@",success == 1 ? @"SUCCESS" : @"FAILURE", error == nil ? @"No Error" : error];
}];
}];
}
- (void)authenticateWithServer:(void (^_Nullable)(BOOL success, NSError *error))completion {
// put this on the background queue so it doesn't hug
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
// call the fakeUrlRequestToServer method to simulate your async request
[self _fakeUrlRequestToServerWithCompletion:^(BOOL successFromServer, NSError * _Nullable errorFromServer) {
// completion block that was passed into the method, callback and pass along the success and error results
completion(successFromServer, errorFromServer);
}];
});
}
- (void)_fakeUrlRequestToServerWithCompletion:(void(^_Nullable)(BOOL successFromServer, NSError *errorFromServer))serverCompletion {
// fake sleep here for 2 seconds just to simulate waiting for the callback
// never call sleep in your own code
sleep(2);
NSError *fakeError = nil;
// just a fake auth success or failure
BOOL fakeSuccess = arc4random() % 2 == 1 ? YES : NO;
if (fakeSuccess == NO) {
// fake error
fakeError = [NSError errorWithDomain:@"FakeErrorDomain" code:22 userInfo:nil];
}
// completion block that was passed into the method, call back with the success and error params passed in
serverCompletion(fakeSuccess, fakeError);
}
@end
这是一个实际应用的例子:
编辑: 因为在我给出的示例中完成块可以为空,所以您需要先检查是否传入了一个。
即
if (completion) {
completion(success, error);
}