我正在尝试创建一个使用Web服务的应用程序从目录中获取一些数据,但我还需要将数据保存到设备中,包括图像,这样做我正在使用 Alamofire用于使用Web服务的和 AlamofireImage 框架。我使用 Realm 框架将生成的对象保存在数据库中,对于图像,我将 UIImage 保存到文件中。
基本上,ViewController有一个显示de数据的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不支持多线程。 它仍然滚动迟滞,但没有第一次那么多。
答案 0 :(得分:1)
所以@Rob给出的正确答案是
DispatchQueue.global().async {
do {
try data.write(to: filename)
}
catch {
print(error)
}
}
但同样重要的是永远不要从异步调用中使用对UITableViewCell的引用(再次使用@Rob)。例如,从代码的异步部分设置单元格值。
cell.imgProfile.image = image
UITableViewCells被重复使用,因此您不知道原始单元格仍在同一索引中使用。对于测试,请快速滚动列表以便加载图像,如果您看到图像出现在错误的单元格中,则会出现重复使用问题。
因此,从异步回调中,您需要确定新图像的单元格索引是否可见,请获取该索引的当前单元格以设置其图像。如果索引不可见,则存储/缓存图像,直到其索引滚动到视图中。此时,它的单元格将使用UITableView.cellForRowAtIndexPath创建,您可以在那里设置图像。