如何使用Swift保存远程图像?

时间:2014-10-09 18:44:57

标签: ios 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
        }
    }
}

2 个答案:

答案 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