Swift 3 DispatchQueue.global (загрузка изображений из Firebase и пользовательского интерфейса заморожена)
У меня проблема с этим методом:
func DownloadImages(uid: String, indice: Int) {
DispatchQueue.global(qos: .background).async {
let refBBDD = FIRDatabase.database().reference().child("users").child(uid)
refBBDD.observeSingleEvent(of: .value, with: { snapshot in
let snapshotValue = snapshot.value as? NSDictionary
let profileImageUrl = snapshotValue?.value(forKey: "profileImageUrl") as! String
let storage = FIRStorage.storage()
var reference: FIRStorageReference!
if(profileImageUrl == "") {
return
}
print("before")
reference = storage.reference(forURL: profileImageUrl)
reference.downloadURL { (url, error) in
let data = NSData(contentsOf: url!)
let image = UIImage(data: data! as Data)
print("image yet dowload ")
self.citas[indice].image = image
DispatchQueue.main.async(execute: { () -> Void in
self.tableView.reloadRows(at: [IndexPath(row: indice, section: 0)], with: .none)
//self.tableView.reloadData()
print("image loaded")
})
}
print("after")
})
}
}
Я хочу скачать изображения в фоновом режиме. Я хочу следить за использованием приложения, но пользовательский интерфейс замерз до тех пор, пока методы не входят в reloadRows
Можно ли запустить в режиме истинного фона и могу ли я следовать с помощью приложения?
Программа трассировки:
before
after
before
after
...
before
after
before
after
image yet dowload --> here start UI frozen
image loaded
image yet dowload
image yet dowload
...
image yet dowload
image yet dowload
image loaded
image loaded
...
image loaded
image loaded
image yet dowload ------> here UI is not frozen
image loaded
2 ответа
Проблема вызвана этой строкой: let data = NSData(contentsOf: url!)
, Этот конструктор NSData
следует использовать только для чтения содержимого локального URL-адреса (путь к файлу на устройстве iOS), поскольку это синхронный метод, и, следовательно, если вы вызываете его для загрузки файла с URL-адреса, он будет блокировать пользовательский интерфейс для много времени.
Я никогда не использовал Firebase, но, глядя на документацию, мне кажется, что вы используете неправильный метод для загрузки этого файла. Вы должны использовать func getData(maxSize size: Int64, completion: @escaping (Data?, Error?) -> Void) -> StorageDownloadTask
вместо func downloadURL(completion: @escaping (URL?, Error?) -> Void)
поскольку, как указано в документации, последний только "получает долгоживущий URL-адрес для загрузки с отзывным токеном", но не загружает содержимое самого URL-адреса.
Более того, вам не следует принудительно распаковывать значения в обработчике завершения сетевого запроса. Сетевые запросы часто могут не выполняться по причинам, отличным от программной ошибки, но если вы не обработаете эти ошибки корректно, ваша программа потерпит крах.
Ваша проблема в этой линии let data = NSData(contentsOf: url!)
и давайте теперь посмотрим, что яблоко говорит об этом методе ниже
Не используйте этот синхронный метод для запроса сетевых URL-адресов. Для сетевых URL-адресов этот метод может блокировать текущий поток на десятки секунд в медленной сети, что приводит к ухудшению работы пользователя, а в iOS может привести к прекращению работы вашего приложения.
Таким образом, ясно говорится, что этот метод заблокирует ваш пользовательский интерфейс.