2014-10-08 128 views
0

我有一个称为getCount:的异步方法,它转到网址,计算一些东西,并在计数完成时调用回调。Obj-C同步使用块回调的异步方法

我有另一种同步的方法,需要将这些结果放入消息中,并返回该消息。下面是两个在一起:

- (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保持同步。我该如何处理?

+0

_Why_您需要'describe'等待返回吗? – 2014-10-08 19:12:34

+0

直到我们看到'getCount:'的来源并知道'describe'正在运行什么队列时,我们才能真正知道发生了什么。我的猜测是,getCount:正在调度回调以与描述相同的串行队列运行。 – 2014-10-08 19:15:18

+3

这种积极等待的形式非常糟糕......如果睡眠和回调在同一队列中,它也不起作用 – 2014-10-08 19:18:10

回答

2

一个可能的事情:如果您的描述方法在主线程中,那么您也可以从主线程调用getCount方法,并且所有Web回调都位于主线程中。 但是你使用线程sleep来阻塞主线程 - >你无法从网络获取回调来获得计数。

被修改:

尝试从另一个线程调用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]; 
} 
+0

我怎么能保证这不会发生? – ArtOfWarfare 2014-10-08 19:23:42

+0

我在您更新的帖子中尝试了解决方案。它不适合我。 – ArtOfWarfare 2014-10-08 19:36:33

+0

我有一位同事看我的代码,他向我透露了一些东西:我的代码实际上是从主线程调用的。我正在使用一个Parse方法,它的名字中有背景,并且使用了一个块回调,并且从该回调调用了'describe'。该回调不会在后台线程上发生 - 该方法在后台线程上运行,然后在主线程上调用您的回调。因此,在'describe'周围的回调中粘贴'dispatch_async'将其放回到我想要的背景中。 – ArtOfWarfare 2014-10-10 01:46:43

0

的方式,将工作,但也是相当的黑客(苹果公司在Mac中老年的API使用所有的时间),将运行runloop在等待:

注:这依赖于回调是在同一队列作为描述方法

见:JSON async request [同样的问题]


个自包含的工作示例:

#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]); 
    } 
} 
+0

我试过了。它不适合我。 – ArtOfWarfare 2014-10-08 19:33:04

+0

这是一个黑客,但不要说它不起作用;)编辑显示它 – 2014-10-08 19:55:11