如何从NSURLSession任务获取值到实例变量?

时间:2016-06-22 01:42:02

标签: ios json nsurlsession

我有一个tableView,我想填写一个Web服务提供的项目列表。该服务返回一个状态为(成功或失败)的JSON对象,并显示(一个字符串数组)。

在viewDidLoad中,我调用自定义方法getShowsFromService()

func getShowsFromService() {
    // Send user data to server side
    let myURL = NSURL(string: "https://myurl.com/srvc/shows.php")

    // Create session instance
    let session = NSURLSession.sharedSession()

    var json:NSDictionary = [:]

    // Create the task
    let task = session.dataTaskWithURL(myURL!) {  //.dataTaskWithRequest(request) {
        (data, response, error) in

        guard let data = data else {
            print("Error: \(error!.code)")
            print("\(error!.localizedDescription)")
            return
        }

        do {
            json = try NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions()) as! NSDictionary
        } catch {
            print (error)
        }

        let sts = json["status"] as! NSString
        print("\(sts)")
    }

    // Resume the task so it starts
    task.resume()

    let shows = json["shows"] as! NSArray
    for show in shows {
        let thisshow = show as! String
        showsArray.append(thisshow)
    }

    // Here I get "fatal error: unexpectedly found nil while unwrapping an Optional value"

}

该方法接收JSON对象并将其放入字典中。然后我想使用该字典调用json ['shows']以获取我想要存储在名为showsArray的实例变量中的节目数组。我们的想法是在tableView(cellForRowAtIndexPath)中使用showsArray来填充数据。

问题是我无法将Dictionary放入变量中。如果我尝试在任务中执行此操作,则会收到一条错误消息,指出我需要调用self.showsArray,如果我这样做,则数据不会进入数组内部。如果我在任务之外执行此操作,则会出现错误,因为它表示我正试图强制解包nil值。

如何将在任务中创建的Dictionary输入到showsArray var?

1 个答案:

答案 0 :(得分:0)

dataTaskWithURL方法进行异步调用,因此只要你执行task.resume(),它就会跳转到下一行,并且json [“shows”]将返回nil,因为此时字典为空。

我建议将该逻辑移到您班级某处的完成处理程序中。有点像:

func getShowsFromService() {
    let myURL = NSURL(string: "https://myurl.com/srvc/shows.php")
    let session = NSURLSession.sharedSession()
    let task = session.dataTaskWithURL(myURL!, completionHandler: handleResult)
    task.resume()
}

//-handle your result
func handleResult(data: NSData?, response: NSURLResponse?, error: NSError?) {
    guard let data = data else {
        print("Error: \(error!.code)")
        print("\(error!.localizedDescription)")
        return
    }

    do {
        if let json = try NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions()) as! NSDictionary {
            if let shows = json["shows"] as! NSArray {
                //- this is still in a separate thread
                //- lets go back to the main thread!
                dispatch_async(dispatch_get_main_queue(), {
                    //- this happens in the main thread
                    for show in shows {
                        showsArray.append(show as! String)
                    }
                    //- When we've got our data ready, reload the table
                    self.MyTableView.reloadData()
                    self.refreshControl?.endRefreshing()
                });
            }
        } 
    } catch {
        print (error)
    }
}

上面的代码段应该作为指南(我无法访问游乐场atm)。

请注意以下事项: 一旦任务完成(异步 - >不同的线程),它将调用新函数 handleResult ,它将检查错误,如果没有,它将使用调度程序在主线程上执行任务。我假设showsArrays是一个类属性。

我希望这会有所帮助

修改

一旦获取数据,您需要重新加载表(上面的更新代码)。您可以使用刷新控件(将其声明为类属性)。

var refreshControl: UIRefreshControl!

然后,当您完成数据后,您可以刷新:

self.MyTableView.reloadData()
self.refreshControl?.endRefreshing()

这将调用您的委托方法来填充行和部分。