ios 在 Swift 上从 URL 加载/下载图像
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/24231680/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Loading/Downloading image from URL on Swift
提问by QuentR
I'd like to load an image from a URL in my application, so I first tried with Objective-C and it worked, however, with Swift, I've a compilation error:
我想从我的应用程序中的 URL 加载图像,所以我首先尝试使用 Objective-C 并且它工作,但是,使用 Swift,我有一个编译错误:
'imageWithData' is unavailable: use object construction 'UIImage(data:)'
'imageWithData' 不可用:使用对象构造 'UIImage(data:)'
My function:
我的功能:
@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
}
In Objective-C:
在 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";
}
Can someone please explain me why the imageWithData:
doesn't work with Swift, and how can I solve the problem.
有人可以解释一下为什么imageWithData:
Swift 不起作用,我该如何解决这个问题。
回答by Leo Dabus
Xcode 8 or later ? Swift 3 or later
Xcode 8 或更高版本?Swift 3 或更高版本
Synchronously:
同步:
if let filePath = Bundle.main.path(forResource: "imageName", ofType: "jpg"), let image = UIImage(contentsOfFile: filePath) {
imageView.contentMode = .scaleAspectFit
imageView.image = image
}
Asynchronously:
异步:
Create a method with a completion handler to get the image data from your url
创建一个带有完成处理程序的方法以从您的 url 获取图像数据
func getData(from url: URL, completion: @escaping (Data?, URLResponse?, Error?) -> ()) {
URLSession.shared.dataTask(with: url, completionHandler: completion).resume()
}
Create a method to download the image (start the task)
创建下载镜像的方法(启动任务)
func downloadImage(from url: URL) {
print("Download Started")
getData(from: url) { data, response, error in
guard let data = data, error == nil else { return }
print(response?.suggestedFilename ?? url.lastPathComponent)
print("Download Finished")
DispatchQueue.main.async() { [weak self] in
self?.imageView.image = UIImage(data: data)
}
}
}
Usage:
用法:
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
print("Begin of code")
let url = URL(string: "https://cdn.arstechnica.net/wp-content/uploads/2018/06/macOS-Mojave-Dynamic-Wallpaper-transition.jpg")!
downloadImage(from: url)
print("End of code. The image will continue downloading in the background and it will be loaded when it ends.")
}
Extension:
扩展:
extension UIImageView {
func downloaded(from url: URL, contentMode mode: UIViewContentMode = .scaleAspectFit) { // for swift 4.2 syntax just use ===> mode: UIView.ContentMode
contentMode = mode
URLSession.shared.dataTask(with: url) { data, response, error in
guard
let httpURLResponse = response as? HTTPURLResponse, httpURLResponse.statusCode == 200,
let mimeType = response?.mimeType, mimeType.hasPrefix("image"),
let data = data, error == nil,
let image = UIImage(data: data)
else { return }
DispatchQueue.main.async() { [weak self] in
self?.image = image
}
}.resume()
}
func downloaded(from link: String, contentMode mode: UIViewContentMode = .scaleAspectFit) { // for swift 4.2 syntax just use ===> mode: UIView.ContentMode
guard let url = URL(string: link) else { return }
downloaded(from: url, contentMode: mode)
}
}
Usage:
用法:
imageView.downloaded(from: "https://cdn.arstechnica.net/wp-content/uploads/2018/06/macOS-Mojave-Dynamic-Wallpaper-transition.jpg")
回答by Lucas Eduardo
(Swift 4 update)To answer the original question directly, here's the swift equivalent of the posted Objective-C snippet.
(Swift 4 更新)要直接回答原始问题,这里是发布的 Objective-C 代码段的 swift 等效项。
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!)
DISCLAIMER:
免责声明:
It's important to note that the Data(contentsOf:)
method will download the contents of the url synchronouslyin the same thread the code is being executed, so do notinvoke this in the main thread of your application.
需要注意的是,该Data(contentsOf:)
方法将在执行代码的同一线程中同步下载 url 的内容,因此不要在应用程序的主线程中调用它。
An easy way to make the same code run asynchronously, not blocking the UI, is by using GCD:
使相同代码异步运行而不阻塞 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!)
}
}
That said, in real life applications, if you want to have the best User Experience and avoid multiple downloads of the same image, you may want to also have them not only downloaded, but cached. There's already quite a few libraries that does that very seamless and they are all really easy to use. I personally recommend Kingfisher:
也就是说,在现实生活中的应用程序中,如果您想获得最佳用户体验并避免多次下载同一图像,您可能还希望不仅下载它们,而且还缓存它们。已经有很多库可以无缝地做到这一点,而且它们都非常易于使用。我个人推荐翠鸟:
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)
And that's it
就是这样
回答by skywinder
If you just want to load image (Asynchronously!)- just add this small extension to your swift code:
如果您只想加载图像(异步!)- 只需将这个小扩展添加到您的 swift 代码中:
extension UIImageView {
public func imageFromUrl(urlString: String) {
if let url = NSURL(string: urlString) {
let request = NSURLRequest(URL: url)
NSURLConnection.sendAsynchronousRequest(request, queue: NSOperationQueue.mainQueue()) {
(response: NSURLResponse?, data: NSData?, error: NSError?) -> Void in
if let imageData = data as NSData? {
self.image = UIImage(data: imageData)
}
}
}
}
}
And use it this way:
并以这种方式使用它:
myImageView.imageFromUrl("https://robohash.org/123.png")
回答by swiftBoy
Swift 2.2|| Xcode 7.3
斯威夫特 2.2|| Xcode 7.3
I got Amazing results!! with AlamofireImageswift library
我得到了惊人的结果!!使用AlamofireImage快速库
It provides multiple features like:
它提供了多种功能,例如:
- Asynchronouslydownload
- Auto Purging Image Cache if memory warnings happen for the app
- Image URL caching
- Image Caching
- Avoid Duplicate Downloads
- 异步下载
- 如果应用程序发生内存警告,则自动清除图像缓存
- 图片网址缓存
- 图片缓存
- 避免重复下载
and very easy to implement for your app
并且很容易为您的应用实现
Step.1 Install pods
Step.1 安装 Pod
Alamofire 3.3.x
阿拉莫火 3.3.x
pod 'Alamofire'
豆荚“阿拉莫火”
AlamofireImage 2.4.x
AlamofireImage 2.4.x
pod 'AlamofireImage'
吊舱'AlamofireImage'
Step.2 import and Use
Step.2 导入使用
import Alamofire
import AlamofireImage
let downloadURL = NSURL(string: "http://cdn.sstatic.net/Sites/stackoverflow/company/Img/photos/big/6.jpg?v=f4b7c5fee820")!
imageView.af_setImageWithURL(downloadURL)
that's it!! it will take care everything
就是这样!!它会照顾一切
Great thanks to Alamofire guys, for making iDevelopers life easy ;)
非常感谢Alamofire 伙计们,让 iDevelopers 的生活变得轻松;)
回答by Mark Moeykens
Xcode 8? Swift 3
Xcode 8? 斯威夫特 3
Leo Dabus's answer is awesome! I just wanted to provide an all-in-one function solution:
Leo Dabus 的回答很棒!我只是想提供一个多合一的功能解决方案:
let url = URL(string:
"http://www.apple.com/euro/ios/ios8/a/generic/images/og.png")
let task = URLSession.shared.dataTask(with: url!) { data, response, error in
guard let data = data, error == nil else { return }
DispatchQueue.main.async() { // execute on main thread
self.imageView.image = UIImage(data: data)
}
}
task.resume()
回答by datayeah
I wrapped the code of the best answers to the question into a single, reusable class extending UIImageView, so you can directly use asynchronous loading UIImageViews in your storyboard (or create them from code).
我将问题的最佳答案的代码包装到一个扩展 UIImageView 的单个可重用类中,因此您可以直接在故事板中使用异步加载 UIImageViews(或从代码创建它们)。
Here is my class:
这是我的课:
import Foundation
import UIKit
class UIImageViewAsync :UIImageView
{
override init()
{
super.init(frame: CGRect())
}
override init(frame:CGRect)
{
super.init(frame:frame)
}
required init(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
func getDataFromUrl(url:String, completion: ((data: NSData?) -> Void)) {
NSURLSession.sharedSession().dataTaskWithURL(NSURL(string: url)!) { (data, response, error) in
completion(data: NSData(data: data))
}.resume()
}
func downloadImage(url:String){
getDataFromUrl(url) { data in
dispatch_async(dispatch_get_main_queue()) {
self.contentMode = UIViewContentMode.ScaleAspectFill
self.image = UIImage(data: data!)
}
}
}
}
and here is how to use it:
这是如何使用它:
imageView.downloadImage("http://www.image-server.com/myImage.jpg")
回答by Hyman
Swift 4::
斯威夫特 4::
This will shows loader while loading the image. You can use NSCachewhich store image temporarily
这将在加载图像时显示加载器。您可以使用临时存储图像的NSCache
let imageCache = NSCache<NSString, UIImage>()
extension UIImageView {
func loadImageUsingCache(withUrl urlString : String) {
let url = URL(string: urlString)
if url == nil {return}
self.image = nil
// check cached image
if let cachedImage = imageCache.object(forKey: urlString as NSString) {
self.image = cachedImage
return
}
let activityIndicator: UIActivityIndicatorView = UIActivityIndicatorView.init(activityIndicatorStyle: .gray)
addSubview(activityIndicator)
activityIndicator.startAnimating()
activityIndicator.center = self.center
// if not, download image from url
URLSession.shared.dataTask(with: url!, completionHandler: { (data, response, error) in
if error != nil {
print(error!)
return
}
DispatchQueue.main.async {
if let image = UIImage(data: data!) {
imageCache.setObject(image, forKey: urlString as NSString)
self.image = image
activityIndicator.removeFromSuperview()
}
}
}).resume()
}
}
Usage:-
用法:-
truckImageView.loadImageUsingCache(withUrl: currentTruck.logoString)
回答by katopz
FYI : For swift-2.0 Xcode7.0 beta2
仅供参考:对于 swift-2.0 Xcode7.0 beta2
extension UIImageView {
public func imageFromUrl(urlString: String) {
if let url = NSURL(string: urlString) {
let request = NSURLRequest(URL: url)
NSURLConnection.sendAsynchronousRequest(request, queue: NSOperationQueue.mainQueue()) {
(response: NSURLResponse?, data: NSData?, error: NSError?) -> Void in
self.image = UIImage(data: data!)
}
}
}
}
回答by user3763002
let url = NSURL.URLWithString("http://live-wallpaper.net/iphone/img/app/i/p/iphone-4s-wallpapers-mobile-backgrounds-dark_2466f886de3472ef1fa968033f1da3e1_raw_1087fae1932cec8837695934b7eb1250_raw.jpg");
var err: NSError?
var imageData :NSData = NSData.dataWithContentsOfURL(url,options: NSDataReadingOptions.DataReadingMappedIfSafe, error: &err)
var bgImage = UIImage(data:imageData)
回答by Manee ios
swift 3 with error handling
带有错误处理功能的 swift 3
let url = URL(string: arr[indexPath.row] as! String)
if url != nil {
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 {
if data != nil {
cell.imgView.image = UIImage(data:data!)
}else{
cell.imgView.image = UIImage(named: "default.png")
}
}
}
}
With Extension
带扩展
extension UIImageView {
func setCustomImage(_ imgURLString: String?) {
guard let imageURLString = imgURLString else {
self.image = UIImage(named: "default.png")
return
}
DispatchQueue.global().async { [weak self] in
let data = try? Data(contentsOf: URL(string: imageURLString)!)
DispatchQueue.main.async {
self?.image = data != nil ? UIImage(data: data!) : UIImage(named: "default.png")
}
}
}
}
Extension Usage
扩展使用
myImageView. setCustomImage("url")
With Cache support
有缓存支持
let imageCache = NSCache<NSString, UIImage>()
extension UIImageView {
func loadImageUsingCacheWithURLString(_ URLString: String, placeHolder: UIImage?) {
self.image = nil
if let cachedImage = imageCache.object(forKey: NSString(string: URLString)) {
self.image = cachedImage
return
}
if let url = URL(string: URLString) {
URLSession.shared.dataTask(with: url, completionHandler: { (data, response, error) in
//print("RESPONSE FROM API: \(response)")
if error != nil {
print("ERROR LOADING IMAGES FROM URL: \(String(describing: error))")
DispatchQueue.main.async { [weak self] in
self?.image = placeHolder
}
return
}
DispatchQueue.main.async { [weak self] in
if let data = data {
if let downloadedImage = UIImage(data: data) {
imageCache.setObject(downloadedImage, forKey: NSString(string: URLString))
self?.image = downloadedImage
}
}
}
}).resume()
}
}
}