我尝试使用Swift显示和保存图像。在第一次点击时,它会在imageview上显示远程图像,在第二次点击时会显示空白的imageview,而不是它应该是首次点击时保存的本地图像。
var paths = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true)[0] as String
var imagePath = paths.stringByAppendingPathComponent("images/\(id)/logo.jpg" )
var checkImage = NSFileManager.defaultManager()
if (checkImage.fileExistsAtPath(imagePath)) {
let getImage = UIImage(contentsOfFile: imagePath)
self.image?.image = getImage
} else {
dispatch_async(dispatch_get_main_queue()) {
let getImage = UIImage(data: NSData(contentsOfURL: NSURL(string: remoteImage)))
UIImageJPEGRepresentation(getImage, 100).writeToFile(imagePath, atomically: true)
self.image?.image = getImage
}
}
编辑:这个对我有用。
var paths = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true)[0] as String
var dirPath = paths.stringByAppendingPathComponent("images/\(id)" )
var imagePath = paths.stringByAppendingPathComponent("images/\(id)/logo.jpg" )
var checkImage = NSFileManager.defaultManager()
if (checkImage.fileExistsAtPath(imagePath)) {
let getImage = UIImage(contentsOfFile: imagePath)
self.image?.image = getImage
} else {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0)) {
checkImage.createDirectoryAtPath(dirPath, withIntermediateDirectories: true, attributes: nil, error: nil)
let getImage = UIImage(data: NSData(contentsOfURL: NSURL(string: remoteImage)))
UIImageJPEGRepresentation(getImage, 100).writeToFile(imagePath, atomically: true)
dispatch_async(dispatch_get_main_queue()) {
self.image?.image = getImage
return
}
}
}
答案 0 :(得分:20)
要回答您的主要问题,您需要拨打错误的UIImage
初始化程序。您应该在swift 2中调用UIImage(contentsOfFile: imagePath)
,在swift 3中调用UIImage(contentsOf: imagePath)
。
此外,您似乎正在尝试使用dispatch_async
(或快速3中的DispatchQueue
)在后台进行远程抓取,但是您将其传递给主要部分队列,所以你实际上用它来阻止主/ UI线程。您应该将其分配给其中一个后台队列,然后在UI中实际设置图像时调度回主队列:
斯威夫特3:
DispatchQueue.global(qos: DispatchQoS.background.qosClass).async {
do {
let data = try Data(contentsOf: URL(string: self.remoteImage)!)
let getImage = UIImage(data: data)
try UIImageJPEGRepresentation(getImage!, 100)?.write(to: imagePath)
DispatchQueue.main.async {
self.image?.image = getImage
return
}
}
catch {
return
}
}
斯威夫特2:
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0)) {
let getImage = UIImage(data: NSData(contentsOfURL: NSURL(string: self.remoteImage)))
UIImageJPEGRepresentation(getImage, 100).writeToFile(imagePath, atomically: true)
dispatch_async(dispatch_get_main_queue()) {
self.image?.image = getImage
return
}
}
@Rob's answer re:获取远程图像并保存它确实是最好的方法。
答案 1 :(得分:10)
您的代码将NSData(contentsOfURL:)
(现在称为Data(contentsOf:)
)发送到主队列。如果您要使用该同步方法请求远程映像,则应在后台队列中执行此操作。
此外,您正在使用NSData
,将其转换为UIImage
,然后使用NSData
将其转换回UIImageJPEGRepresentation
。不要通过UIImageJPEGRepresentation
往返它,因为您将更改原始有效负载并将更改资产的大小。只是确认数据包含图像,然后写出原始NSData
因此,在Swift 3中,您可能希望执行以下操作:
DispatchQueue.global().async {
do {
let data = try Data(contentsOf: URL(string: urlString)!)
if let image = UIImage(data: data) {
try data.write(to: fileURL)
DispatchQueue.main.async {
self.imageView?.image = image
}
}
} catch {
print(error)
}
}
更好的是,您应该使用NSURLSession
,因为您可以更好地诊断问题,可取消等等(并且不要使用已弃用的NSURLConnection
。)我&#39 ; d还要检查响应的statusCode
。例如:
func requestImage(_ url: URL, fileURL: URL) {
let task = URLSession.shared.dataTask(with: url) { data, response, error in
// check for fundamental network issues (e.g. no internet, etc.)
guard let data = data, error == nil else {
print("dataTask error: \(error?.localizedDescription ?? "Unknown error")")
return
}
// make sure web server returned 200 status code (and not 404 for bad URL or whatever)
guard let httpResponse = response as? HTTPURLResponse, 200 ..< 300 ~= httpResponse.statusCode else {
print("Error; Text of response = \(String(data: data, encoding: .utf8) ?? "(Cannot display)")")
return
}
// save image and update UI
if let image = UIImage(data: data) {
do {
// add directory if it doesn't exist
let directory = fileURL.deletingLastPathComponent()
try? FileManager.default.createDirectory(at: directory, withIntermediateDirectories: true)
// save file
try data.write(to: fileURL, options: .atomic)
} catch let fileError {
print(fileError)
}
DispatchQueue.main.async {
print("image = \(image)")
self.imageView?.image = image
}
}
}
task.resume()
}
请注意,只有在您尚未创建文件夹时,才需要及时创建文件夹。就个人而言,当我构建原始路径时,我在那里创建文件夹而不是在完成处理程序中,但您可以以任何您想要的方式执行此操作。在编写文件之前,请确保文件夹存在。
无论如何,希望这说明了要点,即您应该保存原始资产,并且应该在后台执行此操作。
对于Swift 2再现,请参阅previous revision of this answer。