dispatch_async中的完成处理程序错误-可选的展开



我遵循了一个使用Dribbble API获取数据的教程。
我被卡住了完成处理程序错误。
我确认shots的元素作为NSDictionary类型是正确的。
这是由并发队列的竞争条件引起的吗?
提前谢谢你。

DribbbleAPI.swift

//
//  DribbbleAPI.swift
//  iShots
//
//  Created by Seo Yoochan on 10/15/15.
//  Copyright © 2015 yoochan. All rights reserved.
//
import Foundation

class DribbbleAPI {
    let accessToken = "6d23de112fd5859e7d5658e6b41eee5f1e76291e3327882017457352c56e61a9"
    func loadShots(completion: ((AnyObject) -> Void)!) {
        let url = "https://api.dribbble.com/v1/shots?access_token=" + accessToken
        let session = NSURLSession.sharedSession()
        let shotsURL = NSURL(string: url)
        let task = session.dataTaskWithURL(shotsURL!) {
            (data, resposne, error) -> Void in
            if error != nil {
              print(error!.localizedDescription)
            } else {
                do {
                    let shotsData = try NSJSONSerialization.JSONObjectWithData(data!, options: .MutableContainers)

                    var shots = [Shot]()
                    for shot in shotsData as! NSArray {
                        let shot = Shot(data: shot as! NSDictionary)
                        shots.append(shot)
                    }
                    if shots.count > 0 {
                        dispatch_async(dispatch_get_global_queue(Int(QOS_CLASS_USER_INITIATED.rawValue), 0)){
                            dispatch_async(dispatch_get_main_queue()){
                                completion(shots) // error here
                            }
                        }
                    }


                } catch {
                }
            }
        }
        task.resume()

    }

}

Shot.swift

//
//  Shot.swift
//  iShots
//
//  Created by Seo Yoochan on 10/15/15.
//  Copyright © 2015 yoochan. All rights reserved.
//
import Foundation
class Shot {
    var id: Int!
    var title: String!
    var description: String!
    var commentCount: Int!
    var likesCount: Int!
    var viewsCount: Int!
    var commentUrl: String!
    var imageUrl: String!
    var imageData: NSData?
    init(data: NSDictionary){
        self.id = data["id"] as! Int
        self.commentCount = data["comments_count"] as! Int
        self.likesCount = data["likes_count"] as! Int
        self.viewsCount = data["views_count"] as! Int
        self.commentUrl = getStringFromJSON(data, key: "comments_url")
        self.title = getStringFromJSON(data, key: "title")
        self.description = getStringFromJSON(data, key: "description")
        let images = data["images"] as! NSDictionary
        self.imageUrl = getStringFromJSON(images, key: "normal")

    }
    func getStringFromJSON(data: NSDictionary, key: String) -> String {
        if let info = data[key] as? String {
           return info
        }
        return ""
    }
}

ViewController.swift

//
//  ViewController.swift
//  iShots
//
//  Created by Seo Yoochan on 10/15/15.
//  Copyright © 2015 yoochan. All rights reserved.
//
import UIKit
class ViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
        let api = DribbbleAPI()
        api.loadShots(nil)
    }
    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }

}

错误日志
fatal error: unexpectedly found nil while unwrapping an Optional value

您通过api.loadShots(nil)调用您的方法,然后在该方法中编写completion(shots),如果completion定义为((AnyObject) -> Void)!nil,这当然不会起作用。

你可能想把代码改成

func loadShots(completion: ((AnyObject) -> Void)?) {
    ...
    if let callback = completion {
        callback(shots)
    }
    ...
}

或者更短一点的

completion?(shots)

或者,如果您希望编码器总是必须提供如下所示的回调,则将可选的全部删除。注意,在这种情况下,编译器将不允许传递nil。

 func loadShots(completion: ((AnyObject) -> Void)) {
    ...
    completion(shots)
    ...
}

你目前在你的代码中使用的是一个隐式unwrapped可选的,这基本上意味着它可以保持nil不时,但如果它需要被解封,它会自动这样做,这将只工作,如果值不是nil。使用隐式展开可选选项会导致开发人员(您)必须更加小心,否则会发生类似崩溃的事情。

你可能需要再次阅读可选选项