Как правильно использовать DispatchQueue.main.async?

#swift #for-loop #asynchronous #dispatch-queue

#swift #для цикла #асинхронный #отправка-очередь

Вопрос:

В моем приложении есть цикл, обработка которого может занять несколько секунд.

Я хочу, чтобы экран немедленно отключался, пока цикл выполняется в фоновом режиме.

Возможно ли это?

Я попытался добавить только цикл:

 
DispatchQueue.main.async {
                for _ in 1...self.numberOfTransactionsToAdd {
                    
                    let newTransaction = Transaction()
                    
                    var timeAdded = 1.months
                    newTransaction.transactionAmount = self.amountTextField.text!.toDouble()
                    newTransaction.transactionDescription = self.descriptionTextField.text
                    newTransaction.transactionDate = self.datePicked
                    newTransaction.transactionCategory = self.categoryPicked
                    newTransaction.repeatInterval = self.repeatInterval
                    newTransaction.transactionSubCategory = self.subcategoryPicked
                    newTransaction.subCategoryName = self.subcategoryPicked!.subCategoryName
                    
                  
                    try! self.realm.write {
                        self.realm.add(newTransaction)
                    }
                    
                    self.datePicked = self.datePicked   timeAdded
                }
            }
                
            }

  

Я попытался добавить всю функцию целиком:

     @IBAction func doneButtonPressed(_ sender: UIButton) {
        
        self.dismiss(animated: true, completion: nil)

        DispatchQueue.main.async {

            self.saveTransaction()

        }
        
    }
  

Но экран все еще зависает до того, как просмотр будет отклонен.

Я впервые использую DispatchQueue. Я прочитал документацию Apple по этому вопросу, но она крайне расплывчата.

Это вообще правильный способ сделать это?

Может кто-нибудь помочь новичку правильно это сделать?

Комментарии:

1. Почему их два DispatchQueues ? Показан ли первый пункт кода saveTransaction ?

2. Эти фрагменты кода были просто двумя разными вещами, которые я пробовал, а не вместе.

Ответ №1:

Проблема заключается в асинхронном вызове самой основной очереди для работы, не связанной с пользовательским интерфейсом (фоновая работа). Заменить DispatchQueue.main.async на DispatchQueue.global().async . Причина в том, что все задачи, не связанные с пользовательским интерфейсом, должны выполняться асинхронно из основной очереди.

После выполнения вышеуказанного исправления у вас все равно будет другая проблема, которая будет связана с доступом к элементам пользовательского интерфейса из неосновной очереди (поскольку теперь наш код будет выполняться в глобальной очереди). Причина в том, что вы будете извлекать данные элементов пользовательского интерфейса (например, текст amountTextField и т. Д.) Из глобальной очереди. Храните данные пользовательского интерфейса в локальной переменной и используйте локальные переменные в коде цикла вместо вызова amountTextField и других текстовых полей.

 var amountData: Double
var description: String

@IBAction func doneButtonPressed(_ sender: UIButton) {
    amountData = amountTextField.text!.toDouble()
    descriptionTextField = descriptionTextField.text
    DispatchQueue.global().async {
        self.saveTransaction()
    }
    self.dismiss(animated: true, completion: nil)
}

func saveTransaction() {
    for _ in 1...self.numberOfTransactionsToAdd {
        .
        .
        newTransaction.transactionAmount = self.amountData
        newTransaction.transactionDescription = self.descriptionTextField
        .
        .
        .
    }
    
}
  

Ответ №2:

Похоже, ваша проблема связана с GCD:

 @IBAction func doneButtonPressed(_ sender: UIButton) {
    DispatchQueue.global(qos: .background).async {
//  do here your loading, fetching the data etc
        self.saveTransaction()
    DispatchQueue.main.async {
//  do here ui works, because user doesn't want to wait for touching etc so it has to be asp
        self.dismiss(animated: true, completion: nil)
    }
  }
}
  

Комментарии:

1. Когда я пытаюсь это сделать, я получаю сообщение «Завершение работы приложения из-за неперехваченного исключения»RLMException», причина: «Доступ к области из неправильного потока».

2. Я не имел в виду неуважения, я действительно ценю помощь. Я рассмотрю проблему и буду обновлять эту страницу.