从Alamofire捕获数据

时间:2015-10-14 15:48:54

标签: ios swift asynchronous alamofire

我无法异步从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实例仅在使用请求中的数据进行实例化时才会返回该实例?

2 个答案:

答案 0 :(得分:10)

您遇到的问题是您正在调用异步方法并期望同步返回结果。执行代码后,即使getBook请求完成,GET函数也会完成并返回。

基本上,您有两种选择:

  1. 将您的getBook方法更新为异步,并使用完成块/回调
  2. 返回结果
  3. 等待异步调用完成,阻塞当前线程(只要它不是你阻塞的主线程就可以了),并同步返回结果。
  4. 1。将您的方法更新为异步

    为此,您必须在块/回调函数上返回结果。

    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或类似,并检查是否在调用者函数上设置了bookerror

    要调用该函数,您需要传递一个块来处理响应:

    BookGetter.instance.getBook("bookID") { (book, error) in
       if error != nil {
          // Show UIAlertView with error message (localizedDescription)
          return
       }
       // Update User Interface with the book details
    }
    

    2。等待异步调用完成

    如上所述,只有在后台线程上运行此代码时,这才是个好主意。可以阻止后台线程,但在图形应用程序上阻止主线程永远不会,因为它会冻结用户界面。如果您不知道阻止的含义,请使用选项#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)
     }
}

我希望这对你有所帮助。