2015-04-06 79 views
32

错误是: “致命错误:意外发现零而展开的可选值”如何使用URL显示图像?

我在做的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!) 

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

+0

哪个答案正确?我有同样的问题,但现在不知道要遵循什么答案,因为你没有指定一个! – Engineeroholic

+0

它会根据你正在使用的swift版本而改变...我相信Airspeed Velocity的回答在大多数情况下是最可行的 –

回答

3

尝试写:

if data != nil {} 

代替:

if data!= nil {} 

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

+0

任何类型的NSData,永远不会是零。如果它的数据混淆了,那么如果数据! – storedope

+0

= nil是编译器错误的权利? – ashokdy

2

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

if data != nil { 

} 
57

该错误是最有可能imageURL为零。你是在代码的其他地方给它赋值,还是实际代码中实际上是@IBOutlet?如果你没有给它赋值,它将是零 - 但它的UIImageView!类型意味着它是一个“隐式解包可选”,这意味着编译器不会阻止你使用它,即使它是零,但会崩溃在运行时出现错误。

代码的其余部分是正确的(假设缺少空间之前!=是一个拼写错误不是在你的编译代码),但你会使用if let解开你的自选项目,而不是检查他们对nil,然后使用会更好力展开操作:

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

如果你碰巧使用雨燕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) } 
+0

非常感谢你!我接受了您的建议,并创建了一个由故事板中已建立的ImageView的插座。然后我用你建议的方法1。太棒了!!!谢谢。 –

+0

不客气。如果答案回答了您的问题,您可以点击旁边的复选标记来接受答案。 –

+0

如果我使用'flatMap'并且放入了一个虚拟URL,'UIImage'对象是否为'nil',并且不会导致运行时错误? – ton

1

问题是,在viewDidLoad imageURL UIImageView可能还没有设置。我会使用可选的链接,以防UIImageView的是零

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

我在viewDidLayoutSubviews(设置的UIImageView的形象),此时你确保视图控制器的网点已设置。

我愿意做它的方式是这样的:

@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!) 
    } 
} 
4

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

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

这里是我的代码可以帮助你

Swift 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布尔值如下图 enter image description here

1
NSURL(string: "") 

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

在你的代码中,你正在尝试url!当url的值为零时它将会崩溃。

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

而且我相信,如果你是使用它你的零碰撞将被解决。

+0

如果你想使它重量轻,使用后台线程下载图像。 –

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

斯威夫特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) 

      }   
     } 
+0

这是一个很棒的演示代码,它使用一些技巧将数据强制转换为您需要的最终形式。 – Zmart

1

这是相当大的可能性,你正在使用Alamofire如果是的话它就是这么简单:

imageView.af_setImage(withURL: url) 
2

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

这是它的代码。我已经使用这个,你不需要包括类或其他任何东西。只需使用这个扩展。这非常快。

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