Skip to content

Instantly share code, notes, and snippets.

@linearhw
linearhw / 블록을 이해하라.md
Created December 12, 2017 06:44
Effective Objective-C 37

1) 블록이란?

  • 블록은 Objective-C 에서 closure라는 abstract concept 를 구현한 것.
    closure란? function 을 environment 와 함께 저장하는 record
    일반적인 객체라고 생각하면 된다. isa 포인터도 가진다. 단순한 함수 포인터를 대신하는 것.

  • 블록을 실제로 사용하는 방법
    return_type ^(block_name)(params) = ^(params) {
    return_type;
    }
    이 외에도 많이 있다

typedef int(^EOCSomeBlock)(Bool flag, int value);

EOCSomeBlock block = ^(Bool flag, int value){
    // 구현 내용
};

이렇게 하는 게 좋은 이유는?

  • 가독성.

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

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

알림을 받을 수 있는 방법?

// Using the network fetcher
@implementation EOCClass {
    EOCNetworkFetcher *_networkFetcher; // self -> fetcher 
    NSData *_fetchedData;
}

- (void)downloadData {
    NSURL *url = [[NSURL alloc] initWithString:@"http://www.example.com/something.dat"];
    _networkFetcher = [[EOCNetworkFetcher alloc] initWithURL:url];

다시 짚고 가는 sync 와 async 의 차이

  • sync 는 current thread 를 작업이 다 끝날 때까지 block 한다
  • async 는 current thread 를 건드리지 않는다. 새로운 thread를 따로 만들거나 해서 실행시킨다.
    그러니 어느 쪽이 먼저 실행될 지는 알 수 없다.

앞에선 async 를 잘 처리하는 방법에 대해 배웠다. sync 는 어떻게 하면 좋은가?

  • GCD 이전엔 두 가지 방법이 있었다.
    1. 내장된 동기화 블록 사용하기 -> 남용하면 위험하다. 모든 블록이 서로를 동기화할 것이다.
    2. NSLock 객체를 직접 사용하기
  • 하지만 둘 다 문제가 있다. 데드락에 대한 처리가 힘들기 때문.

performSelector 는 GCD나 블록이 나오기 전까진 강력한 기능이었다

SEL selector;
if (/* 어떤 조건 */) {
    selector = @selector(foo);
} else if (/* 다른 어떤 조건*/) {
    selector = @selector(bar);
}

사실 Operation Queue 는 GCD 를 내부적으로 사용하고 있다.

GCD 와 Operation Queue 의 차이

  • GCD 는 C API 이다. Operation Queue 는 Obj-C 객체다.
  • GCD 큐 안에 있는 작업은 블록이다 (가볍다). Operation 은 Obj-C 객체다 (무겁다).

하지만 이럴 때는 Operation Queue 가 더 낫다.

  1. 작업 취소
    Operation Queue 의 경우, 대기 중인건 취소 가능
    GCD의 경우 cancel 기능이 없다. 직접 구현하는 수밖에..

디스패치 그룹의 특징

  • 다수의 작업을 병렬로 실행하고 모든 작업이 끝났을 때 후처리를 하고 싶은 때에 유용

디스패치 그룹을 사용하는 방법

dispatch_group_t dispatch_group_create();

// 같은 group 의 작업이라도 queue 가 같을 필요는 없다.
void dispatch_group_async(dispatch_group_t group,
 dispatch_queue_t queue, 

싱글턴 디자인 패턴은 흔히 사용되는 패턴이지만 thread-safety 에 대한 논쟁이 있다.
그래서 동기화 블록으로 둘러쌓기도 한다.

+ (id) sharedInstance {
    static EOCClass *sharedInstance = nil;
    @synchronized(self) {
        if (!sharedInstance) {
            sharedInstance = [[self alloc] init];
 }

사실 이미 iOS 6.0 에서 deprecated 이다.

이 메서드를 흔히 사용하는 패턴

  • 데드락을 막기 위해서
- (NSString*)someString {
    __block NSString *localSomeString;
    dispatch_sync(_syncQueue, ^{
        localSomeString = _someString;
    });