gpt4 book ai didi

ios - 如何使用 Swift 在后台线程中保存文件?

转载 作者:行者123 更新时间:2023-11-28 06:24:04 25 4
gpt4 key购买 nike

我正在尝试制作一个使用 Web 服务从目录中获取一些数据的应用程序,但我还需要将数据保存到设备中,包括图像,为此我正在使用 Alamofire AlamofireImage 框架,用于使用网络服务。我使用 Realm 框架将生成的对象保存在数据库中,对于图像,我将 UIImage 保存到一个文件中。

基本上,ViewController 有一个显示数据的 tableView,但由于图像写入文件,它看起来很慢。

这是我的写作功能:

func saveImage(_ image: UIImage) {
if let data = UIImagePNGRepresentation(image) {
let name = "images/person_directory_\(id).png"
let docsDir = getDocumentsDirectory()
let filename = docsDir.appendingPathComponent(name)
let fm = FileManager.default

if !fm.fileExists(atPath: docsDir.appendingPathComponent("images").path) {
do {
try fm.createDirectory(at: docsDir.appendingPathComponent("images"), withIntermediateDirectories: true, attributes: nil)
try data.write(to: filename)
try! realm?.write {
self.imageLocal = name
}
}
catch {
print(error)
}
}
else {
do {
try data.write(to: filename, options: .atomic)
try! realm?.write {
self.imageLocal = name
}
}
catch {
print(error)
}

}
}
}

我在Alamofire下载图片的时候调用了这个函数

if person.imageLocal != nil,  let image = person.loadLocalImage() {
print("Load form disk: \(person.imageLocal)")
cell.imgProfile.image = image
}
else if !(person.image?.isEmpty)! {
Alamofire.request(person.image!).responseImage(completionHandler: { (response) in
if response.result.isSuccess {
if let image = response.result.value {
person.saveImage(image)
cell.imgProfile.image = image
print("Downloaded: \(person.imageLocal)")
}
}
})
}

但是 tableView 在滚动时看起来很慢,我试图将写入操作放到不同的线程中,这样它就可以在不影响应用程序性能的情况下通过使用 DispatchQeue

进行写入
DispatchQueue.global(qos: .background).async {
do {
try data.write(to: filename)
}
catch {
print(error)
}
}

但即便如此,应用程序仍然滞后。

更新:

我按照 Rob 的建议尝试了这个:

func saveImage(_ image: UIImage) {
if let data = UIImagePNGRepresentation(image) {
let name = "images/person_directory_\(id).png"
do {
try realm?.write {
self.imageLocal = name
}
}
catch {
print("Realm error")
}
DispatchQueue.global().async {
let docsDir = self.getDocumentsDirectory()
let filename = docsDir.appendingPathComponent(name)
let fm = FileManager.default

if !fm.fileExists(atPath: docsDir.appendingPathComponent("images").path) {
do {
try fm.createDirectory(at: docsDir.appendingPathComponent("images"), withIntermediateDirectories: true, attributes: nil)
}
catch {
print(error)
}
}
do {
try data.write(to: filename)
}
catch {
print(error)
}
}
}
}

我无法调度 Realm 编写,因为 Realm 不支持多线程。它仍然滚动滞后,但没有第一次那么多。

最佳答案

所以@Rob 给出的正确答案是

   DispatchQueue.global().async {
do {
try data.write(to: filename)
}
catch {
print(error)
}
}

但同样重要的是永远不要使用异步调用中对 UITableViewCell 的引用(再次归功于@Rob)。例如,从代码的异步部分设置单元格值。

                cell.imgProfile.image = image

UITableViewCells 被重新使用,所以你不知道原来的单元格还在同一个索引处使用。为了进行测试,请非常快速地滚动您的列表以便加载图像,如果您发现图像出现在错误的单元格中,那就是重用问题。

因此,您需要从异步回调中确定新图像的单元格索引是否可见,然后获取该索引的当前单元格以设置它的图像。如果索引不可见,则存储/缓存图像,直到它的索引滚动到 View 中。那时它的单元格将使用 UITableView.cellForRowAtIndexPath 创建,您可以在那里设置图像。

关于ios - 如何使用 Swift 在后台线程中保存文件?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42514554/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com