Swift Closure vs. Objective-C Block 차이점 비교 분석

Obj-C의 블락(block)이나 Swift 클로저(closure)는 컨셉은 거의 동일하나 closure 내부에서 현재 scope에 존재하는 값 타입(value type) 변수들을 캡쳐(capture)해서 사용할 때 기본동작이 반대로 되어있기 때문에 사용법에 주의를 기울여야 한다. 반면 클래스 인스턴스와 같은 참조 타입(reference type) 변수들은 항상 reference copy가 일어나기 때문에 두 언어를 사용할때 차이점에 크게 신경쓰지않아도 된다. (대신 retain cycle이 생기지 않도록 조심해야 한다.)

다음 예제들을 통해서 차이점을 좀 더 자세히 알아보자.

Capture in Swift closure

Swift의 경우 일반적으로 value type 변수를 다른 변수에 할당하거나, 함수 파라메터로 전달 할 때 copy동작이 기본이다. 하지만 closure에서 변수를 capture를 할 때는 명시적인 capture list를 작성하지 않으면 value type 변수(struct 변수 포함) 임에도 불구하고 reference capture가 일어난다. 확인을 위해서 다음 예제를 살펴보자.

var anInteger = 42

let testClosure = {
    // anInteger는 capture되는 순간 reference copy됨
    print("Integer is: \(anInteger)")
}

anInteger = 84

testClosure()
// Prints "Integer is 84"

경우에 따라서 referece copy동작 대신 value copy가 필요할 때도 있다. 이 경우 아래와 같이 [anInteger, ...] 형태로 capture list를 만들어서 변수를 명시 해주면 된다. (value capture된 값은 const value type 형태로 capture가 되고 closure안에서 변경이 불가능해진다.)

var anInteger = 42

let testClosure = { [anInteger] in
    // anInteger는 capture되는 순간 value copy됨
    print("Integer is: \(anInteger)")
}

anInteger = 84

testClosure()
// Prints "Integer is 42"

Capture in Objective-C Block

반대로 Obj-C block의 경우 value type이 capture 될때 기본동작이 value copy 이다. 아래 예제를 살펴보자.

int anInteger = 42;

void (^testBlock)(void) = ^{
     // anInteger는 capture되는 순간 value copy됨
    NSLog(@"Integer is: %i", anInteger);
};

anInteger = 84;

testBlock();
// Prints "Integer is: 42"

이를 reference copy로 변경 하려면 __block 키워드를 capture할 변수 선언시에 명시해주면 된다.

__block int anInteger = 42;

void (^testBlock)(void) = ^{
     // anInteger는 caputure되는 순간 reference copy됨
    NSLog(@"Integer is: %i", anInteger);
};

anInteger = 84;

testBlock();
// Prints "Integer is: 84"

Obj-c의 블록 사용법에 관해서 더 자세한 내용은 다음 글에 더 자세히 설명해두었다. Objective-C Block 동작 심층 분석