在专用队列上运行任务并返回回调

时间:2016-02-07 16:44:23

标签: ios xcode7 grand-central-dispatch

我的方法在私有队列中运行其代码,在完成后,将调用传入的回调。是否需要检查传入的回调是否打算从主队列运行?

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();
               }
            }
        });
    }

2 个答案:

答案 0 :(得分:1)

虽然在任何地方都没有规定,但如果你看一下Cocoa API,你会看到三种常见的模式:

  1. 主线程:完成处理程序,明确指定将使用主队列。例如,请参阅CLGeocoder asynchronous query methods,其中"您的完成处理程序块将在主线程上执行。"

  2. 任意队列:完成处理程序,您无法保证代码将在哪个队列中运行。例如,如果您使用requestAccessForEntityType CNContactStorethe documentation says"则会在任意队列上调用完成处理程序。"

  3. 指定的队列:完成处理程序,您可以在其中指定要使用的队列。例如,如果使用[NSURLSession sessionWithConfiguration:delegate:queue:],则可以指定将用于委托方法和回调块/闭包的队列。 (但是,顺便说一句,如果你没有指定一个队列,它会使用它自己设计的一个,而不是默认为主队列。)

  4. 您提出的模式并不遵循任何这些非正式约定,而是有时使用主线程(如果碰巧从主线程调用它),但有时使用一些任意队列。在这种情况下,我没有看到引入新公约的迫切需要。

    我建议选择上述方法之一,然后在已发布的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>