【问题标题】:Swift 3: Display Image from URLSwift 3:从 URL 显示图像
【发布时间】:2017-02-10 07:54:03
【问题描述】:

在 Swift 3 中,我试图从互联网上捕获图像,并使用以下代码行:

var catPictureURL = NSURL(fileURLWithPath: "http://i.imgur.com/w5rkSIj.jpg")
var catPictureData = NSData(contentsOf: catPictureURL as URL) // nil
var catPicture = UIImage(data: catPictureData as! Data)

我在这里做错了什么?

【问题讨论】:

  • 第二行返回 nil。
  • 为什么不直接在第一行使用 URL 而不是使用 NSURL 只是为了稍后转换它?
  • 我没有正确看到您之前尝试执行的操作。我现在就写一个正确的答案。

标签: swift3


【解决方案1】:

您的代码存在一些问题:

  1. 您使用了大量的强制转换,这不是必需的。
  2. 您将您的 URL 视为本地文件 URL,但事实并非如此。
  3. 您永远不会下载图片使用的 URL。

我们要做的第一件事是将你的变量声明为let,因为我们以后不会修改它。

let catPictureURL = URL(string: "http://i.imgur.com/w5rkSIj.jpg")! // We can force unwrap because we are 100% certain the constructor will not return nil in this case.

然后我们需要下载该 URL 的内容。我们可以使用URLSession 对象来做到这一点。当调用完成处理程序时,我们会从网上下载一个UIImage

// Creating a session object with the default configuration.
// You can read more about it here https://developer.apple.com/reference/foundation/urlsessionconfiguration
let session = URLSession(configuration: .default)

// Define a download task. The download task will download the contents of the URL as a Data object and then you can do what you wish with that data.
let downloadPicTask = session.dataTask(with: catPictureURL) { (data, response, error) in
    // The download has finished.
    if let e = error {
        print("Error downloading cat picture: \(e)")
    } else {
        // No errors found.
        // It would be weird if we didn't have a response, so check for that too.
        if let res = response as? HTTPURLResponse {
            print("Downloaded cat picture with response code \(res.statusCode)")
            if let imageData = data {
                // Finally convert that Data into an image and do what you wish with it.
                let image = UIImage(data: imageData)
                // Do something with your image.
            } else {
                print("Couldn't get image: Image is nil")
            }
        } else {
            print("Couldn't get response code for some reason")
        }
    }
}

最后你需要在下载任务上调用resume,否则你的任务永远不会启动:

downloadPicTask.resume().

所有这些代码一开始可能看起来有点吓人,但 URLSession API 是基于块的,因此它们可以异步工作 - 如果您将 UI 线程阻塞几秒钟,操作系统将终止您的应用。

您的完整代码应如下所示:

let catPictureURL = URL(string: "http://i.imgur.com/w5rkSIj.jpg")!

// Creating a session object with the default configuration.
// You can read more about it here https://developer.apple.com/reference/foundation/urlsessionconfiguration
let session = URLSession(configuration: .default)

// Define a download task. The download task will download the contents of the URL as a Data object and then you can do what you wish with that data.
let downloadPicTask = session.dataTask(with: catPictureURL) { (data, response, error) in
    // The download has finished.
    if let e = error {
        print("Error downloading cat picture: \(e)")
    } else {
        // No errors found.
        // It would be weird if we didn't have a response, so check for that too.
        if let res = response as? HTTPURLResponse {
            print("Downloaded cat picture with response code \(res.statusCode)")
            if let imageData = data {
                // Finally convert that Data into an image and do what you wish with it.
                let image = UIImage(data: imageData)
                // Do something with your image.
            } else {
                print("Couldn't get image: Image is nil")
            }
        } else {
            print("Couldn't get response code for some reason")
        }
    }
}

downloadPicTask.resume()

【讨论】:

  • 天哪,这就是我试图最终到达的地方;你的反应比我预期的要多。这给了我一个巨大的起点。非常非常感谢您的帮助!
【解决方案2】:
let url = URL(string: "http://i.imgur.com/w5rkSIj.jpg")
let data = try? Data(contentsOf: url)

if let imageData = data {
    let image = UIImage(data: imageData)
}

【讨论】:

  • data!
  • 这对我有用!
【解决方案3】:

您也可以使用 Alamofire\AlmofireImage 来完成该任务: https://github.com/Alamofire/AlamofireImage

代码应该看起来像这样(基于上面链接上的第一个示例):

import AlamofireImage

Alamofire.request("http://i.imgur.com/w5rkSIj.jpg").responseImage { response in
    if let catPicture = response.result.value {
        print("image downloaded: \(image)")
    }
}

虽然它既整洁又安全,但您应该考虑是否值得 Pod 开销。 如果您要使用更多图像并想添加过滤器和转换,我会考虑使用 AlamofireImage

【讨论】:

  • 那么如何将该图像保存到文件中?
【解决方案4】:

使用此扩展程序并更快地下载图像。

extension UIImageView {
    public func imageFromURL(urlString: String) {

        let activityIndicator = UIActivityIndicatorView(activityIndicatorStyle: .gray)
        activityIndicator.frame = CGRect.init(x: 0, y: 0, width: self.frame.size.width, height: self.frame.size.height)
        activityIndicator.startAnimating()
        if self.image == nil{
            self.addSubview(activityIndicator)
        }

        URLSession.shared.dataTask(with: NSURL(string: urlString)! as URL, completionHandler: { (data, response, error) -> Void in

            if error != nil {
                print(error ?? "No Error")
                return
            }
            DispatchQueue.main.async(execute: { () -> Void in
                let image = UIImage(data: data!)
                activityIndicator.removeFromSuperview()
                self.image = image
            })

        }).resume()
    }
}

【讨论】:

  • 你是怎么用的!?
  • @Ahmadreza 你这样使用它:yourImageViewOutlet.imageFromURL(urlString: yourUrl)
【解决方案5】:

斯威夫特

通过扩展

扩展本机功能的良好解决方案
import UIKit
    
extension UIImage {
  convenience init?(url: URL?) {
    guard let url = url else { return nil }
            
    do {
      self.init(data: try Data(contentsOf: url))
    } catch {
      print("Cannot load image from url: \(url) with error: \(error)")
      return nil
    }
  }
}

用法

便利初始化程序是失败的,并接受可选的URL - 方法是安全的。

imageView.image = UIImage(url: URL(string: "some_url.png"))

【讨论】:

  • tableview中有大量数据(即1000、2000等)时使用安全吗?
  • @PratyushPratik 这种方法与表格视图没有任何直接关系,因此您可以使用,但我不推荐。对于表视图流,您需要使用操作(用于取消)和预取。
【解决方案6】:

Swift 3 上使用 Alamofire 对我很有帮助:

第 1 步:

使用 pod 进行集成。

pod 'Alamofire', '~> 4.4'

pod 'AlamofireImage', '~> 3.3'

第 2 步:

导入 AlamofireImage

导入 Alamofire

第 3 步:

Alamofire.request("https://httpbin.org/image/png").responseImage { response in

if let image = response.result.value {
    print("image downloaded: \(image)")
self.myImageview.image = image
}
}

【讨论】:

    【解决方案7】:

    我认为最简单的方法是使用 SDWebImage

    将此添加到您的 pod 文件中

      pod 'SDWebImage', '~> 4.0'
    

    运行 pod 安装

    现在导入 SDWebImage

          import SDWebImage
    

    现在从 url 设置图像

        imageView.sd_setImage(with: URL(string: "http://www.domain/path/to/image.jpg"), placeholderImage: UIImage(named: "placeholder.png"))
    

    它会显示占位符图像,但是当下载图像时,它会显示来自 url 的图像。您的应用永远不会崩溃

    这是 SDWebImage 的主要特点

    为 UIImageView、UIButton、MKAnnotationView 添加网页图片和缓存管理的类别

    异步图片下载器

    具有自动缓存过期处理的异步内存 + 磁盘映像缓存

    背景图片解压

    保证不会多次下载同一个网址

    保证不会一次又一次地重试虚假网址

    保证主线程永远不会被阻塞 表演!

    使用 GCD 和 ARC

    了解更多https://github.com/rs/SDWebImage

    【讨论】:

      【解决方案8】:

      使用 UIImageView 的扩展来加载 URL 图片。

      let imageCache = NSCache<NSString, UIImage>()
      
      extension UIImageView {
      
          func imageURLLoad(url: URL) {
      
              DispatchQueue.global().async { [weak self] in
                  func setImage(image:UIImage?) {
                      DispatchQueue.main.async {
                          self?.image = image
                      }
                  }
                  let urlToString = url.absoluteString as NSString
                  if let cachedImage = imageCache.object(forKey: urlToString) {
                      setImage(image: cachedImage)
                  } else if let data = try? Data(contentsOf: url), let image = UIImage(data: data) {
                      DispatchQueue.main.async {
                          imageCache.setObject(image, forKey: urlToString)
                          setImage(image: image)
                      }
                  }else {
                      setImage(image: nil)
                  }
              }
          }
      }
      

      【讨论】:

        【解决方案9】:
        let url = ("https://firebasestorage.googleapis.com/v0/b/qualityaudit-678a4.appspot.com/o/profile_images%2FBFA28EDD-9E15-4CC3-9AF8-496B91E74A11.png?alt=media&token=b4518b07-2147-48e5-93fb-3de2b768412d")
        
        
        self.myactivityindecator.startAnimating()
        
        let urlString = url
            guard let url = URL(string: urlString) else { return }
            URLSession.shared.dataTask(with: url)
        
        
        {
        (data, response, error) in
                if error != nil {
                    print("Failed fetching image:", error!)
                    return
                }
        
                guard let response = response as? HTTPURLResponse, response.statusCode == 200 else {
                    print("error")
                    return
                }
        
                DispatchQueue.main.async {
                    let image = UIImage(data: data!)
                let myimageview = UIImageView(image: image)
                    print(myimageview)
                    self.imgdata.image = myimageview.image
        self.myactivityindecator.stopanimating()
        
             }
          }.resume()
        

        【讨论】:

          【解决方案10】:

          我使用 AlamofireImage,它适用于 ImageView 中的 Loading url,它也有 Placeholder 选项.

          func setImage (){
          
            let image = “https : //i.imgur.com/w5rkSIj.jpg”
            if let url = URL (string: image)
            {
              //Placeholder Image which was in your Local(Assets)
              let image = UIImage (named: “PlacehoderImageName”)
              imageViewName.af_setImage (withURL: url, placeholderImage: image)
            }
          
          }
          

          注意:- 不要忘记在你的 Pod 文件和 Import Statment 中添加 AlamofireImage

          举例,

          pod 'AlamofireImage' 在您的 PodFile 和 ViewController 中 import AlamofireImage

          【讨论】:

            猜你喜欢
            • 2022-07-05
            • 2019-04-14
            • 2014-07-23
            • 2021-09-07
            • 1970-01-01
            • 2017-10-09
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多