Swift iOS - 从主队列中的函数内部调用主队列上的函数的差异?

时间:2018-03-20 16:19:36

标签: ios swift multithreading grand-central-dispatch

在我的应用程序中,我有几个在下面的完成处理程序中启用的东西,但为了简单起见,我在这个例子中只使用了一个按钮。我之所以这么说是因为有人会看一下这个例子并说因为只有一个按钮可以简单地使用第一个选项,这对1个按钮有意义,但不是几个。此问题也适用于在不同线程上运行的任何内容,然后是主线程,而不是CaptureSesion。

我有一个AVFoundation CaptureSession完成处理程序,它位于与主队列不同的线程上。运行时,它会将按钮更新为.isEnabled = true

我可以

•1。直接更新主队列上的函数:

... completionHandler{(

    DispatchQueue.main.async { [weak self] in
           self?.recordButton.isEnabled = true
    }
)}

•2。将按钮放在函数中,然后在主队列上更新该函数:

... completionHandler{(

    DispatchQueue.main.async { [weak self] in
           self?.enableRecordButton()
    }
)}

func enableRecordButton(){
    recordButton.isEnabled = true
}

•3。更新函数和主队列中函数内部的内容:

... completionHandler{(

    DispatchQueue.main.async { [weak self] in
           self?.enableRecordButton()
    }
)}

func enableRecordButton(){
    DispatchQueue.main.async { [weak self] in
           self?.recordButton.isEnabled = true
    }
}

3?

之间的区别是什么?

3 个答案:

答案 0 :(得分:2)

通常,您应该仅在主线程上更新UI组件。因此

DispatchQueue.main.async { [weak self] in
       self?.recordButton.isEnabled = true
}

绝对有道理。因为您希望启用该按钮并且它是UI修改,您希望它在主线程中。所以DispatchQueue.main.async闭包中的所有语句都将在主线程上执行。

中的位置
DispatchQueue.main.async { [weak self] in
       self?.enableRecordButton()
}

方法enableRecordButton将在主线程上执行。这意味着enableRecordButton方法中的所有语句以及它调用的所有后续方法都将在主线程上执行。

在你的情况下,如果你想要实现的只是启用一个按钮,而不是将它放在一个单独的功能中就没有多大意义。只有您可以通过在任何地方调用enableRecordButton函数来启用该按钮,而不是再次重复相同的语句,才能获得好处。

最后

... completionHandler{(

    DispatchQueue.main.async { [weak self] in
           self?.enableRecordButton()
    }
)}

func enableRecordButton(){
    DispatchQueue.main.async { [weak self] in
           self?.recordButton.isEnabled = true
    }
}

这在你的情况下毫无意义。声明

    DispatchQueue.main.async { [weak self] in
           self?.enableRecordButton()
    }

已经确保enableRecordButton中的所有语句都会在主线程上执行,因此在DispatchQueue.main.async中添加enableRecordButton毫无意义。

func enableRecordButton(){
    DispatchQueue.main.async { [weak self] in
           self?.recordButton.isEnabled = true
    }
}

只有当您的代码中有多个点可以调用enableRecordButton并且可能在非主线程上调用它时,这可能会派上用场,在这种情况下您可以安全地删除

    DispatchQueue.main.async { [weak self] in
           self?.enableRecordButton()
    }

只需在完成处理程序中调用self?.enableRecordButton()DispatchQueue.main.async函数中的enableRecordButton将确保所有语句都将在主线程上执行。

希望有所帮助

答案 1 :(得分:0)

我认为在函数中再次添加DispatchQueue.main.async {}是没用的,因为您已经在主线程上,您需要更新用户界面。假设您在更新按钮后需要安排某个任务,可以添加另一个DispatchQueue.main.async {}将其放入串行队列中,该队列将在更新按钮后执行。但是在每种情况下,更新都将仅在主线程上完成,而那些将是串行的。

答案 2 :(得分:0)

从技术上讲,三者都会达到相同的效果。它更多的是代码组织,可维护性和可读性。

对于#1,您可能在完成处理程序中执行与更新UI无关的业务逻辑。将UI更新移动到自己的方法更简洁,例如,在UIViewController中,其视图拥有该按钮(以及您提到的其他UI控件)。这样做的好处是,您可以通过应用程序中其他位置的相同调用启用UI控件,并且可以针对它编写测试。如果您有办法将UI更新调用(例如通过协议重定向到模拟),可以更好地测试此完成处理程序的业务逻辑。

#3是浪费,因为你浪费了一个收益,向主线程添加了一个任务,只是为了确保UI代码将在主线程上。您应该组织您的类和代码,以便始终很好地理解它们将从哪个线程调用。如果你在SDK中编写一个公共方法,你当然可以检查线程并断言调用者是否调用了你预期的线程以外的线程,但那是我唯一一次打扰它。

所以我的回答是#2是最好的。