在Swift中如何在GCD主线程上调用带参数的方法?


192

在我的应用程序中,我有一个函数使NSRURLSession并使用以下命令发送NSURLRequest

sesh.dataTaskWithRequest(req, completionHandler: {(data, response, error)

在此任务的完成块中,我需要进行一些计算,以将UIImage添加到调用的viewcontroller中。我有一个叫做

func displayQRCode(receiveAddr, withAmountInBTC:amountBTC)

进行UIImage添加计算。如果我尝试在完成块内运行添加视图的代码,则Xcode会引发错误,提示我在后台进程中无法使用布局引擎。所以我在SO上找到了一些代码,试图在主线程上排队一个方法:

let time = dispatch_time(DISPATCH_TIME_NOW, Int64(0.0 * Double(NSEC_PER_MSEC)))

dispatch_after(time, dispatch_get_main_queue(), {
    let returned = UIApplication.sharedApplication().sendAction("displayQRCode:", to: self.delegate, from: self, forEvent: nil)
})

但是,我不知道如何向此函数调用添加参数“ receiveAddr”和“ amountBTC”。我该怎么做,或者有人可以建议将方法调用添加到应用程序主队列的最佳方法?

Answers:


496

Swift的现代版本DispatchQueue.main.async用于调度到主线程:

DispatchQueue.main.async { 
  // your code here
}

要在主队列上分派之后,请使用:

DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
  // your code here
}

使用的旧版Swift:

dispatch_async(dispatch_get_main_queue(), {
  let delegateObj = UIApplication.sharedApplication().delegate as YourAppDelegateClass
  delegateObj.addUIImage("yourstring")
})

尽管您的建议正确无误,但我认为我的回答会稍好一点,因为它不会调用UIApplication.sharedApplication,这很不寻常,可能会使我的代码的其他读者失望。我的回答范围仅限于重要的对象,而您的对象带有辅助对象,这些对象需要我阅读更多文档才能确切地了解自己在做什么。我已经编辑了原始问题,以包含正确的函数调用。我以为displayQRCode不够具体,但现在我们的评论是。感谢您指出了这一点。
almel 2014年

84

Swift 3+和Swift 4版本:

DispatchQueue.main.async {
    print("Hello")
}

Swift 3和Xcode 9.2:

dispatch_async_on_main_queue {
    print("Hello")
}

15

迅捷2

使用尾随闭包将变为:

dispatch_async(dispatch_get_main_queue()) {
    self.tableView.reloadData()
}

尾随闭包是一种Swift语法糖,可以在函数参数范围之外定义闭包。有关更多信息,请参见《Swift 2.2编程语言指南》中的尾随闭包

在dispatch_async情况下,API是func dispatch_async(queue: dispatch_queue_t, _ block: dispatch_block_t)因为dispatch_block_t的类型别名() -> Void-一个闭包,它接收0个参数并且没有返回值,而block是函数的最后一个参数,我们可以在的外部范围中定义闭包dispatch_async


1
那正是我正在寻找的3行...现在您可以停止阅读我的想法了
Laszlo


7

这是更好的(IMO)Swifty / Cocoa样式语法,可实现与其他答案相同的结果:

NSOperationQueue.mainQueue().addOperationWithBlock({
    // Your code here
})

或者,您可以获取流行的Async Swift库以获取更少的代码和更多的功能:

Async.main {
    // Your code here
}

方法重命名为OperationQueue.main.addOperation({ }
Frostmourne

3

正确的方法是在main_queue中使用dispatch_async,就像我在以下代码中所做的那样

dispatch_async(dispatch_get_main_queue(), {
    (self.delegate as TBGQRCodeViewController).displayQRCode(receiveAddr, withAmountInBTC:amountBTC)
})


2
//Perform some task and update UI immediately.
DispatchQueue.global(qos: .userInitiated).async {  
    // Call your function here
    DispatchQueue.main.async {  
        // Update UI
        self.tableView.reloadData()  
    }
}

//To call or execute function after some time
DispatchQueue.main.asyncAfter(deadline: .now() + 5.0) {
    //Here call your function
}

//If you want to do changes in UI use this
DispatchQueue.main.async(execute: {
    //Update UI
    self.tableView.reloadData()
})

2

如果您在闭包内部使用self,请不要忘记削弱自己。

dispatch_async(dispatch_get_main_queue(),{ [weak self] () -> () in
    if let strongSelf = self {
        self?.doSomething()
    }
})

1
您能否解释为什么我们应该这样做?
Jackspicer

这是因为它可以创建内存周期-即,我对某事有很强的引用,并且对我有很强的引用。意味着我们两个都不能离开内存堆。
jackofallcode
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.