如何使用URL显示图像?

时间:2015-04-06 13:20:49

标签: ios swift url

错误是:     “致命错误:在打开可选值时意外发现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!)

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

16 个答案:

答案 0 :(得分:57)

错误很可能是imageURL为零。您是在代码中的其他位置为其分配值,还是在实际代码中实际为@IBOutlet?如果你没有给它赋值,它将是nil - 但它的UIImageView!类型意味着它是一个"隐式解包的可选"这意味着即使编译器为零,编译器也不会阻止你使用它,但是在运行时会因为你得到的错误而崩溃。

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

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

如果您正好使用Swift 1.2测试版,可以将两个ifs组合在一起:

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

答案 1 :(得分:15)

以下是我的代码可能会帮助您

斯威夫特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,如下图所示 enter image description here

答案 2 :(得分:6)

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

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

我相信如果你使用它,你的无故障将会解决。

答案 3 :(得分: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"]];

答案 4 :(得分:3)

尝试写作:

if data != nil {}

代替:

if data!= nil {}

编译器可能会将感叹号与操作混淆,以解开可选值。

答案 5 :(得分:3)

您可以使用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"))

答案 6 :(得分:3)

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)

            }        
        }

答案 7 :(得分:2)

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

if data != nil {

}

答案 8 :(得分:2)

您使用 Alamofire 的可能性非常大,如果是这样,它就像:

imageView.af_setImage(withURL: url)

答案 9 :(得分:2)

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

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

答案 10 :(得分:1)

问题是在viewDidLoad中,imageURL UIImageView可能尚未设置。如果UIImageView为nil,我会使用可选链接

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

我在viewDidLayoutSubviews()处设置了UIImageView的图像,此时您确定已经设置了ViewController的插座。

我这样做的方式如下:

@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 :(得分:1)

NSURL(string: "") 

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

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

答案 12 :(得分:0)

<强>了Methode

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

答案 13 :(得分:0)

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

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

答案 14 :(得分:0)

 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  **//
    }                                                                        

答案 15 :(得分:0)

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