Xcode UIView.init(frame :) должен использоваться только из основного потока

Я пытаюсь сделать некоторые представления в фоновом потоке, чтобы не влиять на основной поток. Это никогда не было проблемой перед Xcode 9.

DispatchQueue.global(qos: .background).async {
    let customView = UIView(frame: .zero)
    DispatchQueue.main.async {
        self.view.addSubview(customView)
    }
}

UIView.init(frame :) должен использоваться только из основного потока

Эта ошибка возникает во второй строке.

Обновить

Документация Apple UIView самом деле говорит в разделе Threading Considerations:

Манипуляции к пользовательскому интерфейсу приложений должны присутствовать в основном потоке. Таким образом, вы всегда должны вызывать методы класса UIView из кода, запущенного в основном потоке вашего приложения. Единственный раз, когда это может быть не обязательно, необходимо при создании самого объекта вида, но все другие манипуляции должны происходить в основном потоке.

Ответ 1

Xcode 9 имеет новую среду выполнения Main Thread Checker, которая обнаруживает вызов UIKit из фонового потока и генерирует предупреждения.

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

enter image description here

Я попробовал этот код в примере проекта, отладчик остановился из-за проблемы (как и положено), но приложение не зависло.

override func viewDidLoad() {
    super.viewDidLoad()

    DispatchQueue.global().async {
        let v = UIView(frame: .zero)
    }
}

Ответ 2

Вы можете использовать эту функцию

func downloadImage(urlstr: String, imageView: UIImageView) {
    let url = URL(string: urlstr)!
    let task = URLSession.shared.dataTask(with: url) { data, _, _ in
        guard let data = data else { return }
        DispatchQueue.main.async { // Make sure you're on the main thread here
            imageview.image = UIImage(data: data)
        }
    }
    task.resume()
}

Как использовать эту функцию?

downloadImage(urlstr: "imageUrl", imageView: self.myImageView)

Ответ 3

Запись основного потока

Вы можете войти в основной поток следующим образом

      DispatchQueue.main.async { 
         // UIView usage
      }