如何在Swift中构造多个HTTP请求?

弗雷德·弗林斯通

我对Swift和编程完全陌生。我非常热衷于学习所有正确的方法。因此,任何其他提示或评论总是感激不尽。

我正在对api进行HTTP请求,效果很好。问题在于每个请求最多只能有100个结果。我可以设置一个可选的偏移量和一个限制。如果我给出的限制为101,则会收到服务器错误消息:“错误的请求:为限制指定了无效的值。最大允许值为100。” 总数是101,所以我需要至少执行两个请求。仅在收到所有请求的总数据后,我才想填充表格视图。这就是我所拥有的:

class Book {

var id: Int
var title: String
let description: String
var coverImage: String
var isbn: String
var publisherID: Int
var publisherName: String
var authorID: Int
var authorFirstName: String
var authorLastName: String

class func getDataFromJson(completionHandler: ([Book]) -> ()) {

    var books = [Book]()

    let session = NSURLSession(configuration: NSURLSessionConfiguration.defaultSessionConfiguration())

    let request = NSURLRequest(URL: NSURL(string: "http://example.website.nl/books/highlighted")!)

    let task: NSURLSessionDataTask = session.dataTaskWithRequest(request) { (data, response, error) -> Void in

        if let data = data {

            do {
                let json = try NSJSONSerialization.JSONObjectWithData(data, options: .AllowFragments)

                if let booksFromResult = json["books"] as? [[String: AnyObject]] {
                    for book in booksFromResult {
                        let bookID = book["id"] as! Int
                        let bookTitle = book["title"] as! String
                        let bookDescription = book["description"] as! String
                        let bookCoverImage = book["cover_url"] as! String
                        let bookISBN = book["isbn"] as! String
                        if let bookPublisher = book["publisher"] as? [String: AnyObject] {
                            let bookPublisherID = bookPublisher["id"] as! Int
                            let bookPublisherName = bookPublisher["name"] as! String
                            if let bookAuthor = book["author"] as? [String: AnyObject] {
                                let bookAuthorID = bookAuthor["id"] as! Int
                                let bookAuthorFirstname = bookAuthor["first_name"] as! String
                                let bookAuthorLastName = bookAuthor["last_name"] as! String
                                books.append(Book(id: bookID, title: bookTitle, description: bookDescription, coverImage: bookCoverImage, isbn: bookISBN, publisherID: bookPublisherID, publisherName: bookPublisherName, authorID: bookAuthorID, authorFirstName: bookAuthorFirstname, authorLastName: bookAuthorLastName))
                            }
                        }

                    }
                    print(books.count)

                }
                dispatch_async(dispatch_get_main_queue(),{
                    completionHandler(books)
                })
            } catch {
                print("error serializing JSON: \(error)")
            }

        }
    }
    task.resume()
}




init(id: Int, title: String, description: String, coverImage: String, isbn: String, publisherID: Int, publisherName: String, authorID: Int, authorFirstName: String, authorLastName: String) {

    self.id = id
    self.title = title
    self.description = description
    self.coverImage = coverImage
    self.isbn = isbn
    self.publisherID = publisherID
    self.publisherName = publisherName
    self.authorID = authorID
    self.authorFirstName = authorFirstName
    self.authorLastName = authorLastName
  }
}

我已经尝试解决这个问题超过24小时。我确实在这里和网上搜索了一个示例。我在这里找到的小东西帮不了我。

我的想法是应该怎么做:

  1. 发出第一个请求->将数据存储在某处
  2. 发出第二个请求->将数据添加到存储的数据
  3. 发出最后一个请求->将数据添加到存储的数据
  4. 发送数据以填充tableview。

我应该使用网址数组并对其进行遍历,而不是将数据附加到某个地方吗?

我希望有一个人可以帮助我。我真的很感激。

提前致谢。

汤姆·马格努森

问题的直接答案:

// Heavily based on the video I recommended. Watch it for a great explanation
struct Resource<A>{
    let url: NSURL
    let parse: (NSData) -> [A]?
}

extension Book {

    // You could figure a way to dynamically populate this based on limiting
    static let urls = [NSURL(string: "http://example.website.nl/books/highlighted")!,
                       NSURL(string: "http://example.website.nl/books/highlighted2")!]

    // Creates an array of Requests passing in each url for the url, but the same parse function
    static let requests = urls.map { Resource<Book>(url: $0, parse: Book.parse) }

    // Used by Webservice (from the Resource struct) to parse the data into a Book
    static let parse: (NSData?) -> [Book]? = { data in
        guard let data = data else { return nil }

        guard let json = try? NSJSONSerialization.JSONObjectWithData(data, options: .AllowFragments) else {
            print("Error deserializing json.")
            return nil
        }
        var books: [Book]? = nil
        guard let jsonBooks = json["books"] as? [[String: AnyObject]] else { return nil }
        for jsonBook in jsonBooks {
            guard let book = Book(fromJson: jsonBook) else { continue } // skips nil books from failable initializer, depends on how you want to handle that
            books = books ?? [Book]() // if nil create a new array, if not use the old one
            books!.append(book)
        }
        return books
    }
}

class Webservice {

    // A stands for a generic type. You could add a type called Publisher later and use the same function
    // This adopted from the video I showed you so it's a little more in depth
    func loadAll<A>(resources: [Resource<A>], completion: [A] -> ()) {
        let session = NSURLSession(configuration: NSURLSessionConfiguration.defaultSessionConfiguration())
        var currentRequest = 0 // used to keep track of asynchronous callback order
        var allA = [A]()
        for resource in resources {
            session.dataTaskWithURL(resource.url) { (data, _, _) in
                defer {
                    currentRequest += 1 // marks that we're done with one request

                    // This check ensures that we only call the completion handler
                    // after we're done with the last request
                    if currentRequest == resources.count {
                        completion(allA)
                    }
                }
                guard let data = data else { return }

                // this parse function comes from the resource struct passed in.
                // It converts the data we get back from one request into an array of books.
                guard let manyA = resource.parse(data) else { return }

                // This is the total running tally of books from all our requests.
                allA.appendContentsOf(manyA)
            }
        }
    }
}

class TableViewController: UITableViewController {

    var books = [Book]() {
        didSet { tableView.reloadData() }
    }

    override func viewDidLoad() {
        super.viewDidLoad()

        // Call site
        Webservice().loadAll(Book.requests) { [weak self] (books) in
            dispatch_async(dispatch_get_main_queue()) {
                self?.books.appendContentsOf(books)
            }
        }

    }

    //... all your normal methods for cells and stuff
}

额外的

我为Book基于JSON对象的类创建了一个失败的初始化程序,因此您的类方法不必进行大量的解析。您可能希望您的Book类型为astruct以获取成员初始化程序通过值语义传递

充分利用guard let else控制语句,以免因可选的展开而导致厄运金字塔

defer不管您如何退出范围(避免重复代码),语句对于调用完成处理程序都是很有用的。

强烈推荐这个视频,展示一个Web服务api设计它有点高级,但是它向您展示了一种从Web服务初始化模型对象的好方法。

class Book {

    var id: Int
    var title: String
    let description: String
    var coverImage: String
    var isbn: String
    var publisherID: Int
    var publisherName: String
    var authorID: Int
    var authorFirstName: String
    var authorLastName: String

    init(id: Int, title: String, description: String, coverImage: String, isbn: String, publisherID: Int, publisherName: String, authorID: Int, authorFirstName: String, authorLastName: String) {

        self.id = id
        self.title = title
        self.description = description
        self.coverImage = coverImage
        self.isbn = isbn
        self.publisherID = publisherID
        self.publisherName = publisherName
        self.authorID = authorID
        self.authorFirstName = authorFirstName
        self.authorLastName = authorLastName
    }

    typealias JSONDictionary = [String: AnyObject] // syntactic sugar, makes it clearer

    convenience init?(fromJson json: JSONDictionary) {
        let bookID = json["id"] as! Int
        let bookTitle = json["title"] as! String
        let bookDescription = json["description"] as! String
        let bookCoverImage = json["cover_url"] as! String
        let bookISBN = json["isbn"] as! String

        // I would use guard let else statements here to avoid the pyramid of doom but it's stylistic
        if let bookPublisher = json["publisher"] as? [String: AnyObject] {
            let bookPublisherID = bookPublisher["id"] as! Int
            let bookPublisherName = bookPublisher["name"] as! String
            if let bookAuthor = json["author"] as? [String: AnyObject] {
                let bookAuthorID = bookAuthor["id"] as! Int
                let bookAuthorFirstname = bookAuthor["first_name"] as! String
                let bookAuthorLastName = bookAuthor["last_name"] as! String
                self.init(id: bookID, title: bookTitle, description: bookDescription, coverImage: bookCoverImage, isbn: bookISBN, publisherID: bookPublisherID, publisherName: bookPublisherName, authorID: bookAuthorID, authorFirstName: bookAuthorFirstname, authorLastName: bookAuthorLastName)
                return

            }
        }
        return nil
    }

}

extension Book {

    class func getDataFromJson(completionHandler: ([Book]) -> ()) {

        var books = [Book]()

        let session = NSURLSession(configuration: NSURLSessionConfiguration.defaultSessionConfiguration())

        let request = NSURLRequest(URL: NSURL(string: "http://example.website.nl/books/highlighted")!)

        let task: NSURLSessionDataTask = session.dataTaskWithRequest(request) { (data, response, error) -> Void in

            defer { // no matter how you exit the scope this will be called
                dispatch_async(dispatch_get_main_queue()) {
                    completionHandler(books)
                }
            }

            guard let data = data else { return } // still will call the deferred completion handler

            guard let json = try? NSJSONSerialization.JSONObjectWithData(data, options: .AllowFragments) else {
                print("Error deserializing json.")
                return // still will call the deferred completion handler
            }

            if let jsonBooks = json["books"] as? [[String: AnyObject]] {
                for jsonBook in jsonBooks {
                    guard let book = Book(fromJson: jsonBook) else { continue } // skips nil books from failable initializer, depends on how you want to handle that
                    books.append(book)
                }
                print(books.count)
            }
        }
        task.resume()
        // call the deferred completion handler after leaving scope
    }
}

本文收集自互联网,转载请注明来源。

如有侵权,请联系[email protected] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章

来自分类Dev

如何在Swift中构造多个HTTP请求?

来自分类Dev

如何在Swift / Objective C中从HTTP请求返回数据

来自分类Dev

如何在Swift / Objective C中从HTTP请求返回数据

来自分类Dev

如何在Swift中防止对象构造

来自分类Dev

如何在Python中的单个HTTP POST请求中格式化多个数据?

来自分类Dev

如何在angularjs中限制$ http请求?

来自分类Dev

如何在golang中传递http请求?

来自分类Dev

如何在Telnet中创建HTTP请求

来自分类Dev

如何在http请求中设置边界?

来自分类Dev

如何在Rails中创建HTTP请求?

来自分类Dev

如何在JavaScript中编写HTTP请求?

来自分类Dev

如何在 Laravel 中验证 HTTP 请求

来自分类Dev

如何在Swift中打印请求NSMutableURLRequest

来自分类Dev

如何在iOS Swift中的时间间隔上发送HTTP GET请求?

来自分类Dev

如何在Swift iOS中向php服务器发出HTTP请求

来自分类Dev

如何在Swift中查看来自HTTP GET请求的服务器响应?

来自分类Dev

如何在没有AlamoFire的情况下在Swift 3中同时发出异步HTTP请求

来自分类Dev

如何在Jmeter中同时请求AJAX和HTTP请求

来自分类Dev

如何在Jmeter中与HTTP请求同时请求AJAX

来自分类Dev

如何在Swift 2.0(Xcode 7.2)中进行HTTP请求

来自分类Dev

如何在Swift中应用多个变换

来自分类Dev

如何发出多个http请求?

来自分类Dev

在我的示例中,如何获取多个http请求结果?

来自分类Dev

如何按照收到的顺序从多个请求中获取http响应

来自分类Dev

如何在Swift子类中实现复制构造函数?

来自分类Dev

如何在Swift中完成工厂构造函数?

来自分类Dev

如何在节点 js 中使用请求包禁用多个 http(s) 请求?

来自分类Dev

如何在单个请求中从GitHub复制多个文件

来自分类Dev

如何在PHP中获得对单个Ajax请求的多个响应

Related 相关文章

  1. 1

    如何在Swift中构造多个HTTP请求?

  2. 2

    如何在Swift / Objective C中从HTTP请求返回数据

  3. 3

    如何在Swift / Objective C中从HTTP请求返回数据

  4. 4

    如何在Swift中防止对象构造

  5. 5

    如何在Python中的单个HTTP POST请求中格式化多个数据?

  6. 6

    如何在angularjs中限制$ http请求?

  7. 7

    如何在golang中传递http请求?

  8. 8

    如何在Telnet中创建HTTP请求

  9. 9

    如何在http请求中设置边界?

  10. 10

    如何在Rails中创建HTTP请求?

  11. 11

    如何在JavaScript中编写HTTP请求?

  12. 12

    如何在 Laravel 中验证 HTTP 请求

  13. 13

    如何在Swift中打印请求NSMutableURLRequest

  14. 14

    如何在iOS Swift中的时间间隔上发送HTTP GET请求?

  15. 15

    如何在Swift iOS中向php服务器发出HTTP请求

  16. 16

    如何在Swift中查看来自HTTP GET请求的服务器响应?

  17. 17

    如何在没有AlamoFire的情况下在Swift 3中同时发出异步HTTP请求

  18. 18

    如何在Jmeter中同时请求AJAX和HTTP请求

  19. 19

    如何在Jmeter中与HTTP请求同时请求AJAX

  20. 20

    如何在Swift 2.0(Xcode 7.2)中进行HTTP请求

  21. 21

    如何在Swift中应用多个变换

  22. 22

    如何发出多个http请求?

  23. 23

    在我的示例中,如何获取多个http请求结果?

  24. 24

    如何按照收到的顺序从多个请求中获取http响应

  25. 25

    如何在Swift子类中实现复制构造函数?

  26. 26

    如何在Swift中完成工厂构造函数?

  27. 27

    如何在节点 js 中使用请求包禁用多个 http(s) 请求?

  28. 28

    如何在单个请求中从GitHub复制多个文件

  29. 29

    如何在PHP中获得对单个Ajax请求的多个响应

热门标签

归档