如何用Swift保存远程图像?

我试图用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 } } } 

要回答你的主要问题,你正在调用错误的UIImage初始值设定项。 你应该在UIImage(contentsOfFile: imagePath) 2中调用UIImage(contentsOfFile: imagePath)在Swift 3中调用UIImage(contentsOfFile: imagePath)

另外,它看起来像你正在尝试在dispatch_async (或Swift 3中的DispatchQueue )的背景下进行远程获取,但是你将它传递给主队列,所以你实际上阻止了主/ UI线程。 您应该将其分派到其中一个后台队列,然后在您实际在UI中设置图像时将其派送回主队列:

Swift 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 } } 

Swift 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 } } 

@罗布的答案重新:获取您的远程图像,并保存是真正的最好的方式来做到这一点。

你的代码调用NSData(contentsOfURL:) (现在称为Data(contentsOf:) )到主队列。 如果您打算使用该同步方法来请求远程映像,则应在后台队列上执行此操作。

另外,你正在使用NSData ,将其转换为UIImage ,然后使用UIImageJPEGRepresentation将其转换回NSData 。 不要通过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 。)我还要检查响应的statusCode 。 例如:

 func requestImage(_ url: URL, fileURL: URL) { let task = URLSession.shared.dataTask(with: url) { data, response, error in // check for fundamental network issues (eg 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() } 

请注意,只有在您尚未创build文件夹的情况下,才需要即时创build文件夹。 就个人而言,当我build立原始path时,我会在那里创build文件夹,而不是在完成处理程序中,但是您可以以任何方式执行此操作。 在写入文件之前,确保文件夹已经存在。

无论如何,希望这可以说明要点,即您应该保存原始资产,并且您应该在后台执行此操作。

对于Swift 2演绎,请参阅此答案的以前版本 。