所以在业余时间我正在处理HTTP请求'引擎'。 我正在尝试构建的是一个“引擎”,它生成对通用对象的请求/解析响应 对于iPhone应用程序。
最重要的是,它应该 _allways _回调用户界面。
无论发生什么(NSURLRequest超时/解析错误/ NSExcept引发) (也许SIG也有一天?)
所以我使用blocks和dispatch_once创建了一些gory。 它有效,但我有这个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
答案 0 :(得分:1)
你曾经'对于dispatch_once块,变量应该是静态的 - 即
static dispatch_once_t once = 0;
这将确保您的代码只执行一次恢复回调。实际上,你可以只使用一个静态布尔值 - 你实际上并不需要一个dispatch_once块,因为你要调度到一个串行队列(根据你的评论)。但是,这是一种很好的做法。
正如您的代码当前所示,每个异常都会执行一次恢复回调,这意味着如果您向APIEngineQueue分配两个块,理论上两个块都可以执行回调 - 因为每个块都有自己的本地'一次& #39;变量。换句话说,您的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也有点复杂,因为你知道你不在主线程上,所以为什么要测试呢?