有人可以解释为什么完成返回空数组吗?
功能:
import Foundation
class IMBD{
func searchMovies(searchText:String, completion: (result: [Movies]) -> Void){
var movies = [Movies]()
let replacedMovieTitle = searchText.stringByReplacingOccurrencesOfString(" ", withString: "+")
let URLString = "http://www.omdbapi.com/?s=\(replacedMovieTitle)&y=&r=json"
let URL = NSURL(string: URLString)
let session = NSURLSession.sharedSession()
let task = session.dataTaskWithURL(URL!, completionHandler: {(data, response, error) -> Void in
do{
let jsonData = try NSJSONSerialization.JSONObjectWithData(data!, options: .MutableContainers) as! NSDictionary
if let search = jsonData["Search"] as? [[String : AnyObject]]{
for hit in search{
guard let title = hit["Title"] as? String else{
print("returna title")
return
}
guard let year = hit["Year"] as? String else{
print("returna year")
return
}
guard let imbdID = hit["imdbID"] as? String else{
print("returna imbd")
return
}
guard let poster = hit["Poster"] as? String else{
print("returna poster")
return
}
let movie = Movies(title: title, released: year, poster: poster, imbdID: imbdID)
movies.append(movie)
}
}
}catch{
}
}).resume()
completion(result: movies)
}
}
电话:
imbd.searchMovies(searchtext!, completion: { (result) -> Void in
self.movieList = result
})
答案 0 :(得分:3)
你必须在dataTaskWithURL
闭包内调用你的完成句柄,而不是之后。这是异步运行的,所以如果你在闭包之外调用completion
,它将在异步请求有机会检索任何东西之前被调用。
另外,请记住,此闭包不会在主线程上运行,因此您可能还希望将其分配到主队列(从dataTaskWithURL
内)。
例如:
class IMDB {
func searchMovies(searchText:String, completion: (result: [Movie]?, error: NSError?) -> Void) -> NSURLSessionTask {
var movies = [Movie]()
let allowedCharacters = NSCharacterSet.alphanumericCharacterSet().mutableCopy() as! NSMutableCharacterSet
allowedCharacters.addCharactersInString("-._* ")
let replacedMovieTitle = searchText.stringByAddingPercentEncodingWithAllowedCharacters(allowedCharacters)!
.stringByReplacingOccurrencesOfString(" ", withString: "+")
let URLString = "http://www.omdbapi.com/?s=\(replacedMovieTitle)&y=&r=json"
let URL = NSURL(string: URLString)
let session = NSURLSession.sharedSession()
let task = session.dataTaskWithURL(URL!) { data, response, error in
guard error == nil && data != nil else {
dispatch_async(dispatch_get_main_queue()) {
completion(result: nil, error: error)
}
return
}
do {
let jsonData = try NSJSONSerialization.JSONObjectWithData(data!, options: .MutableContainers) as! NSDictionary
if let search = jsonData["Search"] as? [[String : AnyObject]]{
for hit in search{
guard let title = hit["Title"] as? String else{
print("returna title")
continue
}
guard let year = hit["Year"] as? String else{
print("returna year")
continue
}
guard let imdbID = hit["imdbID"] as? String else{
print("returna imbd")
continue
}
guard let poster = hit["Poster"] as? String else{
print("returna poster")
continue
}
let movie = Movie(title: title, released: year, poster: poster, imdbID: imdbID)
movies.append(movie)
}
}
dispatch_async(dispatch_get_main_queue()) {
completion(result: movies, error: nil)
}
} catch let error as NSError {
dispatch_async(dispatch_get_main_queue()) {
completion(result: nil, error: error)
}
}
}
task.resume()
return task
}
}
上述代码段中的其他一些更改包括:
如果出现基本网络错误(例如远程服务器关闭,无法访问互联网等),请添加guard
在检查guard
值的nil
语句中,而不是执行return
(在这种情况下不会收集更多结果),您可能希望只是continue
(即跳到下一条记录)。您通常会将guard
与return
结合使用,但在这种情况下,continue
可能更合适。
坦率地说,您可能希望更进一步,考虑其中一些是否可选,而不是丢弃整个记录。值得注意的是,如果没有可用的海报,poster
可能会让我感到nil
。也许其他一些也应该是可选的(例如,如果电影还没有发布,可能没有发布日期吗?)。
" imbd"的出现已被" imdb"。
Movies
类已重命名为Movie
(因为每个实例都是一部电影,而不是它们的集合)。
我更改了completion
块以使[Movie]
成为可选项并返回NSError
。没有它,你就没有办法区分"找不到那个名字的标题"并且"呐喊,出了点问题"。
当我们在completion
内调用dataTaskWithURL
闭包时,将searchMovies
调度completion
调用回主队列非常有用,像上面一样。这是因为UI更新必须始终发生在主线程上,并且经常在您编写这样的例程时,您可以更新UI或模型中的结果。
这样做并不总是必要的(您可能希望直接从后台线程调用completion
并让调用searchMovies
的例程手动将内容分配给主线程本身),但我经常发现让这个搜索方法只是将completion
发送回主线程并完成它就很有用。
作为一种惯例,我总是在执行请求时返回NSURLSessionTask
。您现在可能不需要它,但在将来某个日期,您可能希望能够取消正在进行的请求,并且对该任务的引用可能很有用。返回它并没有什么坏处,它可能很有用。
您可能应该百分之百转义您添加到网址的值。值得注意的是,&
或+
字符的存在可能会有问题。请注意,在这种情况下,无论如何,看起来这个网站并没有适当地处理它,但是养成在查询中正确地百分比转义值的习惯是很好的。
就个人而言,我在String
扩展名中保留了这个逃避逻辑的百分比,但我想保持这个简单,所以我把它嵌入到这个方法中,但希望它能说明这个想法。