iOS/Objective-C

[Objective-C] Objective-C의 block과 Swift의 closure

TDCIAN 2023. 4. 13. 22:50

 

 

Q. Objective-C의 block과 Swift의 closure의 각 정의와 공통점, 그리고 차이점을 설명해 줘

 

A. Objective-C의 Block과 Swift의 Closure는 모두 코드 블록을 나타내는 기능입니다.

 

Closure는 Swift에서 함수를 변수나 상수에 저장하거나 전달할 수 있는 기능입니다.

Closure는 중괄호로 감싸진 코드 블록으로, 함수처럼 매개 변수와 반환 값이 있는 경우도 있고, 없는 경우도 있습니다.

 

예를 들어, 아래와 같은 Closure를 정의할 수 있습니다.

let myClosure = { (a: Int, b: Int) -> Int in
  return a + b
}

위 Closure는 Int 타입의 매개 변수 a와 b를 받아서, 두 매개 변수를 더한 값을 Int 타입으로 반환합니다.

 

Objective-C의 Block은 마찬가지로 코드 블록을 나타내는 기능입니다.

Block은 ^ 기호로 시작하는 코드 블록으로, 변수와 함수를 포함할 수 있습니다.

 

아래는 Objective-C에서 Block을 사용하는 예시입니다.

int (^myBlock)(int a, intb) = ^(int a, int b) {
    return a + b;
};

위 Block은 Int 타입의 매개 변수 a와 b를 받아서, 두 매개 변수를 더한 값을 Int 타입으로 반환합니다.

 

공통점

- Closure와 Block은 모두 중괄호로 감싸진 코드 블록으로, 함수처럼 매개 변수와 반환 값이 있는 경우도 있고, 없는 경우도 있습니다.

- 둘 다 변수나 상수에 할당하거나, 함수의 매개 변수로 전달할 수 있습니다.

 

차이점

- Closure는 Swift에서만 사용할 수 있고, Block은 Objective-C에서 사용할 수 있습니다.

- Closure는 기본적으로 참조 타입으로 작동하며, Block은 기본적으로 값 타입으로 작동합니다.

- Swift의 Closure는 자동으로 매개 변수의 타입 유추를 제공하며, Objective-C의 Block은 매개 변수 타입을 직접 지정해야 합니다.

- Swift의 Closure는 Objective-C의 Block보다 표현력이 풍부하며, 간결하고 가독성이 좋습니다.

 

+ Q. Objective-C에서 ^의 정의와 용도를 예시 코드와 함께 설명해 줘

 

A. Objective-C에서 '^'는 블록(Block)을 정의하기 위한 문법입니다. 블록은 함수형 프로그래밍에서 익명 함수(anonymous function)의 역할을 하며, 변수나 매개 변수로 전달될 수 있습니다.

 

'^'는 블록을 정의할 때 사용되며, 블록 내부에는 매개 변수와 반환 값의 타입이 선언됩니다. 예를 들어, 다음은 두 개의 'int' 값을 더하는 블록을 정의한 코드입니다.

int (^addBlock)(int, int) = ^(int a, int b) {
    return a + b;
};

위 코드에서 '^'는 블록을 정의하기 위한 문법이며, 'addBlock'은 블록을 저장하기 위한 변수입니다.

블록 내부에는 'int' 타입의 매개 변수 'a'와 'b'가 선언되며, 이 블록은 'a'와 'b'를 더한 결과를 반환합니다.

 

블록은 변수나 매개 변수로 전달될 수 있습니다. 예를 들어, 다음은 블록을 매개 변수로 받는 함수를 호출하는 예시 코드입니다.

void performBlock(int (^block)(int, int)) {
    int result = block(2, 3);
    NSLog(@"Result: %d", result);
}

performBlock(addBlock); // "Result: 5" 출력

위 코드에서 'performBlock' 함수는 'int' 값을 반환하는 블록을 매개 변수로 받습니다.

함수 내부에서는 전달된 블록을 호출하여 반환된 결과를 출력합니다.

 

블록은 Objective-C에서 함수형 프로그래밍을 구현할 때 유용하게 사용됩니다. 예를 들어, 다음은 블록을 사용하여 배열의 각 원소를 제곱하는 코드입니다.

NSArray *numbers = @[@1, @2, @3, @4, @5];

NSArray *squaredNumbers = [numbers valueForKeyPath:@"@map.self * self"];

NSLog(@"@", squaredNumbers); // [1, 4, 9, 16, 25] 출력

위 코드에서 'valueForKeyPath:' 메서드를 사용하여 각 원소를 제곱하는 블록을 전달합니다.

블록 내부에는 'self'를 사용하여 현재 원소의 값을 참조할 수 있습니다. 이를 통해 배열의 각 원소를 제곱한 새로운 배열을 생성하고 반환합니다.

 

 

 

Q. Swift의 Closure와 Objective-C의 Block이 같은 역할을 한다고 봐도 될까?

 

A. Swift의 Closure와 Objective-C의 Block은 기본적으로 비슷한 기능을 수행하지만, 약간의 차이점이 있기 때문에 완전히 동일한 역할을 하는 것은 아닙니다.

 

예를 들어, Swift의 Closure는 기본적으로 참조 타입으로 작동하며, Objective-C의 Block은 기본적으로 값 타입으로 작동합니다.

이것은 Closure와 Block을 변수나 상수에 할당하거나 함수의 매개 변수로 전달할 때 차이를 만들 수 있습니다.

 

또한 Swift의 Closure는 Objective-C의 Block보다 표현력이 풍부하며, 간결하고 가독성이 좋다는 장점이 있습니다.

Swift의 Closure는 자동으로 매개 변수의 타입 유추를 제공하며, Objective-C의 Block은 매개 변수 타입을 직접 지정해야 하는 등 구문의 차이가 있습니다.

 

따라서 Swift의 Closure와 Objective-C의 Block은 비슷한 기능을 수행하지만, 언어의 차이로 인해 세부적인 동작 방식에 차이가 있으며, 완전히 동일한 역할을 하는 것은 아닙니다. 

 

 

Q. Swift의 Closure가 참조 타입으로 작동하고 Objective-C의 Block이 값 타입으로 작동하는 것이 변수나 상수에 할당하거나 함수의 매개 변수로 전달할 때 왜 차이를 발생 시키는 거야?

 

A. Swift의 Closure가 참조 타입(Reference Type)으로 작동하는 이유는 클로저 인스턴스를 여러 곳에서 참조하거나 공유할 수 있기 때문입니다. 다른 말로, 클로저를 변수나 상수에 할당하거나 함수의 매개 변수로 전달하면, 해당 변수, 상수, 함수에서 참조된 클로저 인스턴스가 모두 같은 객체를 가리키게 됩니다. 이는 객체의 생명 주기를 관리하는 데 유용합니다.

 

반면, Objective-C의 Block은 값 타입(Value Type)으로 작동하기 때문에 Block 인스턴스를 전달할 때마다 새로운 인스턴스가 생성됩니다. 즉, 변수나 상수에 할당하거나 함수의 매개 변수로 전달하면, 해당 변수, 상수, 함수에서 참조된 Block 인스턴스는 각각 다른 인스턴스를 가리키게 됩니다. 이는 값을 복사하는 것과 비슷한 동작 방식입니다.

 

이러한 차이점은 변수나 상수에 Closure나 Block을 할당하거나 함수의 매개 변수로 전달할 때 객체 생명 주기나 동작 방식을 결정하는 데 영향을 미칩니다. 예를 들어, Swift에서는 Closure를 변수나 상수에 할당하면 해당 변수나 상수에서 참조된 Closure 인스턴스가 해제될 때까지 메모리에 유지됩니다. 하지만 Objective-C에서는 Block을 변수나 상수에 할당하면 해당 변수나 상수에서 참조된 Block 인스턴스가 변수나 상수의 범위를 벗어나면 자동으로 해제됩니다.

 

따라서 Swift에서는 Closure를 사용하여 객체의 생명 주기를 관리하고, Objective-C에서는 Block을 사용하여 간단한 값의 전달을 수행하는 것이 일반적입니다. 이러한 차이점은 Swift와 Objective-C의 프로그래밍 패러다임과 차이와 관련이 있습니다.

 

 

 

Q. Swift와 Objective-C의 프로그래밍 패러다임이 어떻게 다른데?

 

A. Swift와 Objective-C는 다른 프로그래밍 언어이며, 각각 다른 프로그래밍 패러다임을 지향하고 있습니다.

 

Objective-C는 객체 지향 프로그래밍 패러다임을 중심으로 설계되었습니다. 따라서 Objective-C 코드는 객체 간의 상호작용을 중심으로 구성되며, 객체를 사용하여 데이터와 행위를 캡슐화하고 재사용 가능한 모듈로 만들 수 있습니다. Objective-C는 또한 동적 바인딩(Dynamic Binding)을 지원하므로, 객체의 타입을 런타임에 결정할 수 있습니다.

 

반면, Swift는 객체 지향 프로그래밍뿐만 아니라 함수형 프로그래밍 패러다임도 지원합니다. Swift는 객체 지향적인 기능을 제공하면서도, 함수형 프로그래밍을 적극적으로 지원하여, 데이터와 행위를 분리하고 함수를 일급 객체로 사용할 수 있습니다. 또한, Swift는 안전한 코드 작성을 지향하기 때문에, 컴파일 타임에서 많은 에러를 감지할 수 있습니다.

 

따라서, Swift와 Objective-C는 프로그래밍 패러다임에서 차이가 있습니다. Objective-C는 객체 지향적인 코드 작성을 중심으로 설계되었고, 동적 바인딩을 지원하여 유연한 프로그래밍이 가능합니다. 반면에, Swift는 객체 지향적인 기능과 함수형 프로그래밍 기능을 모두 제공하며, 안전한 코드 작성을 지향합니다.

 

 

Q. Objective-C로는 함수형 프로그래밍이 불가능해?

 

A. Objective-C로도 함수형 프로그래밍을 할 수 있지만, Swift에 비해 함수형 프로그래밍을 위한 지원이 부족하다는 것은 사실입니다.

 

Objective-C에서는 함수를 일급 객체로 취급하지 않고, 함수 포인터를 사용하여 함수를 전달하거나, 메시지를 보내는 방식으로 함수를 호출합니다. 이는 함수형 프로그래밍을 위한 고차 함수나 Closure를 사용하는 것이 어렵다는 것을 의미합니다.

그러나 Objective-C는 런타임에서 동적으로 클래스와 메서드를 추가하거나 수정할 수 있기 때문에, 일부 함수형 프로그래밍 기법을 적용할 수 있습니다.

 

하지만 Swift는 함수형 프로그래밍에 더욱 적합한 언어입니다. Swift에서는 함수를 일급 객체로 취급하며, Closure를 사용하여 함수형 프로그래밍을 적극적으로 지원합니다. Swift에서는 고차 함수와 Closure를 사용하여, 불변성을 유지하면서 함수형 프로그래밍을 구현할 수 있습니다. 또한, Swift에서는 함수형 프로그래밍 기법을 사용하여 코드의 안정성과 가독성을 높일 수 있습니다.

 

 

 

Q. 함수를 일급 객체로 가진다는 것에 대한 내용을 좀 더 자세히 설명해 줘

 

A. 함수를 일급 객체(First-class object)로 취급한다는 것은, 함수를 변수나 데이터 구조에 할당하고, 함수를 매개 변수로 전달하고, 함수를 반환값으로 사용할 수 있다는 것을 의미합니다.

 

일급 객체로 취급되는 함수는 다음과 같은 특징을 가지게 됩니다.

 

1. 변수나 데이터 구조에 할당할 수 있다.

2. 매개 변수로 전달할 수 있다.

3. 반환값으로 사용할 수 있다.

 

함수가 일급 객체로 취급되면, 함수를 사용하여 더욱 유연하고 간결한 코드를 작성할 수 있습니다. 예를 들어, 함수를 변수에 할당하고, 이를 매개 변수로 전달하거나, 반환값으로 사용하여, 코드의 중복을 줄일 수 있습니다. 또한, 함수를 사용하여 추상화(abstraction)와 모듈화(modularization)를 할 수 있어, 코드의 가독성과 재사용성을 높일 수 있습니다.

 

Swift는 함수를 일급 객체로 취급하기 때문에, 함수형 프로그래밍 기법을 적극적으로 활용할 수 있습니다. 함수형 프로그래밍은 불변성과 함수 조합을 통해 코드의 안정성과 가독성을 높일 수 있습니다. 이러한 특징은 함수형 프로그래밍에서 사용되는 다양한 함수를 일급 객체로 취급하여 가능해진 것입니다.

 

 

 

Q. 같은 동작을 하는 함수형 프로그래밍 코드를 Swift와 Objective-C 각각 보여줘

 

A. Swift와 Objective-C에서 같은 동작을 하는 함수형 프로그래밍 코드를 예시로 보여드리겠습니다.

 

다음은 Swift에서 배열의 각 원소에 1을 더하는 과정을 함수형 프로그래밍으로 구현한 예시 코드입니다.

let numbers = [1, 2, 3, 4, 5]

// 고차 함수 map을 사용하여 배열의 각 원소에 1을 더한다.
let transformedNumbers = numbers.map { $0 + 1 }

print(transformedNumbers) // [2, 3, 4, 5, 6]

위 예시 코드에서 'map' 함수는 배열의 각 원소를 함수로 전달하고, 반환된 값을 새로운 배열로 만들어 반환합니다.

이러한 고차 함수를 사용하여, 함수형 프로그래밍에서는 불변성을 유지하면서 코드를 간결하게 작성할 수 있습니다.

 

다음은 Objective-C에서 배열의 각 원소에 1을 더하는 과정을 함수형 프로그래밍으로 구현한 예시 코드입니다.

NSArray *numbers = @[@1, @2, @3, @4, @5];

// 함수를 전달하기 위해 블록(Block)을 사용한다.
NSArray *transformedNumbers = [numbers valueForKeyPath:@"@map.self + 1"];

NSLog(@"@", transformedNumbers); // [2, 3, 4, 5, 6]

위 예시 코드에서 'valueForKeyPath:' 메서드를 사용하여 배열의 각 원소를 함수로 전달합니다. 이를 위해 Objective-C에서는 블록(Block)을 사용합니다. 블록은 익명 함수의 역할을 하며, 매개 변수와 반환값을 가질 수 있습니다.

 

Swift에서는 'map' 함수를 사용하여 간결하게 작성할 수 있지만, Objective-C에서는 블록을 사용해야 하므로 코드가 상대적으로 길어지는 단점이 있습니다.