В Swift как вызвать метод с параметрами в основном потоке GCD?

151

В моем приложении у меня есть функция, которая делает NSRURLSession и отправляет NSURLRequest, используя

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

В блоке завершения для этой задачи мне нужно сделать некоторые вычисления, которые добавят UIImage к вызывающему диспетчеру просмотра. У меня есть функция, называемая

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". Как я могу это сделать, или кто-то может предложить оптимальный способ добавления вызова метода в основную очередь приложения?

Теги:
grand-central-dispatch
parameters

9 ответов

405
Лучший ответ

Просто напишите это в completion handler нужно использовать dispatch_after

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

Свифт 3:

DispatchQueue.main.async { 
  let delegateObj = UIApplication.sharedApplication().delegate as YourAppDelegateClass
  delegateObj.addUIImage("yourstring")
}

Также для отправки после основной очереди

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

Замените YourAppDelegateClass вашим классом делегата.

  • 0
    Это не работает, потому что XCode возвращает ошибку, говоря, что UIApplication не имеет члена с именем addUIImage. Также нет необходимости в символе карата в Swift.
  • 0
    извините за карат это опечатка. Но где у вас addUIImage addUIImage. Если это в делегате app delegate чем он будет работать. Я проверил это работает правильно
Показать ещё 8 комментариев
66

Версия Swift 3 & Swift 4:

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

Swift3 и XCode 9.2:

dispatch_async_on_main_queue {
     //Your code
     print("Hello")
 }
  • 0
    Спасибо, это сработало для меня.
14

Swift 2

Использование Trailing Closures становится следующим:

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

Trailing Closures - это синтаксический сахар Swift, который позволяет определять замыкание вне области параметров функции. Для получения дополнительной информации см. Trailing Closures в руководстве по языку программирования Swift 2.2.

В случае dispatch_async API func dispatch_async(queue: dispatch_queue_t, _ block: dispatch_block_t), поскольку dispatch_block_t является псевдонимом типа для () -> Void - закрытие, которое принимает 0 параметров и не имеет возвращаемого значения, а блок является последним параметром функции, которую мы можем определить замыкание во внешнем объеме dispatch_async.

  • 1
    это было именно 3 строки, которые я ищу ... теперь вы можете перестать читать мои мысли
6

Здесь лучше (IMO) Swifty/ Cocoa синтаксис стиля для достижения того же результата, что и другие ответы:

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

Или вы могли бы захватить популярную библиотеку Async Swift за еще меньше кода и больше функциональности:

Async.main {
    // Your code here
}
3

Правильный способ сделать это - использовать dispatch_async в main_queue, как я сделал в следующем коде

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

Вот небольшая глобальная функция, которую вы можете добавить для лучшего синтаксиса:

func dispatch_on_main(block: dispatch_block_t) {
    dispatch_async(dispatch_get_main_queue(), block)
}

И использование

dispatch_on_main {
    // Do some UI stuff
}
1

Не забывайте ослаблять себя, если вы используете себя внутри закрытия.

dispatch_async(dispatch_get_main_queue(),{ [weak self] () -> () in
            if let strongSelf = self {
                self?.doSomething()
            }
        })
  • 0
    Не могли бы вы объяснить, почему мы должны это делать?
  • 0
    Это потому, что он может создавать циклы памяти - то есть, у меня есть сильная ссылка на что-то, и это имеет сильную ссылку на меня. То есть ни один из нас не может оставить кучу памяти.
0
//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()
})
0

Перезагрузить коллекциюПосмотреть на главной теме

 DispatchQueue.main.async {
      self.collectionView.reloadData()
 }

Ещё вопросы

Сообщество Overcoder
Наверх
Меню