-1

我最近遇到了 Alamofire 的问题(更普遍的是异步调用)

我有两个模型,列表和用户。Listings 包含用户的电子邮件,我还想获取用户的名字和姓氏(我知道我也可以在后端解决这个问题,但是,我想看看是否有前端解决方案,因为这个问题出现了对于更复杂的事情也是如此)

目前,我正在发出 GET 请求以获取所有列表,并且正在循环它们,并发出另一个 GET 请求以获取名字、姓氏。我需要等待获取此获取请求的结果,或者至少将其附加到我的列表字典中。同样,在我做任何其他事情之前(转到我的应用程序的下一个屏幕),我希望将所有列表链接到一个名字、姓氏。因为有一个循环,这似乎特别会导致一些问题(即,如果它只是两个嵌套的 GET 请求,它可能在回调中)。有没有一种简单的方法来解决这个问题。我在下面附上了伪代码:

GET Request to grab listings:
  for each listing:
    GET request to grab first_name, last_name

Once all listings have gotten first_name, last_name -> Load next page
4

3 回答 3

0

使用 Scala 风格的期货和承诺,您可以执行以下操作:

let future: Future<[Listing]> = fetchListings().flatMap { listings in
    listings.traverse { listing in
        fetchUser(listing.userId).map { user in
            listing.userName = "\(user.firstName) \(user.lastName)"
            return listing
        }
    }
}

上述表达式的结果是一个未来,其值是一个列表数组。

完成上述表达式后,打印列表的用户名:

future.onSuccess { listings in
    listings.forEach {
        print($0.userName)
    }
}

Scala 风格的 future 和 promise 库: BrightFuturesFutureLib

下面是一个即用型代码示例,您可以将其粘贴到 Playgrounds 文件中以试验上述任何库(在 FutureLib 中工作,BrightFutures 可能需要稍作修改)。

import FutureLib
import Foundation
import XCPlayground
XCPlaygroundPage.currentPage.needsIndefiniteExecution = true


class Listing  {
    let userId: Int
    init(userId: Int) {
        self.userId = userId
        userName = ""
    }

    var userName: String
}

struct User {
    let id: Int
    let firstName: String
    let lastName: String
    init (_ id: Int, firstName: String, lastName: String) {
        self.id = id
        self.firstName = firstName
        self.lastName = lastName
    }
}

func fetchListings() -> Future<[Listing]> {
    NSLog("start fetching listings...")
    return Promise.resolveAfter(1.0) {
        NSLog("finished fetching listings.")
        return (1...10).map { Listing(userId: $0) }
        }.future!
}

// Given a user ID, fetch a user:
func fetchUser(id: Int) -> Future<User> {
    NSLog("start fetching user[\(id)]...")
    return Promise.resolveAfter(1.0) {
        NSLog("finished fetching user[\(id)].")
        return User(id, firstName: "first\(id)", lastName: "last\(id)")
        }.future!
}


let future: Future<[Listing]> = fetchListings().flatMap { listings in
    listings.traverse { listing in
        fetchUser(listing.userId).map { user in
            listing.userName = "\(user.firstName) \(user.lastName)"
            return listing
        }
    }
}

future.onSuccess { listings in
    listings.forEach {
        print($0.userName)
    }
}
于 2016-01-01T13:32:06.543 回答
0

您的问题的答案称为dispatch group

只有当调度组中当前没有代码时,才能进入和离开调度组以执行某些代码。

GET Request to grab listings{
  var downloadGroup = dispatch_group_create() 
//Create a dispatch group

  for each listing{
    dispatch_group_enter(downloadGroup)
//Enter the dispatch group
    GET request to grab first_name, last_name (Async){
      dispatch_group_leave(downloadGroup)
//Leave the dispatch group
    }
  }

  dispatch_group_notify(downloadGroup, dispatch_get_main_queue()) {
//Run this code when all GET requests are finished
  }
}

如这段代码所示。

关于调度的来源和有趣的阅读材料:Ray Wenderlich 的Grand Central Dispatch Tutorial for Swift

于 2015-12-30T11:16:26.373 回答
-2

这是一个可能的解决方案:

GET Request to grab listings:
  var n = the number of listings
  var i = 0 //the number of retrieved
  for each listing:
    GET request to grab first_name, last_name, callback: function(response){
      assign first/last name using response.
      i+=1
      if(i==n)
        load_next_page()
   }

因此,它的作用是记录您获取了多少名/姓记录。确保您处理获取名称的调用失败的情况。

或者,正如对该问题的评论中所建议的,您可以使用承诺。他们使这样的异步代码变得更好。

于 2015-12-30T09:05:37.500 回答