2014-10-08 124 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