2014-10-18 1 views
1

UITableViewController가 있습니다. TableViewControllerA라고합니다. API와 통신하기 위해 만든 다른 개체 APICallerB의 대리인입니다. NSURLSessionDataTask를 통해 APICallerB는 TableViewControllerA의 속성 중 하나와 동일하게 설정 될 속성 중 하나를 설정합니다. self.property1 = acb.property2가 작동 할 수 있도록, 무엇을 완료하는 [acb makeAPICallWithARgument:self.argument] 기다릴 수있는 가장 좋은 방법 :GCD NSURLSessionDataTask가 완료 될 때까지 대기

- (void)viewDidLoad { 

    [super viewDidLoad]; 

    // init instance of APICallerB 
    APICallerB *acb = [[APICallerB alloc] init]; 

    // Set TableViewControllerA as delegate 
    tvcA.delegate = self; 


    [acb makeAPICallWithArgument:self.argument]; 


    self.property1 = acb.property2; 
} 

내 질문은 :

여기 tableViewControllerA의 viewDidLoad 방법입니까? 나는 GCD가 사용될 수 있다고 가정하고있다. (`dispatch_sync '?) iOS/Objective-C에 익숙하지 않다. 아니면 다른 곳으로 이동하는 것이 좋을까요?

여기 APICallerB에서 방법 : 당신은 비동기 패턴을 사용한다, 그래서

- (void)makeAPICallWithArgument:(NSString *)arg 
{ 


    NSString *requestString = [NSString stringWithFormat:@"http://%@:%@@apiurl.com/json/Request?arg=%@", API_USERNAME, API_KEY, arg]; 
    NSURLSessionConfiguration *config = [NSURLSessionConfiguration ephemeralSessionConfiguration]; 
    config.HTTPAdditionalHeaders = @{@"Accept" : @"application/json"}; 
    NSURLSession *urlSession = [NSURLSession sessionWithConfiguration:config delegate:self delegateQueue:nil]; 

    NSURL *url = [NSURL URLWithString:requestString]; 
    NSURLRequest *req = [NSURLRequest requestWithURL:url]; 

    NSURLSessionDataTask *dataTask = [urlSession dataTaskWithRequest:req completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) { 

     NSDictionary *jsonObject = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil]; 
     NSArray *ar = [jsonObject[@"Result"] objectForKey:@"results"]; 
     self.property2 = ar; 
     }]; 

    [dataTask resume]; 
} 
+0

disparch_semaphore는 사용할 수있는 옵션입니다. 이 블로그 게시물을 살펴보십시오. http://www.g8production.com/post/76942348764/wait-for-blocks-execution-using-a-dispatch-semaphore – HorseT

+0

차가움. 나는 그것을 탐험 할 것이다. – Ja5onHoffman

답변

2

당신은 비동기 방식을 요구하고있다. 예를 들어, 완료 블록 구현과 같습니다

- (void)makeAPICallWithArgument:(NSString *)arg completionHandler:(void (^)(NSArray *results, NSError *error))completionHandler 
{ 
    NSString *requestString = [NSString stringWithFormat:@"http://%@:%@@apiurl.com/json/Request?arg=%@", API_USERNAME, API_KEY, arg]; 
    NSURLSessionConfiguration *config = [NSURLSessionConfiguration ephemeralSessionConfiguration]; 
    config.HTTPAdditionalHeaders = @{@"Accept" : @"application/json"}; 
    NSURLSession *urlSession = [NSURLSession sessionWithConfiguration:config delegate:self delegateQueue:nil]; 

    NSURL *url = [NSURL URLWithString:requestString]; 
    NSURLRequest *req = [NSURLRequest requestWithURL:url]; 

    NSURLSessionDataTask *dataTask = [urlSession dataTaskWithRequest:req completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) { 
     if (completionHandler) { 
      if (error) { 
       dispatch_async(dispatch_get_main_queue(), ^{ 
        completionHandler(nil, error); 
       }); 
      } else { 
       NSError *parseError; 
       NSDictionary *jsonObject = [NSJSONSerialization JSONObjectWithData:data options:0 error:&parseError]; 
       dispatch_async(dispatch_get_main_queue(), ^{ 
        completionHandler(jsonObject[@"Result"][@"results"], parseError); 
       }); 
      } 
     } 
    }]; 

    [dataTask resume]; 
} 

그리고 당신은 같이 호출 것 :

[acb makeAPICallWithArgument:self.argument completionHandler:^(NSArray *results, NSError *error){ 
    // you'd probably first check to make sure you didn't have an error 

    self.property1 = results; 
}]; 

작은 관찰의 커플 :

  1. 아마 같으면 ' 매번 새로운 세션을 만들지 마십시오. 두 번 이상의 호출을 원할 경우 향후 요청을 위해이 세션을 저장하십시오.

  2. makeAPICallWithArgument은 나중에 검색하려고하는 속성을 업데이트하고 있습니다. 그 재산을 퇴직시키고 매개 변수로 값을 완성 블록에 전달합니다.

  3. 약간의 오류 처리가 추가되었습니다.

  4. [jsonObject[@"Result"] objectForKey:@"results"]이 맞지 않을 수 있습니다. "Result"키를 가진 사전을 반환하는 JSON과 "results"키를 가진 다른 사전을 실제로 가지고 계십니까? 그렇다면 괜찮습니다.하지만 의심스러워 보입니다. JSON 형식이더라도이 내용을 jsonObject[@"Result"][@"results"]으로 단순화했습니다.

  5. 다른 곳에서는 세마포어를 고려할 것을 제안했습니다. 그것은 거의 항상 나쁜 생각입니다. 이것은 비동기 메서드를 동 기적으로 동작시키는 데 사용됩니다. 하지만 메인 큐를 차단하고 싶지는 않습니다.

    완료 블록 패턴을 사용하면 세마포어가 필요하지 않습니다. Apple은 이유 때문에 비동기 API를 제공하므로 비동기 패턴을 사용해야합니다.

+0

위대한 설명. 나는 이것을 구현할 것이다. – Ja5onHoffman

+0

나는 물어 본 동일한 질문의 수를 감안할 때 본질적으로 비 답이라고 생각한다. 쿼리는 "비동기 I/O를 사용하도록 코드를 어떻게 재구성해야합니까?"가 아니라 "데이터 태스크가 완료 될 때까지 기다리는 방법"입니다. 나는 이전 질문이 유효하다고 생각하고 대답하지 않았다. (다른 질문에 대해서는 여기 또는 다른 곳에서).특히'sendSynchronousRequest'는 iOS 9에서 더 이상 사용되지 않습니다. I/O를 차단하려는 사람들을위한 답은 무엇입니까? – aroth

+1

나는 당신의 말을 듣지 만, 단순한 진실은 동기 호출을하는 99.9 %의 시간이 단지 잘못된 행동이라는 것입니다. 그것은 더 단순 해 보이지만 (특히 비동기 패턴에 익숙하지 않은 경우), 일반적으로 _really_ 나쁜 생각입니다. 애플은 이유 때문에 동시 호출을 회수했다. 나는 누군가가 내게 다가와서 "이런, 나는 조금 우울해하고 있는데,이 총의 안전을 어떻게 끌지"라고 말합니다. 우리는 그들에게 그것을하는 방법을 보여줄 수는 있지만, 그렇게하는 것은 거의 변함이 없습니다. 그러나 다음과 같이 여러 번 묻습니다. http://stackoverflow.com/a/21205992/1271826 – Rob