【问题标题】:Perform selector with a callback = concurrency?使用回调 = 并发执行选择器?
【发布时间】:2012-12-03 10:12:47
【问题描述】:

关于我所面临的情况,我有一个小问题。 我有两种方法:

- (void)firstSelector {
    [self launchAsyncTask];
    ... do some work for a long time (10secs) ...
}

- (void)asyncTaskFinished {
    ... some work after 5secs of async task ...
}

firstSelector 执行launchAsyncTask,这只是一个后台任务,它有一个名为asyncTaskFinished 的回调。 假设firstSelector在启动异步任务后运行了一定时间(比如说10秒),并且异步任务运行了5秒,会不会出现并发问题?

这在后台是如何工作的? asyncTaskFinished会在firstSelector之后执行,还是firstSelector会暂停运行asyncTaskFinished

是否有运行循环的链接?方法是否添加到队列中,然后在我调用它们时执行?

我迷路了:)

谢谢。

【问题讨论】:

  • 您阅读过文档developer.apple.com/library/ios/#documentation/Cocoa/Conceptual/… 吗?我相信它可以解释一切,直到您有任何具体问题。
  • 我知道我的回调是使用主线程运行循环排队的,但是 firstSelector 呢?我使用标准“[self firstSelector];”来执行它。也是这样排队的?
  • “回调”通常在与主“操作”相同的线程中触发,它可能是任何线程,而不仅仅是主线程。由于您没有要讨论的代码,因此通常有可能从分离线程调用 firstSelector 并且 launchAsyncTask 也创建另一个后台线程。或者它们可能是相同的主线程/分离线程,或者其中一个位于主线程,另一个位于分离线程。您可能还决定始终在主线程上触发回调。这一切都是由设计驱动的,并且总是需要有据可查,因为每个场景都是不同的。

标签: iphone ios cocoa methods concurrency


【解决方案1】:

异步任务异步运行,它不在主运行循环上运行,而 UI 在主循环上运行。看看Concurrency Programming Guide

因此,在您的情况下,您并不确定同步时间需要多长时间。您假设它可能需要 10 秒,但并不完全确定。因此,在这种情况下,当异步任务在主线程上完成时,您将需要使用块或找到一种方法来触发 asyncTaskFinished 函数。您可以定义一个简单的块回调,然后在异步任务完成时触发该函数。

如果您将 GCD 用于异步任务,它会变得非常简单。你会做这么多;

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        [self runMyAsyncTask];
        // trigger the main completion handler when this completed
        dispatch_async(dispatch_get_main_queue(), ^{
            [self asyncTaskFinished];
        });
    });

如果您使用 NSThread 进行并发,您可以使用 performSelector:onThread: 在异步任务完成时触发完成选择器。对于一个简单的案例,我将向您展示如何实现一个回调处理程序。你可以创建一个这样的函数来触发异步任务,

-(void)launchAsyncTaskWithCompletionHandler:(void(^)(void))completionHandler{
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        [self runMyAsyncTask];
        // trigger the main completion handler when this completed
        dispatch_async(dispatch_get_main_queue(), ^{
            completionHandler();
        });
    });
}

而且调用这个比较简单;

[self launchAsyncTaskWithCompletionHandler:^{
        [self asyncTaskFinished];
    }];

这很容易理解并使您的代码更加清晰。希望对您有所帮助。

【讨论】:

  • 谢谢。我了解您所写的内容并且已经知道这些概念。当方法 A 运行并且来自另一个实体的回调 B 在同一个线程上被调用(但方法 A 尚未完成)时,我遇到的问题发生了。如果这两种方法都使用运行循环进行排队,则没有问题(我认为回调就是这种情况,因为我知道 -performSelector... 使用运行循环)。
  • 但是在 A 没有排队的情况下(这是我不知道使用 [self methodA] 时可可在引擎盖下会发生什么;),它提出了一个问题(A 是执行,B 将被执行,问题是何时以及如何因为 A 不在队列中)。
  • @Nicolas 请查看文档的Queuing Tasks for Dispatch 部分:developer.apple.com/library/ios/#documentation/Performance/… 它对可用的串行/并发队列有很好的简短说明。
【解决方案2】:

线程的运行循环以顺序(非并发)方式从其输入源执行任务。因此,只要firstSelectorasyncTaskFinished 在同一个运行循环中执行,您就不必担心。这将取决于回调语义。您可能需要使用 performSelector:onThread:withObject:waitUntilDone: 之类的东西来确保异步回调函数在正确的线程中执行。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多