2016-08-31 7 views
1

私はiOSでかなり新しく、Alamofireを使いたいと思っています。私は次のように頼みたい:すべてのアイテム(私の場合はユーザ)がすでに処理されているときに完了ブロックを呼び出す方法。完了ブロックは延期ブロックであるアラモファイア - どのように完了ブロックを処理するには?

StopsHandler.swift

func requestStopsForUser(user: User, completion: (result: RequestResult, json: JSON?) -> Void) { 
    alamofireManager?.request(.GET, "\(AppSettings.ApiURL)/v1/users/\(user.id)/stops.json", headers: ["Authorization": "Token token=\(user.apiKey)"]).responseJSON { response in 
     switch response.result { 
     case .Success: 
      if let value = response.result.value { 
       completion(result: .Success, json: JSON(value)) 
      } 
     case .Failure(let error): 
      if error.code == NSURLErrorTimedOut { 
       completion(result: .TimedOut, json: nil) 
      } else { 
       completion(result: .ConnectionFailed, json: nil) 
      } 
     } 
    } 
} 

Main.swift

func fetchUsersAndStops(completion: (result: RequestResult) -> Void) { 

    var allStopsToWrite = [[Stop]]() //for each user we have array of stops to write in model 

    requestAllUsers() { result, json in 
     switch result { 
     case .Success: 
      let users = self.usersFromJSON(json) 

      for (i, user) in users.enumerate() { 
       StopsHandler.sharedInstance.requestStopsForUser(user) { result, json in 
        print("i in = \(i)") 
        switch result { 
        case .Success: 
         defer { 
          let isLastUser = (i == users.count - 1) 
          if isLastUser { 
           try! self.realm.write(transactionBlock: { 
            for (index, stopsToWrite) in allStopsToWrite.enumerate() { 
             users[index].stops.appendContentsOf(stopsToWrite) 
             self.realm.add(users[index], update: true) 
            }}, 
            completion: { 
             completion(result: .Success) //I want to call this completion when last user is already handled. 
           }) 
          } 
         } 

         guard let json = json else {return} 
         let stops = StopsHandler.sharedInstance.stopsFromJSON(json) 

         let globalStops = self.realm.objects(Stop) 

         var stopsToWrite = [Stop]() 

         for stop in stops { 
          if globalStops.filter("id = '\(stop.id)'").first == nil { 
           stopsToWrite.append(stop) 
           if let currentUserId = self.currentUser?.id { 
            if currentUserId == user.id { 
             user.loggedIn = true 
            } 
           } 
          } 
         } 
         allStopsToWrite.append(stopsToWrite) 
        case .TimedOut: 
         completion(result: .TimedOut) 
        case .ConnectionFailed: 
         completion(result: .ConnectionFailed) 
        } 
       } 
      } 
     case .TimedOut: 
      completion(result: .TimedOut) 
     case .ConnectionFailed: 
      completion(result: .ConnectionFailed) 
     } 
    } 
} 

私は私のコードはmain_queueに実行されることを想定して、私は(次のような出力をしたいですサーバーに4人のユーザーがいる):

i in = 0 
i in = 1 
i in = 2 
i in = 3 

しかし、突然、私は次のようしている:

i in = 3 
i in = 1 
i in = 2 
i in = 0 

そして、私は理由を知りません。どんな助けも大いにありがとう!前もって感謝します!

+0

あなたは4人のユーザーを持っているので、4回のリクエストを呼び出して、4人のユーザーをすべて取得した後で何かしたいのですか?私はすべてのユーザーを処理した後に何かしたいと思うよ、 – Tj3n

+0

@ Tj3nはいああああああああああああああ –

+0

あなたはあらかじめリクエスト数を持っていますか?あなたはそれを4回呼ぶ必要があるのを知っていますか? – Tj3n

答えて

0

Alamofire.requestメインキューでは実行されません。これはasynchronouslyを実行しますが、.responseJSONはデフォルトでmain queueに戻ってUIを更新できるようになります。したがって、あなたの出力は期待どおりではありません。

ご注文を返品したい場合は、ディスパッチメインキューにリクエストをラップする必要があります。

このような何か:

dispatch_after(dispatch_time(DISPATCH_TIME_NOW, Int64(Double(0.2) * Double(NSEC_PER_SEC))), dispatch_get_main_queue(), { 
    // your code here. 
}) 
0

Alarmofireは非同期メソッドでリクエストを呼び出しています。なぜなら、すべての要求が一度に呼び出されるのに対し、応答時間はすべての要求に対して同じではないからです。

すべてのリクエストを順番に呼び出すには、以前のサービスが完了してからサービスを呼び出すことができます。

同じ問題が発生しているので、dispatch_block_tを使用してシーケンスタスクを実行しました。

- (void)fetchAllUserAndStopWithCompletion:(void(^)(id resultResponse, BOOL isComplete))completion { 

    // Step 1: Define default parameters and limits. 
    __block NSInteger totalNumberOfUser = 4; 
    __block NSInteger currentRequest = 0; 
    __block dispatch_block_t t_request; 

dispatch_block_t request = [^{ 
    // Step 2: Fetch User information for currentRequest id. 
    [UserRequest fetchUserRequestWithId:<UserId or Any Unique Id> 
          successBlock:^(id resultResponse, NSError *error) { 

           currentRequest += 1; 
           // Step 3: Check for remaining request. If request is remaining then call ’t_request()’. 
           if (currentRequest < totalNumberOfUser) { 
            // Request Remaining 
            if (completion) { 
             id response = (!error)?resultResponse:nil; 
             completion(response, NO); 
            } 
            t_request(); 
           } 
           else { 
            // All Request Completed 
            if (completion) { 
             id response = (!error)?resultResponse:nil; 
             completion(response, YES); 
            } 
           } 
          }]; 

} copy]; 

t_request = request; 
request(); 
} 

注:これは、別の通話で各ユーザー情報を取得する場合にのみ役立ちます。単一の呼び出しですべてのユーザー情報を取得した場合、NSSortDescriptorでユーザーを並べ替えるだけで済みます。

シーケンスタスクを実行する際に問題が発生した場合は、下にコメントを残してください。

関連する問題