我想从我的应用程序中的URL加载图像,所以我首先尝试了Objective-C和它的工作,但是,与Swift,我有一个编译错误:
'imageWithData'不可用:使用对象构造'UIImage(data:)'
我的函数:
@IBOutlet var imageView : UIImageView
override func viewDidLoad() {
super.viewDidLoad()
var url:NSURL = NSURL.URLWithString("http://myURL/ios8.png")
var data:NSData = NSData.dataWithContentsOfURL(url, options: nil, error: nil)
imageView.image = UIImage.imageWithData(data)// Error here
}
在objective - c中:
- (void)viewDidLoad {
[super viewDidLoad];
NSURL *url = [NSURL URLWithString:(@"http://myURL/ios8.png")];
NSData *data = [NSData dataWithContentsOfURL:url];
_imageView.image = [UIImage imageWithData: data];
_labelURL.text = @"http://www.quentinroussat.fr/assets/img/iOS%20icon's%20Style/ios8.png";
}
有人能解释一下为什么imageWithData:不能与Swift一起工作,我该如何解决这个问题。
斯威夫特4
这个方法将从一个网站异步下载图像并缓存它:
func getImageFromWeb(_ urlString: String, closure: @escaping (UIImage?) -> ()) {
guard let url = URL(string: urlString) else {
return closure(nil)
}
let task = URLSession(configuration: .default).dataTask(with: url) { (data, response, error) in
guard error == nil else {
print("error: \(String(describing: error))")
return closure(nil)
}
guard response != nil else {
print("no response")
return closure(nil)
}
guard data != nil else {
print("no data")
return closure(nil)
}
DispatchQueue.main.async {
closure(UIImage(data: data!))
}
}; task.resume()
}
在使用:
getImageFromWeb("http://www.apple.com/euro/ios/ios8/a/generic/images/og.png") { (image) in
if let image = image {
let imageView = UIImageView(frame: CGRect(x: 0, y: 0, width: 200, height: 200))
imageView.image = image
self.view.addSubview(imageView)
} // if you use an Else statement, it will be in background
}
Swift 2带有错误句柄和自定义请求头
简单地添加扩展到UIImageView:
extension UIImageView {
public func imageFromUrl(urlString: String) {
if let url = NSURL(string: urlString) {
let request = NSMutableURLRequest(URL: url)
request.setValue("<YOUR_HEADER_VALUE>", forHTTPHeaderField: "<YOUR_HEADER_KEY>")
NSURLSession.sharedSession().dataTaskWithRequest(request) {
(data, response, error) in
guard let data = data where error == nil else{
NSLog("Image download error: \(error)")
return
}
if let httpResponse = response as? NSHTTPURLResponse{
if httpResponse.statusCode > 400 {
let errorMsg = NSString(data: data, encoding: NSUTF8StringEncoding)
NSLog("Image download error, statusCode: \(httpResponse.statusCode), error: \(errorMsg!)")
return
}
}
dispatch_async(dispatch_get_main_queue(), {
NSLog("Image download success")
self.image = UIImage(data: data)
})
}.resume()
}
}
}
然后,使用新的imageFromUrl(urlString: String)下载图像
用法:
imageView.imageFromUrl("https://i.imgur.com/ONaprQV.png")
您可以使用pod SDWebImage来实现相同的功能。它很容易使用。你可以在SDWebImage这里获得文档
下面是示例代码
self.yourImage.sd_setImage(with: NSURL(string: StrUrl as String ) as URL!, placeholderImage: placeholderImage, options: SDWebImageOptions(rawValue: 0), completed: { (image, error, cacheType, imageURL) in
if( error != nil)
{
print("Error while displaying image" , (error?.localizedDescription)! as String)
}
})
(Swift 4更新)
为了直接回答最初的问题,下面是发布的Objective-C代码片段的快速等效版本。
let url = URL(string: image.url)
let data = try? Data(contentsOf: url!) //make sure your image in this url does exist, otherwise unwrap in a if let check / try-catch
imageView.image = UIImage(data: data!)
免责声明:
需要注意的是,Data(contentsOf:)方法将在执行代码的同一线程中同步下载url的内容,因此不要在应用程序的主线程中调用此方法。
让相同的代码异步运行,而不阻塞UI的简单方法是使用GCD:
let url = URL(string: image.url)
DispatchQueue.global().async {
let data = try? Data(contentsOf: url!) //make sure your image in this url does exist, otherwise unwrap in a if let check / try-catch
DispatchQueue.main.async {
imageView.image = UIImage(data: data!)
}
}
也就是说,在现实生活中的应用程序中,如果您希望获得最佳的用户体验并避免同一映像的多次下载,您可能还希望不仅下载它们,而且缓存它们。已经有相当多的库可以无缝地做到这一点,而且它们都非常易于使用。我个人推荐翠鸟:
import Kingfisher
let url = URL(string: "url_of_your_image")
// this downloads the image asynchronously if it's not cached yet
imageView.kf.setImage(with: url)
就是这样
我建议使用Kingfisher库来异步下载图像。使用翠鸟最好的部分是,它默认缓存所有下载的图像,图像url作为id。下次当您请求下载具有特定URl的图像时,它将从缓存中加载它。
用法:
newsImage.kf.setImage(with: imageUrl!, placeholder: nil, options: nil, progressBlock: nil, completionHandler: { (image, error, cacheType, imageUrl) in
if error == nil{
self.activityIndicator.stopAnimating()
}else if error != nil{
self.activityIndicator.stopAnimating()
}
})