请求completionhandler的数据并不总是被调用

时间:2016-06-03 12:51:14

标签: ios swift nsurlsession nsurl

我正在创建一个应用,您可以在其中搜索API为http://www.omdbapi.com/的电影。

我遇到的问题是dataTaskWithRequest的完成处理程序。如果单击其中一个collectionView单元格,您将转到所选电影的detailView。然而,它并不是一直都在工作。我得到一个错误说:在解开时意外地发现了nil。这是因为它没有进入dataTaskWithRequest的完成处理程序,而是直接进入detailVC并尝试在标题标签,流派标签等中传递数据但是没有数据。

我希望你们知道问题是什么,因为我已经尝试了,但我不知道问题是什么。

或者,这个问题是否因为之前的事情而发生?因为首先我使用"通过搜索"从http://www.omdbapi.com/检索数据。而不是" ID"。从那里我检索ID,并从该ID检索我的detailVC的数据。

这是我的代码:

 // Go to detail view of selected movie
func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath) {

    let selectedMovieId = self.IDs[indexPath.row]

    chosenMovieId = selectedMovieId

    self.performSegueWithIdentifier("showDetail", sender: self)
}

// Preparations before going to the detail view of selected movie
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {

    if segue.identifier == "showDetail" {

        _ = self.movieInfoFrom(searchMovie: chosenMovieId, segue: segue)
    }
}


func movieInfoFrom(searchMovie movieId: String, segue: UIStoryboardSegue) {

    let movieUrlString = "http://www.omdbapi.com/?i=\(movieId)&y=&plot=full&r=json"
    let url = NSURL(string: movieUrlString)
    print(movieUrlString)

    let urlRequest = NSURLRequest(URL: url!)
    let urlSession = NSURLSession(configuration: NSURLSessionConfiguration.defaultSessionConfiguration())

    let urlTask = urlSession.dataTaskWithRequest(urlRequest) { (data, response, error) in

        if error == nil {

            // Convert data to JSON
            let swiftyJSON = JSON(data: data!)

            let title = swiftyJSON["Title"].string!
            let runTime = swiftyJSON["Runtime"].string!
            let genre = swiftyJSON["Genre"].string!
            let plot = swiftyJSON["Plot"].string!
            let rating = swiftyJSON["imdbRating"].string!
            let year = swiftyJSON["Year"].string!
            let poster = swiftyJSON["Poster"].string

            self.infoResult = ["\(title)", "\(runTime)", "\(genre)", "\(plot)", "\(rating)", "\(year)"]
            print("\(self.infoResult)")

            let destinationVC = segue.destinationViewController as! MovieDetailController

            destinationVC.movieDetails = self.infoResult
            destinationVC.moviePoster = poster
        }
    }

    urlTask.resume()
}

2 个答案:

答案 0 :(得分:1)

我尝试修改您的代码并解释一些评论:

func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath) {

    let selectedMovieId = self.IDs[indexPath.row]

    chosenMovieId = selectedMovieId

    self.movieInfoFrom(searchMovie: chosenMovieId)
}

// Preparations before going to the detail view of selected movie
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {

    if segue.identifier == "showDetail" {

        let destinationVC = segue.destinationViewController as! MovieDetailController

            destinationVC.movieDetails = self.infoResult
            destinationVC.moviePoster = poster
    }
}


func movieInfoFrom(searchMovie movieId: String) {

    let movieUrlString = "http://www.omdbapi.com/?i=\(movieId)&y=&plot=full&r=json"
    let url = NSURL(string: movieUrlString)
    print(movieUrlString)

    let urlRequest = NSURLRequest(URL: url!)
    let urlSession = NSURLSession(configuration: NSURLSessionConfiguration.defaultSessionConfiguration())

    // This is asynchronously, you can put a loading here 
    let urlTask = urlSession.dataTaskWithRequest(urlRequest) { (data, response, error) in
        // Got response, stop loading here
        if error == nil {

            // Convert data to JSON
            let swiftyJSON = JSON(data: data!)

            let title = swiftyJSON["Title"].string!
            let runTime = swiftyJSON["Runtime"].string!
            let genre = swiftyJSON["Genre"].string!
            let plot = swiftyJSON["Plot"].string!
            let rating = swiftyJSON["imdbRating"].string!
            let year = swiftyJSON["Year"].string!

            // You can save the poster as local variable
            let poster = swiftyJSON["Poster"].string

            self.infoResult = ["\(title)", "\(runTime)", "\(genre)", "\(plot)", "\(rating)", "\(year)"]
            print("\(self.infoResult)")

            // This should be call on main thread
            dispatch_async(dispatch_get_main_queue()) {
                self.performSegueWithIdentifier("showDetail", sender: self)
            }


        }
    }

    urlTask.resume()
}

答案 1 :(得分:0)

尝试使用安全选项

的此代码
func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath) {

    chosenMovieId = self.IDs[indexPath.row]
    movieInfoFrom(searchMovie: chosenMovieId)

}

func movieInfoFrom(searchMovie movieId: String) {

    let movieUrlString = "http://www.omdbapi.com/?i=\(movieId)&y=&plot=full&r=json"
    let url = NSURL(string: movieUrlString)
    print(movieUrlString)

    let urlRequest = NSURLRequest(URL: url!)
    let urlSession = NSURLSession(configuration: NSURLSessionConfiguration.defaultSessionConfiguration())

    let urlTask = urlSession.dataTaskWithRequest(urlRequest) { (data, response, error) in

        if error == nil && data != nil {

            // Convert data to JSON
            let swiftyJSON = JSON(data: data!)

            let title = swiftyJSON["Title"].string ?? ""
            let runTime = swiftyJSON["Runtime"].string ?? ""
            let genre = swiftyJSON["Genre"].string ?? ""
            let plot = swiftyJSON["Plot"].string ?? ""
            let rating = swiftyJSON["imdbRating"].string ?? ""
            let year = swiftyJSON["Year"].string ?? ""
            let poster = swiftyJSON["Poster"].string

            self.infoResult = ["\(title)", "\(runTime)", "\(genre)", "\(plot)", "\(rating)", "\(year)"]
            print("\(self.infoResult)")

            dispatch_async(dispatch_get_main_queue()) {
                self.performSegueWithIdentifier("showDetail", sender: poster)
            }
        }
    }
    urlTask.resume()
}

override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {

    if segue.identifier == "showDetail", let destinationVC = segue.destinationViewController as? MovieDetailController {

        destinationVC.movieDetails = self.infoResult
        destinationVC.moviePoster = sender as? String
    }
}