0

所以在我的业余时间,我正在研究一个 HTTP 请求“引擎”。我正在尝试构建的是一个“引擎”,它为 iphone 应用程序生成对通用对象的请求/解析响应。

最重要的是,它应该_allways _ 回调 UI。

不管发生了什么(NSURLRequest 超时/解析错误/ NSExcept 引发)(也许有一天也有 SIG?)

所以我用blocks和dispatch_once创造了一些血腥的东西。它有效,但我有这个 Clang 警告。我的意思是我的请求有效,如果出现异常,显然会调用一次 UI。

调用“dispatch_once”使用局部变量“once”作为谓词值。对谓词使用这种瞬态记忆是有潜在危险的

这是问题的核心

// invoke a bloc in a proper thread with a proper autorelease / trycatch / logs
static inline void api_dispatch_concurrent(EngineOnceCallback block, SEL caller, EngineCallback callback) {
    dispatch_async(APIengineQueue(), ^{  // serial dispatch_queue
    @autoreleasepool {    

            dispatch_once_t once = 0;

            @try {
                // block may callback using 'once'
                (block) ? block(once) : NULL;
            }

            @catch (NSException *exception) {
            [[ACLogs sharedLogs] logException:exception caller:caller
                                        class:[ACRetroscopeEngine class]];

            APILog(@"NSException invoking API block:%@", exception);
            dispatch_once(&once, ^{
                APILog(@"Perform callback as recover from exception");
                ACResponse *defaultResponse = [ACResponse responseWithException:exception];

                try_catch(block_safe_invoke_main_thread(callback, defaultResponse));
            });
        }
        @finally {

        }
    }
});
}

那里使用了一些宏:

#define block_safe_invoke(block, ...) (block != NULL) ? block(__VA_ARGS__) : NULL;

#define block_safe_invoke_main_thread(block, ...)               \
if ([NSThread isMainThread]) {                                  \
    block_safe_invoke(block, __VA_ARGS__)                       \
} else {                                                        \
    dispatch_sync(dispatch_get_main_queue(), ^{                 \
        block_safe_invoke(block, __VA_ARGS__)                   \
    });                                                         \
}                                                               \

提前感谢:p

4

1 回答 1

1

对于 dispatch_once 块,您的“once”变量应该是静态的 - 即

  static dispatch_once_t once = 0;

这将确保您的代码永远只执行一次恢复回调。在实践中,您可以只使用静态布尔值 - 您实际上不需要 dispatch_once 块,因为您正在调度到串行队列(根据您的评论)。但是,这是一种很好的做法。

就您的代码当前而言,每个异常都会执行一次恢复回调,这意味着如果您将两个块分派到 APIEngineQueue,理论上两个块都可以执行回调 - 因为每个块都有自己的本地“一次”变量。换句话说,此时您的 dispatch_once 根本没有任何效果,它与编写相同:

    @catch (NSException *exception) {
        [[ACLogs sharedLogs] logException:exception caller:caller
                                    class:[ACRetroscopeEngine class]];

        APILog(@"NSException invoking API block:%@", exception);
        APILog(@"Perform callback as recover from exception");
        ACResponse *defaultResponse = [ACResponse responseWithException:exception];
        try_catch(block_safe_invoke_main_thread(callback, defaultResponse));

block_safe_invoke_main_thread 也有点复杂,因为你知道你不在主线程上,所以为什么要测试它呢?

于 2014-09-02T20:15:16.497 回答