-1

最近 Alamofire で問題が発生しました (より一般的には非同期呼び出しで)

リストとユーザーの 2 つのモデルがあります。Listings にはユーザーの電子メールが含まれており、ユーザーの姓名も取得したいと考えています (バックエンドでもこれを解決できることは理解していますが、この問題が発生したときにフロントエンドの解決策があるかどうかを確認したいと考えています)。より複雑なものにも)

現在、すべてのリストを取得するために GET リクエストを作成しており、それらをループして、ファーストネーム、ラストネームを取得するために別の GET リクエストを作成しています。この get リクエストの結果を取得するのを待つか、少なくともリスティング ディクショナリに追加する必要があります。同様に、何か他のことをする前に (アプリの次の画面に進みます)、すべてのリストをファーストネーム、ラストネームにリンクさせたいと思います。ループがあるため、これは特にいくつかの問題を引き起こしているようです (つまり、入れ子になった GET 要求が 2 つだけの場合は、コールバックである可能性があります)。これを回避する簡単な方法はありますか。以下に疑似コードを添付しました。

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

あなたの質問に対する答えは、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によるSwift のグランド セントラル ディスパッチ チュートリアル

于 2015-12-30T11:16:26.373 に答える
0

Scala スタイルの future と promise を使用すると、次のようなことができます。

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 ライブラリ: BrightFuturesまたはFutureLib

上記のライブラリのいずれかを試すためにプレイグラウンド ファイルに貼り付けることができる、すぐに使用できるコード例を以下に示します (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 に答える
-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 に答える