Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save linearhw/3a6fdf879aade688dece1d94ddae1d2d to your computer and use it in GitHub Desktop.
Save linearhw/3a6fdf879aade688dece1d94ddae1d2d to your computer and use it in GitHub Desktop.
Effective Objective-C 39

시간이 오래 걸리는 작업(ex. 네트워크)을 할 때, 이 작업이 끝날 때까지 ui thread 가 기다리고 있는 건 바람직하지 않다.
특정 상황에서 앱이 특정 시간동안 응답하지 않으면 강제 종료가 될 것이다.

따라서 시간이 오래 걸리는 작업은 비동기로 작업하고, 작업이 끝났을 때 알림을 받고 싶을 것이다.

알림을 받을 수 있는 방법?

  • delegate 패턴
    아래와 같이 서로 다른 여러 개의 클래스에 대해 처리해야 할 때 delegate 에서 구분해줘야 한다는 단점이 있다.
// Multiple fetchers with delegation
- (void)fetchFooData {
    NSURL *url = [[NSURL alloc] initWithString:@"http://www.example.com/foo.dat"];
    _fooFetcher = [[EOCNetworkFetcher alloc] initWithURL:url];
    _fooFetcher.delegate = self;
    [_fooFetcher start];
}

- (void)fetchBarData {
    NSURL *url = [[NSURL alloc] initWithString:@"http://www.example.com/bar.dat"];
    _fooFetcher = [[EOCNetworkFetcher alloc] initWithURL:url];
    _fooFetcher.delegate = self;
    [_fooFetcher start];
}

- (void)networkFetcher:(EOCNetworkFetcher*)networkFetcher didFinishWithData:(NSData*)data {
    if (networkFetcher == _fooFetcher) {
        _fetchedFooData = data;
        _fooFetcher = nil;
    } else if (networkFetcher == _barFetcher) {
        _fetchedBarData = data;
        _barFetcher = nil;
    }
    // etc
}
  • 핸들러 블록
    블록이 정의된 scope 안에 있는 모든 변수에 접근할 수 있다는 장점이 있다.
// Multiple fetchers with completion handler block
- (void)fetchFooData {
    NSURL *url = [[NSURL alloc] initWithString:@"http://www.example.com/foo.dat"];
    EOCNetworkFetcher *fetcher = [[EOCNetworkFetcher alloc] initWithURL:url];
    [fetcher startWithCompletionHandler:^(NSData *data){
        _fetchedFooData = data;
    }];
}

- (void)fetchBarData {
    NSURL *url = [[NSURL alloc] initWithString:@"http://www.example.com/bar.dat"];
    EOCNetworkFetcher *fetcher = [[EOCNetworkFetcher alloc] initWithURL:url];
    [fetcher startWithCompletionHandler:^(NSData *data){
        _fetchedBarData = data;
    }];
}

API 에러 처리를 위한 핸들러 블록 사용

사용할 수 있는 방법은 크게 두 가지

  • 성공했을 때와 실패했을 때의 로직을 분리해서 사용한다.
[fetcher startWithCompletionHander:^(NSData *data){
    // Handle success
} failureHandler:^(NSError *error){
    // Handle failure
}];

이렇게 쓰면 가독성이 좋아진다.

  • 성공했을 때와 실패했을 때의 로직을 블록 하나에 넣는다.
[fetcher startWithCompletionHander:^(NSData *data, NSError *error){
    if (error) {
        // Handle failure
    } else {
        // Handle success
    }
}];

이렇게 쓰면 처리가 유연하다는 장점이 있다. 데이터와 에러 둘 다 필요한 상황에 대응할 수 있다.

핸들러를 실행할 큐를 신중하게 결정해야 한다.

핸들러 블록을 사용하는 API를 설계할 때 블록이 들어갈 큐를 parameter 로 주게 만들 수 있다.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment