【问题标题】:How to display an image using URL?如何使用 URL 显示图像?
【发布时间】:2015-06-10 21:39:28
【问题描述】:

错误是: “致命错误:在展开可选值时意外发现 nil”

我在 ViewController 中执行以下操作:

var imageURL:UIImageView!

override func viewDidLoad() {
    super.viewDidLoad()
    let url = NSURL(string:"http://cdn.businessoffashion.com/site/uploads/2014/09/Karl-Lagerfeld-Self-Portrait-Courtesy.jpg")
    let data = NSData(contentsOfURL:url!)
    if data!= nil {
        imageURL.image = UIImage(data:data!)
    }
}

我真的不明白为什么会报错

imageURL.image = UIImage(data:data!)

虽然我已经告诉它如果数据为零则不要继续。 这不是链接的问题。 “数据”也没有问题。我尝试打印它,它不是零。

【问题讨论】:

  • 哪个答案是正确的?我有同样的问题,但现在不确定要遵循什么答案,因为您没有指定一个!
  • 它会根据您使用的 swift 版本而改变...我相信 Airspeed Velocity 的答案对于大多数情况来说是最可行的

标签: ios swift url


【解决方案1】:

错误很可能是imageURL 为零。您是在代码中的其他地方为其分配了一个值,还是在实际代码中实际上是@IBOutlet?如果你不给它赋值,它将是 nil - 但它的类型 UIImageView! 意味着它是一个“隐式展开的可选”,这意味着即使它是 nil,编译器也不会阻止你使用它,但会在运行时崩溃并出现您遇到的错误。

其余代码是正确的(假设!= 之前缺少的空格是您编译代码中没有的拼写错误),但您最好使用if let 来解开您的选项,而不是对照@987654326 检查它们@ 然后使用 force-unwrap 运算符:

if let url = NSURL(string: "http://etc...") {
    if let data = NSData(contentsOfURL: url) {
        imageURL.image = UIImage(data: data)
    }        
}

如果您碰巧使用的是 Swift 1.2 测试版,您可以将两个 if 组合在一起:

if let url  = NSURL(string: "http://etc..."),
       data = NSData(contentsOfURL: url)
{
        imageURL.image = UIImage(data: data)
}

或者,如果您愿意,可以使用flatMap

imageURL.image =
    NSURL(string: "http://etc...")
    .flatMap { NSData(contentsOfURL: $0) }
    .flatMap { UIImage(data: $0) }

【讨论】:

  • 非常感谢!!我听取了您的建议,并使用情节提要中已建立的 ImageView 创建了一个出口。然后我使用了您建议的方法1。这太棒了!!!谢谢。
  • 不客气。如果某个答案回答了您的问题,您可以点击旁边的复选标记接受它。
  • 如果我使用 flatMap 并输入一个虚拟 URL,UIImage 对象是否会是 nil 并且不会导致运行时错误?
  • 您能帮我异步执行此操作吗?这可行,但我想要异步
【解决方案2】:

这是我的代码可能会对你有所帮助

斯威夫特 2:

extension UIImageView{

    func setImageFromURl(stringImageUrl url: String){

        if let url = NSURL(string: url) {
            if let data = NSData(contentsOfURL: url) {
                self.image = UIImage(data: data)
            }        
        }
    }
}

斯威夫特 3:

extension UIImageView{

func setImageFromURl(stringImageUrl url: String){

      if let url = NSURL(string: url) {
         if let data = NSData(contentsOf: url as URL) {
            self.image = UIImage(data: data as Data)
         }
      }
   }
}

用法

 let imgURL = "https://yourdomain.com/picturepath/picname.png" // or jpg
 self.myImage.setImageFromURl(stringImageUrl: imgURL)

如果你使用的是 HTTP 连接而不是 https,别忘了添加这个

App Transport Security Settings 作为字典,并将 Allow Arbitrary Loads 作为布尔值放入其中,值为 YES,如下图所示

【讨论】:

    【解决方案3】:

    这里我有一种方法,您在下载图像时不会遇到任何类型的崩溃。 现在您正在使用以下代码:

    override func viewDidLoad() {
        super.viewDidLoad()
        let url = NSURL(string:"http://cdn.businessoffashion.com/site/uploads/2014/09/Karl-Lagerfeld-Self-Portrait-Courtesy.jpg")
        let data = NSData(contentsOfURL:url!)
        if data!= nil {
            imageURL.image = UIImage(data:data!)
        }
    }
    

    现在用这个改变代码,如果你继续这个方法:

    override func viewDidLoad() {
        super.viewDidLoad()
        let url = NSURL(string:"http://cdn.businessoffashion.com/site/uploads/2014/09/Karl-Lagerfeld-Self-Portrait-Courtesy.jpg")
        let data = NSData(contentsOfURL:url!) 
    
        // It is the best way to manage nil issue. 
        if data.length > 0 {
            imageURL.image = UIImage(data:data!)
        } else {
            // In this when data is nil or empty then we can assign a placeholder image 
            imageURL.image = UIImage(named: "placeholder.png")
        }
    }
    

    而且我确信如果你使用它,你的 nil 崩溃将得到解决。

    【讨论】:

    • 如果要轻量化,请使用后台线程下载图片。
    【解决方案4】:

    您可以使用 SDWebImage 从 URL 显示图像 https://github.com/rs/SDWebImage

    [cell.imageView sd_setImageWithURL:[NSURL URLWithString:@"http://www.domain.com/path/to/image.jpg"]
                          placeholderImage:[UIImage imageNamed:@"placeholder.png"]];
    

    【讨论】:

      【解决方案5】:

      尝试写作:

      if data != nil {}
      

      改为:

      if data!= nil {}
      

      编译器可能会将感叹号与解包可选值的操作混淆。

      【讨论】:

      • 任何 NSData 类型的东西,都不能为零。
      • 如果它混淆了,那么如果数据! = nil 是编译器错误吧?
      【解决方案6】:

      您可以使用 UIImageView+AFNetworking 在图像视图中设置图像

      首先在项目中拖动 UIImageView+AFNetworking 目标 c 类,然后在项目的桥头文件中导入 UIImageView+AFNetworking.h 类。并使用此行在 imageview 中使用占位符设置图像。这样您就可以在一个视图中设置多个图像而不会卡住。

      yourImageview.setImageWithURL(NSURL(string: self.yourArray.objectAtIndex(indexPath.row).objectForKey("imageurl") as! String), placeholderImage: UIImage(named:"NoUserimage.png"))
      

      【讨论】:

        【解决方案7】:

        Swift 3:(本例中的图像是 64 位二进制数据)

        if let url = NSURL(string: route) {
                    if let imageData = NSData(contentsOf: url as URL) {
                        let str64 = imageData.base64EncodedData(options: .lineLength64Characters)
                        let data: NSData = NSData(base64Encoded: str64 , options: .ignoreUnknownCharacters)!
                        let dataImage = UIImage(data: data as Data)
        
                    }        
                }
        

        【讨论】:

        • 这是一段很棒的演示代码,可以使用一些技巧将数据强制转换为您需要的最终形式。
        【解决方案8】:

        您的代码是正确的,只需使用:

        if data != nil {
        
        }
        

        【讨论】:

          【解决方案9】:

          您使用 Alamofire 的可能性很大,如果是这样,那么它很简单:

          imageView.af_setImage(withURL: url)
          

          【讨论】:

            【解决方案10】:

            问题在于 viewDidLoad 处的 imageURL UIImageView 可能尚未设置。如果 UIImageView 为零,我会使用可选链接

            imageURL?.image = UIImage(data:data!)

            我会在 viewDidLayoutSubviews() 中设置 UIImageView 的图像,此时您确定 ViewController 的 outlets 已设置。

            我的做法是这样的:

            @IBOutlet weak var imageURL: UIImageView!
            var data: NSData?
            
            override func viewDidLoad() {
                super.viewDidLoad()
                let url = NSURL(string:"http://cdn.businessoffashion.com/site/uploads/2014/09/Karl-Lagerfeld-Self-Portrait-Courtesy.jpg")
                data = NSData(contentsOfURL:url!)
                if data != nil {
                    imageURL?.image = UIImage(data:data!)
                }
            }
            
            override func viewDidLayoutSubviews() {
                if data != nil {
                    imageURL.image = UIImage(data:data!)
                }
            }
            

            【讨论】:

              【解决方案11】:
              NSURL(string: "") 
              

              这将返回一个可选值。看看它的描述。它说An NSURL object initialized with URLString. If the URL string was malformed, returns nil.

              在您的代码中,您尝试使用url!,只要 url 的值为 nil,它就会崩溃。

              【讨论】:

                【解决方案12】:

                这是它的代码。我用过这个,你不需要包含类或其他任何东西。只需使用此扩展程序。这是非常快的。

                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()
                    }
                }
                

                【讨论】:

                  【解决方案13】:

                  方法

                  extension UIImage {
                  
                  /// Loads image asynchronously
                  ///
                  /// - Parameters:
                  ///   - url: URL of the image to load
                  ///   - callback: What to do with the image
                  
                  class func loadFromURL(url: NSURL, callback: (UIImage)->()) {
                      dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), {
                  
                          let imageData = NSData(contentsOfURL: url)
                          if let data = imageData {
                              dispatch_async(dispatch_get_main_queue(), {
                                  if let image = UIImage(data: data) {
                                      callback(image)
                                  }
                              })
                          }
                      })
                  }
                  

                  }

                  用法

                      let logoUrl = ImageService().buildImageString((self.uiConfig?.headerImage)!, imageMode: .Uniform, size: self.headerImage.frame.size)
                      UIImage.loadFromURL(logoUrl, callback: { (image: UIImage) -> () in
                          self.headerImage.image = image
                      }) 
                  

                  【讨论】:

                    【解决方案14】:

                    使用 URLSession 和 URLRequest 下载图像和解析 json 的 Swift 3.0。

                    static func getRequest(_ urlString:String, completion:@escaping (Any?) -> ()) {
                        guard let url = URL(string: urlString) else { return }
                        let session = URLSession.shared
                        let request = URLRequest(url: url)
                    
                        let task = session.dataTask(with: request, completionHandler: {
                            (data, response, error) -> Void in
                    
                            if let data = data {
                                do {
                                    let json = try JSONSerialization.jsonObject(with: data, options: [])
                                    completion(json)
                                } catch {
                                    print(error)
                                }
                            }
                        })
                        task.resume()
                    }
                    
                    static func downloadImage(_ url: String, completion:@escaping(UIImage?)->()) {
                        let aUrl = URL(string: url)
                        DispatchQueue.global().async {
                            do {
                                let data = try? Data(contentsOf: aUrl!)
                                completion(UIImage(data: data!))
                            } catch {
                                print("Unable to download image")
                            }
                        }
                    }
                    

                    【讨论】:

                      【解决方案15】:
                       let urlImg = NSURL(string:"https://firebasestorage.googleapis.com/v0/b/fanism-dccfe.appspot.com/o/Heros%2FIMG-20171116-WA0003.png?alt=media&token=b31a6d9e-cea6-422a-b198-82365abd845e")
                      
                          data = NSData.init(contentsOf: urlImg! as URL)
                          if data != nil {
                              imageView?.image = UIImage(data:data! as Data) //**Here imageView our ImageView outlet  **//
                          }                                                                        
                      

                      【讨论】:

                      • 这不是一个好的解决方案。像这样使用 NSData 会阻塞应用程序的主要进程,并会造成延迟和冻结。您应该改用 URLSession.shared.dataTask。
                      • @Moritz。下次我会检查它。
                      【解决方案16】:

                      Swift 4:使用 NSCache 并始终在主线程上运行的小图像(例如:缩略图)的简单加载器:

                      class ImageLoader {
                      
                        private static let cache = NSCache<NSString, NSData>()
                      
                        class func image(for url: URL, completionHandler: @escaping(_ image: UIImage?) -> ()) {
                      
                          DispatchQueue.global(qos: DispatchQoS.QoSClass.background).async {
                      
                            if let data = self.cache.object(forKey: url.absoluteString as NSString) {
                              DispatchQueue.main.async { completionHandler(UIImage(data: data as Data)) }
                              return
                            }
                      
                            guard let data = NSData(contentsOf: url) else {
                              DispatchQueue.main.async { completionHandler(nil) }
                              return
                            }
                      
                            self.cache.setObject(data, forKey: url.absoluteString as NSString)
                            DispatchQueue.main.async { completionHandler(UIImage(data: data as Data)) }
                          }
                        }
                      }
                      

                      【讨论】:

                      猜你喜欢
                      • 1970-01-01
                      • 1970-01-01
                      • 2017-11-20
                      • 1970-01-01
                      • 1970-01-01
                      • 2022-12-11
                      • 2015-03-13
                      • 1970-01-01
                      • 2016-12-19
                      相关资源
                      最近更新 更多