2017-12-08 4 views
1

Alamofire 요청이 데이터를 가져 오기까지 기다려야합니다. (오류 또는 값). 나는 Alamofire 함수가 for 루프 안에서 또 다른 함수로 호출되도록하기 때문에 Alamofire 요청은 두 번째 for 루프가 호출되기 전에 끝나야한다. 예를 들어; 첫 번째 루프 -> 첫 번째 요청 -> 두 번째 루프 -> 두 번째 요청 ... 등등. 이제 첫 번째 루프 -> 두 번째 루프 -> 모든 루프가 끝난 후에 요청 응답이 돌고 있습니다.DispatchGroup을 사용한 동기 Alamofire 요청

요청 기능 :

내가 전화
func like(sender_id: String, completion: @escaping (String?) ->()){ 
    let group = DispatchGroup() 
    if let key = api_key{ 
     let headers: HTTPHeaders = [ 
      "X-Auth-Token": key, 
      "Accept": "application/json" 
     ] 
     group.enter() 
     Alamofire.request(baseUrl + likeURL + sender_id, method: .get, parameters: nil, encoding: URLEncoding.default, headers: headers).validate() 
      .responseJSON { (response) -> Void in 
       guard response.result.isSuccess else { 
        print("Error while doing : \(response.result.error)") 
        completion(nil) 
        group.leave() 
        return 
       } 
       if let error = response.error{ 
        completion(nil) 
        group.leave() 
        print("Error Occured with Request: \(error)") 
       } 
       if let jsonData = response.data{ 
        let json = JSON(data: jsonData) 
        print(json) 
        group.leave() 
        if let matched = json["match"].bool{ 
         completion(matched.description) 
         print("Liked!: \(matched)") 
         if(matched){ 
         } 
        }else{ 
         group.leave() 
         "There is an error with JSON" 
        } 
       }} 
    } 
} 

: 당신은 분명히 함수의 끝 부분에있는 그룹에 대한 대기의 목적으로 파견 그룹을 사용하는

func like_all(completion: @escaping() ->()){ 
    for user in SharedUsers.sharedUser.users{ 
     if let id = user.id{ 
      Network.sharedInstance.like(sender_id: id) { result in 
       print(result) 
      } 
     } 
     else{ 
      continue 
     } 
    } 
    completion() 
} 
+0

관련없는, 당신의 완료 처리기에서, 당신은 두 번'leave' 호출하는 실행 경로를 가지고있다. 그걸 고쳐야 해. 또는이 디스패치 그룹 패턴을 유지하는 경우 종료하기 전에 'defer {group.leave()}'를 사용하고 다른 모든 'leave'호출을 꺼내서 위험을 피할 것을 제안합니다. 당신이 '떠나라'고 말하지 않은 처형의 길을 가졌던 것. 솔직히 말해서, 이것은 파견단을 전혀 사용하지 않아야하지만, 단지 FYI입니다. – Rob

+0

나는 promisekit 보였지만 내 문제에 대한 올바른 방법인지 잘 모르겠습니다. –

+0

아래에서는이 작업을 수행하는 방법에 대한 두 가지 방법을 간략히 설명했지만 PromiseKit은이 문제를 해결하는 또 다른 방법입니다. 핵심 아이디어는 다른 비동기 프로세스를 시작하기 전에 비동기 프로세스를 '대기'하고 싶지는 않지만 이전 패턴이 완료 될 때 비동기 적으로 한 요청을 트리거하는 데 이러한 패턴 중 하나를 사용하는 것입니다. 이렇게하면 스레드 차단이 방지되고 교착 상태 위험이 제거됩니다. – Rob

답변

0

. 그러나 당신은 그것을 기다리지 않고 있으므로, 당신이 찾고 있던 동기 동작을 얻지 못하고 있습니다.

메인 스레드에서 wait 그 그룹 (또는 세마포어, 다른 패턴이 동작을 달성하기 위해) 때문에, 당신이 주된 스레드를 막을뿐만 아니라 (그 결과 끔찍한 UX를 초래하고 귀하의 애플 리케이션은 감시 프로세스에 의해 사망), 당신은 교착 상태가 될 것입니다 responseJSON 완료 처리기에 대한 메인 대기열을 사용하기 때문에. 따라서 디스패치 그룹/세마포어에 wait() 호출을 추가하기 전에이 전체 for 루프를 일부 백그라운드 스레드에 비동기 적으로 보내야합니다. 이렇게하면 주 스레드를 차단하지 않고 교착 상태 위험을 제거 할 수 있습니다.

그러나이 전체 패턴은 근본적으로 결함이 있습니다. 실제로는 디스패치 그룹이나 세마포어를 사용하면 안됩니다. 그러면 몇 가지 질문이 제기됩니다.

첫 번째 질문은 동기를 설정하려는 이유입니다. 네트워크 요청에는 내재 된 대기 시간이 있으므로 일련의 작업을 수행하는 것은 매우 느립니다. 꼭 필요한 경우에만이 순서의 요청을 수행하십시오 (예 : 각 요청은 이전 요청의 응답에서 무언가를 필요로하므로 작성할 수 없습니다). 그러나 그것은 여기에있는 것처럼 보이지 않습니다. 그렇다면이 과정을 불필요하게 만드는 이유는 무엇입니까?

하지만 순차적으로 이것을 순차적으로 수행해야한다고 가정 해 봅시다 (여기서는 사실이 아니며 말할 수는 없지만이를 설명해주십시오).

  • 당신은 완전히이 for 루프를 잃고, 단순히 n 번째 요청을 보내고 요청 N + 1을 전송하는 루틴을 할 수 있습니다 : 그리고 동시에 일련의 요청을 수행 연속적보다는 두 가지 패턴이있다 완료 핸들러에서. 따라서 스레드를 차단하기 위해 디스패치 그룹/세마포어가 필요하지 않습니다.

  • 또는 작동 중에이를 감쌀 수 있으며 (예 : https://stackoverflow.com/a/27022598/1271826) 작업 대기열을 사용할 수 있습니다.

+0

첫 번째 요청에 의해 채워진 User 클래스가 있고 그 다음에 사용자 클래스의 정보로 두 번째 요청을하기 때문에이 작업을 수행하려고합니다. like_all 함수가 리턴 한 후 다시 요청을하고 다시 like_all 등등을 수행합니다. –

+0

이 예제에 대한 예제를 제공해 주시겠습니까? "이 루프를 완전히 잃어 버릴 수도 있고 단순히 n을 보내는 루틴을 가질 수도 있습니다 요청을 처리하고 완료 핸들러에서 요청 n + 1을 전송하므로 스레드를 차단하는 데 필요한 디스패치 그룹/세마포어가 필요하지 않습니다. " –

0

Alamofire가 값을 반환 할 때마다 index + 1 함수를 호출하여이 문제를 해결합니다. 또한 fetch 요청의 완료 부분에서 함수를 호출합니다.기능처럼

@objc func action(_ sender: LGButton) { 
     sender.titleString = "Started to Like :)" 
     Network.sharedInstance.get_rec(completion: { (result) in 
      if(result != nil) 
      { 
       Network.sharedInstance.like(sender: 0, completion: { (result) in 
        //print(result) 
       }) 
      } 
     }) 
} 

: 여기

코드입니다

func like(sender: Int, completion: @escaping (String?) ->()){ 
    if let key = api_key{ 
     let headers: HTTPHeaders = [ 
      "X-Auth-Token": key, 
      "Accept": "application/json" 
     ] 
     print(sender) 
     print(SharedUsers.sharedUser.users.count) 
     if(sender < SharedUsers.sharedUser.users.count){ 
      if let user_id = SharedUsers.sharedUser.users[sender].id{ 
       Alamofire.request(baseUrl + likeURL + user_id, method: .get, parameters: nil, encoding: URLEncoding.default, headers: headers).validate() 
        .responseJSON { (response) -> Void in 
         guard response.result.isSuccess else { 
          print("Error while doing : \(response.result.error)") 
          completion(nil) 
          return 
         } 
         if let error = response.error{ 
          completion(nil) 
          print("Error Occured with Request: \(error)") 
         } 
         if let jsonData = response.data{ 
          let json = JSON(data: jsonData) 
          if let matched = json["match"].bool{ 
           completion(matched.description) 
           print("Liked!: \(matched)") 
           if(sender <= SharedUsers.sharedUser.users.count){ 
            self.like(sender: sender + 1, completion: {result in 
             //print(result) 
            }) 
           }else{ 
            return 
           } 
           if(matched){ 
           } 
          }else{ 
           "There is an error with JSON" 
          }}} 
      }else{return} 
     }}}