简体   繁体   English

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

[英]How do I get a value from an NSURLSession task into an instance variable?

I have a tableView which I want to fill with a list of items provided by a web service. 我有一个tableView,我想填写一个Web服务提供的项目列表。 The service returns a JSON object with status (success or failure) and shows (an array of strings). 该服务返回具有状态(成功或失败)的JSON对象并显示(字符串数组)。

In viewDidLoad I call the custom method getShowsFromService() 在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"

}

The method receives the JSON object and puts it into a dictionary. 该方法接收JSON对象并将其放入字典中。 Then I want to use that dictionary to call json['shows'] in order to get to the array of shows which I want to store in an instance variable called showsArray. 然后我想使用该字典调用json ['shows']以获取我想要存储在名为showsArray的实例变量中的节目数组。 The idea is to use showsArray in tableView(cellForRowAtIndexPath) in order to fill in the data. 我们的想法是在tableView(cellForRowAtIndexPath)中使用showsArray来填充数据。

The problem is that I can't get the Dictionary into the variable. 问题是我无法将Dictionary放入变量中。 If I try to do it inside the task, I get an error that says I need to call self.showsArray and if I do, the data doesn't go inside the array. 如果我尝试在任务中执行此操作,则会收到一条错误消息,指出我需要调用self.showsArray,如果我这样做,则数据不会进入数组内部。 If I do it outside the task I get an error because it says I'm trying to force unwrap a nil value. 如果我在任务之外执行此操作,则会出现错误,因为它表示我正在尝试强制解包nil值。

How can I get the Dictionary created within the task out into the showsArray var? 如何将在任务中创建的Dictionary输入到showsArray var中?

The dataTaskWithURL method makes an async call, so as soon as you do task.resume() it will jump to the next line, and json["shows"] will return nil as the dictionary is empty at this point. dataTaskWithURL方法进行异步调用,因此只要你执行task.resume(),它就会跳转到下一行,并且json [“shows”]将返回nil,因为此时字典为空。

I would recommend moving that logic to a completion handler somewhere in your class. 我建议将该逻辑移到类中的某个完成处理程序中。 Something along the lines of: 有点像:

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

The snippet above should serve as a guide (I dont have access to a playground atm). 上面的片段应该作为指导(我无法访问游乐场atm)。

Note the following: as soon as the task completes (asynchronously -> different thread) it will call the new function handleResult which will check for errors and if not, it will use the dispatcher to perform your task on the main thread. 请注意以下事项:一旦任务完成(异步 - >不同的线程),它将调用新函数handleResult ,它将检查错误,如果没有,它将使用调度程序在主线程上执行任务。 I'm assuming showsArrays is a class property. 我假设showsArrays是一个类属性。

I hope this helps 我希望这有帮助

EDIT: 编辑:

As soon as you fetch your data you need to reload the table (updated code above). 一旦获取数据,您需要重新加载表(上面的更新代码)。 You can use a refresh control (declare it as a class property). 您可以使用刷新控件(将其声明为类属性)。

var refreshControl: UIRefreshControl!

Then when you finish getting your data you can refresh: 然后,当您完成数据获取后,您可以刷新:

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

This will call your delegate methods to populate the rows and sections. 这将调用您的委托方法来填充行和节。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM