2015-04-06 150 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() 
    } 
}