我无法异步从Alamofire请求中检索数据。
class BookGetter {
static let instance = BookGetter()
func getBook(bookId: String) -> Book {
let rootUrl = "https://www.someusefulbookapi.com/bookid=?"
let url = rootUrl + bookId
var title = ""
Alamofire.request(.GET, url).response { response in
let jsonDict = JSON(data: response.2!)
title = String(jsonDict["items"][0]["volumeInfo"]["title"])
}
let book = Book(title: title)
print(book.title)
return book
}
}
print(book.title)
的输出是""
,我理解这是因为print语句在请求返回之前运行。
如果book
实例仅在使用请求中的数据进行实例化时才会返回该实例?
答案 0 :(得分:10)
您遇到的问题是您正在调用异步方法并期望同步返回结果。执行代码后,即使getBook
请求完成,GET
函数也会完成并返回。
基本上,您有两种选择:
getBook
方法更新为异步,并使用完成块/回调为此,您必须在块/回调函数上返回结果。
class BookGetter {
static let instance = BookGetter()
func getBook(bookId: String, complete: (book: Book?, error: NSError?) -> Void) {
let rootUrl = "https://www.someusefulbookapi.com/bookid=?"
let url = rootUrl + bookId
var title = ""
Alamofire.request(.GET, url).response { request, response, data, error in
// TODO: You should check for network errors here
// and notify the calling function and end-user properly.
if error != nil {
complete(book: nil, error: error as? NSError)
return
}
let jsonDict = JSON(data: response.2!)
title = String(jsonDict["items"][0]["volumeInfo"]["title"])
let book = Book(title: title)
print(book.title)
complete(book: book, error: nil)
}
}
}
如上面的代码所述,理想情况下,您应该处理回调响应中的错误(包括解析JSON时的异常)。处理完毕后,您可以将回调参数更新为(book: Book?, error: NSError?) -> Void
或类似,并检查是否在调用者函数上设置了book
或error
。
要调用该函数,您需要传递一个块来处理响应:
BookGetter.instance.getBook("bookID") { (book, error) in
if error != nil {
// Show UIAlertView with error message (localizedDescription)
return
}
// Update User Interface with the book details
}
如上所述,只有在后台线程上运行此代码时,这才是个好主意。可以阻止后台线程,但在图形应用程序上阻止主线程永远不会,因为它会冻结用户界面。如果您不知道阻止的含义,请使用选项#1。
class BookGetter {
static let instance = BookGetter()
func getBook(bookId: String) -> Book {
let rootUrl = "https://www.someusefulbookapi.com/bookid=?"
let url = rootUrl + bookId
var title = ""
let semaphore = dispatch_semaphore_create(0)
Alamofire.request(.GET, url).response { response in
let jsonDict = JSON(data: response.2!)
title = String(jsonDict["items"][0]["volumeInfo"]["title"])
dispatch_semaphore_signal(semaphore)
}
//Wait for the request to complete
while dispatch_semaphore_wait(semaphore, DISPATCH_TIME_NOW) != 0 {
NSRunLoop.currentRunLoop().runMode(NSDefaultRunLoopMode, beforeDate: NSDate(timeIntervalSinceNow: 10))
}
let book = Book(title: title)
print(book.title)
return book
}
}
答案 1 :(得分:2)
您可以使用闭包并在书中返回completionHandler
,如下所示:
func getBook(bookId: String, completionHandler: (book: Book?) -> ()) {
let rootUrl = "https://www.someusefulbookapi.com/bookid=?"
let url = rootUrl + bookId
Alamofire.request(.GET, url).response { response in completionHandler(
book:
{
// In this block you create the Book object or returns nil in case of error
if response == nil {
return nil
}
let jsonDict = JSON(data: response.2!)
let title = String(jsonDict["items"][0]["volumeInfo"]["title"])
let book = Book(title: title)
return book
}())
}
}
然后您可以通过以下方式调用它:
getBook("idOfYourBook") { book in
if let book = book {
println(book.title)
}
}
我希望这对你有所帮助。