Как скачать изображения асинхронно для WidgetKit

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

В настоящее время виджет загружает массив объектов, и каждый объект имеет URL-адрес изображения. Идея в том, что каждый объект делает SimpleEntry для Timeline.

Как лучше всего этого добиться? Я читал, что виджеты не должны использовать ObservableObject. Я получаю набор объектов в поставщике временной шкалы, что, похоже, рекомендует Apple. Но могу ли я также загрузить туда изображения и дождаться, пока все будет готово, чтобы отправить временную шкалу?

Любые советы были бы очень полезны,


person Joan Cardona    schedule 30.07.2020    source источник


Ответы (2)


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

Для этого я использую группу отправки. Что-то вроде:

let imageRequestGroup = DispatchGroup()
var images: [UIImage] = []
for imageUrl in imageUrls {
    imageRequestGroup.enter()
    yourAsyncUIImageProvider.getImage(fromUrl: imageUrl) { image in
        images.append(image)
        imageRequestGroup.leave()
    }
}
imageRequestGroup.notify(queue: .main) {
    completion(images)
}

Затем я использую инициализатор SwiftUI Image (uiImage :) для отображения изображений.

person bee8ee    schedule 17.09.2020
comment
Это лучшее решение на данный момент. Я использовал SDWebImage в своем виджете, и этот метод надежно работает в iOS, iPadOS и macOS (Catalyst) (хост-приложение, виджет будет родным) - person dezinezync; 02.10.2020
comment
Должны ли мы использовать это внутри getTimeline (для конфигурации ...? И при завершении вызова (временной шкале) внутри него !? - person Ahmadreza; 13.12.2020
comment
@Ahmadreza Да, я так и использую. - person bee8ee; 14.12.2020

У меня нет хорошего решения, но я пытаюсь использовать WidgetCenter.shared.reloadAllTimelines(), и это имеет смысл. В следующем коде.

var downloadImage: UIImage?

func downloadImage(url: URL) -> UIImage {
    
    var picImage: UIImage!
    
    if self.downloadImage == nil {
        
        picImage = UIImage(named: "Default Image")
        
        DispatchQueue.global(qos: .background).async {
            do {
                let data = try Data(contentsOf: url)
                DispatchQueue.main.async {
                    self.downloadImage = UIImage.init(data: data)
                    if self.downloadImage != nil {
                        DispatchQueue.main.async {
                            WidgetCenter.shared.reloadAllTimelines()
                        }
                    }
                }
            } catch { }
        }
    } else {
        picImage = self.downloadImage
    }
    
    return picImage
}

Также вы должны подумать, когда удалить это изображение. Это вроде tableView.reloadData().

person yang lu    schedule 07.09.2020