Элементы пользовательского интерфейса Отсутствуют текст после Segue при вызове асинхронно

Сегодня я столкнулся с интересной дилеммой в создании приложения для сетевого анализа для колледжа. Вызов функции performSegue из асинхронного DispatchQueue делает текст некоторого пользовательского интерфейса в контроллере представления назначения пустым. Кнопки, метки и т. Д. Все так же, как если бы у них были свойства текста, установленные на пустые строки.

Я объясню дальше.

У меня есть пользовательский класс Swift, называемый Globals , который используется для размещения (очевидно) глобальных переменных, которые необходимо читать и писать в приложениях.

У меня есть UIViewController который действует как экран загрузки для моего приложения.

У меня есть UIViewController который загружается по завершении этого экрана загрузки.

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

 func testSpeed() { Globals.shared.dlStartTime = Date() if Globals.shared.currentSSID == "" { Globals.shared.bandwidth = 0 Globals.shared.DownComplete = true } else { let url = URL(string: "[EXAMPLE]") let session = URLSession(configuration: URLSessionConfiguration.default, delegate: self, delegateQueue: nil) let task = session.downloadTask(with: url!) task.resume() } } public func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didWriteData bytesWritten: Int64, totalBytesWritten: Int64, totalBytesExpectedToWrite: Int64) { Globals.shared.dlFileSize = (Double(totalBytesExpectedToWrite) * 8) / 1000 let progress = (Double(totalBytesWritten) / Double(totalBytesExpectedToWrite)) * 100.0 Globals.shared.dlprogress = Int(progress) } public func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didFinishDownloadingTo location: URL) { let elapsed = Double( Date().timeIntervalSince(Globals.shared.dlStartTime)) Globals.shared.bandwidth = Int(Globals.shared.dlFileSize / elapsed) Globals.shared.DownComplete = true Globals.shared.dataUse! += (Globals.shared.dlFileSize! / 8000) } 

Как вы можете видеть, URLSession использует делегаты URLSessionDelegate и URLSessionDownloadDelegate чтобы передать ход загрузки на экран загрузки, который позволяет пользователю знать, как идут дела.

Как вы можете видеть, существует глобальная логическая переменная DownComplete , которая позволяет остальной части приложения знать, когда процесс будет завершен.

Вернитесь к экрану загрузки. Существует метка завершения, называемая progressLabel а также пользовательский радиальный прогресс, называемый MainProgress . Вот код:

 override func viewDidAppear(_ animated: Bool) { [...] Networking().testSpeed() updateProgress() } func updateProgress() { DispatchQueue.global().async { while Globals.shared.DownComplete == false { DispatchQueue.main.sync { self.progressLabel.text = String(Globals.shared.dlprogress) + "%" self.MainProgress.animate(fromAngle: self.MainProgress.angle, toAngle: Double(Globals.shared.dlprogress) } } self.performSegue(withIdentifier: "LoadCompleteSegue", sender: self) } } 

Идея состоит в том, чтобы запустить цикл while, который ждет завершения процесса до загрузки следующего контроллера представления.

Но чтобы не блокировать основной поток, цикл while должен выполняться асинхронно.

… Но для правильного обновления пользовательского интерфейса эти вызовы должны выполняться в синхронном блоке.

…… Но чтобы полностью не пропустить процесс, performSegue выполнения должна выполняться в том же потоке, что и цикл while. И я думаю, это то, что вызывает мою проблему.

Ниже приведен снимок экрана следующего контроллера представлений, где я изложил области, где должен быть текст в красных квадратах. Потому что то, что меня озадачивает, это то, что оно не влияет на все элементы пользовательского интерфейса, всего на несколько.

Скриншот: Отсутствующие элементы

РЕДАКТИРОВАТЬ:

Я знаю, что код не самый чистый, но это мои «тестовые площадки» Git branch. Потерпите меня, пожалуйста.

Вы должны выполнить segue в главной очереди. Если вы отправите его после цикла while, он должен работать нормально. Попробуйте обновить updateProgress() до следующего:

 func updateProgress() { DispatchQueue.global().async { while Globals.shared.DownComplete == false { DispatchQueue.main.sync { self.progressLabel.text = String(Globals.shared.dlprogress) + "%" self.MainProgress.animate(fromAngle: self.MainProgress.angle, toAngle: Double(Globals.shared.dlprogress) } } DispatchQueue.main.async { self.performSegue(withIdentifier: "LoadCompleteSegue", sender: self) } } } 

Вы делаете это очень плохо. Вы можете просто использовать NSNotificatioCenter

В вашем представленииDidLoad я бы заметил следующие события:

 NotificationCenter.default.addObserver(self, selector: #selector(processFinished), name: NSNotification.Name(rawValue: "ProcessFinished"), object: nil) NotificationCenter.default.addObserver(self, selector: #selector(ProcessUpdating), name: NSNotification.Name(rawValue: "ProcessUpdating"), object: nil) 

и в ваших соответствующих делегатах я бы сказал:

 // complete event NotificationCenter.default.post(name: NSNotification.Name(rawValue: "ProcessFinished"), object: nil, userInfo: nil) // progress event NotificationCenter.default.post(name: NSNotification.Name(rawValue: "ProcessUpdating"), object: nil, userInfo: ["progress" : 11]) 

Затем вы можете обрабатывать свои события с помощью:

  func processFinished(notification: Notification) { // perform yout segue print("processFinished") } func ProcessUpdating(notification: Notification) { // update UI let progress = notification.userInfo!["progress"] as! Int print("progress: \(progress)") } 
  • Реагировать на перезагрузку приложения iOS для iOS
  • Аккумуляторная батарея SpriteKit / Energy Drain
  • Процесс подачи заявки на основе IOT в AppStore
  • Задержка симулятора при прокрутке UICollectionView на XCode 7.1. +
  • Xcode работает очень медленно
  • Преобразование отдельного TableViewController и ViewController в UISplitView
  • iPhone Motion - EXC BAD ACCESS
  • Методы протокола IOS AWS с параметром Error в качестве параметра заставляют протокол не соответствовать
  • Как реализовать NSCoding для свойств и ivars автоматически
  • UISplitView, получение семантических вопросов при настройке делегатов
  • Невозможно изменить цвет текста UIButton в методе делегата
  • Давайте будем гением компьютера.