我的方法在私有队列中运行其代码,在完成后,将调用传入的回调。是否需要检查传入的回调是否打算从主队列运行?
e.g。
- (void)doSomethingWithCalback:(void(^)())callback {
dispatch_async(self.privateQueue, ^{
// Should I make sure this gets dispatched
// to a main thread if it was passed in from a main thread?
if (callback) callback();
});
}
我应该做以下事情:
- (void)doSomethingWithCalback:(void(^)())callback {
BOOL isMainThread = [NSThread isMainThread];
dispatch_async(self.privateQueue, ^{
if (callback) {
if (isMainThread) {
dispatch_async(dispatch_get_main_thread, callback);
}
else {
callback();
}
}
});
}
答案 0 :(得分:1)
虽然在任何地方都没有规定,但如果你看一下Cocoa API,你会看到三种常见的模式:
主线程:完成处理程序,明确指定将使用主队列。例如,请参阅CLGeocoder
asynchronous query methods,其中"您的完成处理程序块将在主线程上执行。"
任意队列:完成处理程序,您无法保证代码将在哪个队列中运行。例如,如果您使用requestAccessForEntityType
CNContactStore
,the documentation says"则会在任意队列上调用完成处理程序。"
指定的队列:完成处理程序,您可以在其中指定要使用的队列。例如,如果使用[NSURLSession sessionWithConfiguration:delegate:queue:]
,则可以指定将用于委托方法和回调块/闭包的队列。 (但是,顺便说一句,如果你没有指定一个队列,它会使用它自己设计的一个,而不是默认为主队列。)
您提出的模式并不遵循任何这些非正式约定,而是有时使用主线程(如果碰巧从主线程调用它),但有时使用一些任意队列。在这种情况下,我没有看到引入新公约的迫切需要。
我建议选择上述方法之一,然后在已发布的API中明确说明。例如,如果您要使用privateQueue
:
@interface MyAPI : NSObject
/// Private queue for callback methods
@property (nonatomic, strong, readonly) dispatch_queue_t privateQueue;
/// Do something asynchronously
///
/// @param callback The block that will be called asynchronously.
/// This will be called on the privateQueue.
- (void)doSomethingWithCallback:(void(^)())callback;
@end
@implementation MyAPI
- (void)doSomethingWithCallback:(void(^)())callback {
dispatch_async(self.privateQueue, ^{
if (callback) callback();
});
}
@end
或者
@interface MyAPI : NSObject
/// Private queue used internally for background processing
@property (nonatomic, strong, readonly) dispatch_queue_t privateQueue;
/// Do something asynchronously
///
/// @param callback The block that will be called asynchronously.
/// This will be called on the main thread.
- (void)doSomethingWithCallback:(void(^)())callback;
@end
@implementation MyAPI
- (void)doSomethingWithCallback:(void(^)())callback {
dispatch_async(self.privateQueue, ^{
if (callback) {
dispatch_async(dispatch_get_main_queue(), ^{
callback();
});
}
});
}
@end
注意,无论您使用哪种约定,我都建议您在标题中使用///
条评论或/** ... */
条评论,这样当您在代码中使用该方法时,您就可以看到该队列行为显示在右侧的快速帮助面板中。
答案 1 :(得分:0)
您应该指定API方法/// callback will be executed on the queue passed in to onQueueOrNil.
/// If onQueueOrNil is nil, it will be executed on the main queue
- (void)doSomethingWithCallback:(void(^)())callback onQueue:(dispatch_queue_t)onQueueOrNil {
dispatch_async(self.privateQueue, ^{
if (callback){
if(!onQueueOrNil) {
onQueueOrNil = dispatch_get_main_queue();
}
dispatch_async(onQueueOrNil, callback);
}
});
}
在执行回调时将使用的队列,或者允许方法的使用者传入他们希望执行的队列,如下所示:
<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="initial-scale=1, maximum-scale=1, user-scalable=no" />
<link rel="stylesheet" href="../bower_components/bootstrap/dist/css/bootstrap.min.css">
<link rel="stylesheet" href="../bower_components/alertify.js/dist/css/alertify.css">
</head>
<body ng-app="gameApp">
<div ng-view=""></div>
<!-- COMPONENTS -->
<script src="../bower_components/angular/angular.js"></script>
<script src="../bower_components/react/react.js"></script>
<script src="../bower_components/react/react-dom.js"></script>
<script src="../bower_components/ngReact/ngReact.min.js"></script>
<script src="../bower_components/angular-route/angular-route.js"></script>
<script src="../bower_components/angular-resource/angular-resource.js"></script>
<script src="../bower_components/jquery/dist/jquery.min.js"></script>
<script src="../bower_components/bootstrap/dist/js/bootstrap.min.js"></script>
<script src="../bower_components/alertify.js/dist/js/alertify.js"></script>
<script src="../bower_components/babel/browser.js"></script>
<!-- SOCKET.IO -->
<script src="../node_modules/socket.io-client/socket.io.js"></script>
<!-- REACT COMPONENTS -->
<script type="text/babel" src="js/components/LoginComponent.js"></script>
<!-- DIRECTIVES -->
<script src="js/directives/login.js"></script>
<!-- JAVASCRIPT FILES -->
<script src="js/app.js"></script>
<!-- CONTROLLERS -->
<script src="js/controllers/login.js"></script>
<!-- SERVICES -->
<script src="js/services/commonServices.js"></script>
</body>
</html>