我有一个名为getCount:
的异步方法,它指向一个web URL,对一些内容进行计数,并在计数完成后调用带有计数的回调。
我有另一个同步的方法,需要获取这些结果,将它们放入消息中,然后返回该消息。以下是两者:
- (NSString *)describe {
__block bool gotCount = NO;
[self getCount:^(int count) {
NSLog(@"Got the count: %i", count);
_count = count; // _count is an ivar of the object with this method.
gotCount = YES;
}];
// Pause here until the count has been fetched.
while (!gotCount) {
[NSThread sleepForTimeInterval:0.05];
}
return [NSString stringWithFormat:@"The count is %i", _count];
}
当我尝试此操作时,我的回调从未被调用。它从不打印
Got the count 0
或者在这种情况下用于计数的任何其他值。
如果我注释掉while循环,那么消息就会打印出来。所以我知道getCount:
方法是有效的,只是我的循环在等待它到达时出现了问题。
我需要getCount:
保持异步(在其他地方使用它更重要),我需要describe
保持同步。我该如何处理?
一件可能的事情:如果你的描述方法在主线程中,那么你也从主线程调用getCount方法,所有的web回调都在主线程但是你用线程睡眠阻塞了主线程->你无法从网络上得到回叫以获得计数。
编辑:
尝试从另一个线程调用getCount方法。使用例如
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[self getCount:^(int count) {
NSLog(@"Got the count: %i", count);
_count = count; // _count is an ivar of the object with this method.
gotCount = YES;
}];
});
编辑2:
我试过这段代码,它运行得很好->getCount方法中的线程可能出了问题。
- (NSString *)describe {
__block bool gotCount = NO;
__block NSInteger _count;
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[NSThread sleepForTimeInterval:5.00];
_count = 5;
gotCount = YES;
});
// Pause here until the count has been fetched.
while (!gotCount) {
[NSThread sleepForTimeInterval:0.05];
}
return [NSString stringWithFormat:@"The count is %li", _count];
}
一种可行但已退出的方法是在等待时运行runloop:
注意:这依赖于回调与描述方法在同一队列上
请参阅:JSON异步请求[SAME ISSUE]
一个独立的工作示例:
#import <Foundation/Foundation.h>
@interface T : NSObject
- (NSString *)describe;
@end
@implementation T {
int _count;
}
- (void)getCount:(void (^)(int c)) handler {
dispatch_async(dispatch_get_global_queue(0,0), ^ {
sleep(5);
dispatch_sync(dispatch_get_main_queue(), ^{
handler(55);
});
});
}
- (NSString *)describe {
__block bool gotCount = NO;
[self getCount:^(int count) {
NSLog(@"Got the count: %i", count);
_count = count; // _count is an ivar of the object with this method.
gotCount = YES;
}];
// Pause here until the count has been fetched.
while (!gotCount) {
[[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:0.1]];
}
return [NSString stringWithFormat:@"The count is %i", _count];
}
@end
int main(int argc, char *argv[]) {
@autoreleasepool {
T *t = [T new];
NSLog(@"describe: %@", [t describe]);
}
}