본문 바로가기

iOS/Swift

Swift & Objective-C) Closure와 Block의 차이점

 

 

 

안녕하세요 :) 소들입니다!

오늘은 Swift와 Objective-C를 같이 다뤄볼 예정인데요!!

 

만약

응 난 Objective-C 관심 없어~~

하면 나가세요!! 👀

 

Swift 유저들에겐 Block이란 개념이 생소할 것이고,

Objective-C 유저들에겐 Closure란 개념이 생소할 것 같아요 :)

 

먼저 말해두고 가면

 

Block과 Closure는 익명함수를 뜻하는

같은 개념입니다

 

자바에선 람다라고 하져???

스위프트에선 Closure라 부르고

Objective-C에선 Block이라고 부를 뿐입니다!!!

 

근데 제목에 거창하게 vs를 써둔 것을 보면 둘은 뭔가 다른 성질을 갖고 있나봐요 :)

궁금하지 않나연?

 

 

이것에 대해 알아보고 갈 거예요~~~~

모든 포스팅은 편의 말투로 합니다~!!

 

 

 

 

1. Closure vs Block

 

위에서 이 둘은 익명함수로 같은 개념이라고 했음!

근데 그럼 뭐가 다를까..?

거두절미하고 얘기하면

 

같은 Scope에 있는 값(Value) 타입지역변수캡쳐하는 방식이 다름

 

ㅇㅖ..?

제로 알아보자 :)

 

 

먼저, "값이 캡쳐"된다는 개념부터 알고 갈 것임

 

Closure의 기본 개념을 보면,

(설명은 Closure로 하지만 Block도 같은 개념임)

 

"Closure란 내부 함수와 내부 함수에 영향을 미치는 주변 환경을 모두 포함한 객체이다."

 

이게 무슨 말이냐면

다음과 같은 코드가 있울 때

 

 

func doSomething() {
    var message = "Hi i am sodeul!"
 
    //클로저 범위 시작
    
    var num = 10
    let closure = { print(num) }
 
    //클로저 범위 끝
    
    print(message)
}
 

 

 

closure는 내부에서 외부 변수인 num이라는 Value 타입의 변수를 사용하기 때문에

num의 값을 내부적으로 저장하고 있는데,

이것을 num의 값이 캡쳐되었다 라고 표현함

 

근데 message란 변수는 closure 내부에서 사용하지 않기 때문에 따로 저장하지(캡쳐되지) 않음

 

 

캡쳐가 뭔지 알겠셈!?! 👀

이 캡쳐를 할 때, Closure와 Block의 방식이 서로 다른 것임!!!!

 

 

 

 

2. Closure의 캡쳐 방식

 

결론부터 말하겠음

 

Closure는 값을 캡쳐할 때

Value/Reference 타입에 관계 없이 Reference Capture 한다

 

왜 위에서 Value Type의 변수를 캡쳐하는 방식이 다르다 했냐면,

Reference Type인 경우엔 값을 저장할 때 참조하는 것이 당연함(주소값을 저장)

(Closure, Block 모두 동일하기 때문에 Reference Capture에 대해선 안 다룸)

 

근데 Int, Double, Struct 같은  Value Type의 값은

값을 저장할 때 Copy되어 저장되는 것이 당연하잖음???

실제로도 그럼 ㅇ.ㅇ

 

근데 Swift는 이 Value Type 값도 캡쳐할 땐 Reference 방식으로 캡쳐

쉽게 말해서 '참조' 한다는 뜻임

 

 

예제로 보자 :)

 

 

func doSomething() {
    var num: Int = 0
    print("num check #1 = \(num)")
    
    let closure = {
        print("num check #3 = \(num)")
    }
    
    num = 20
    print("num check #2 = \(num)")
    closure()
}
 

 

 

위에서 closure는 같은 Scope의 지역변수인 num을 사용하므로

closure는 num 값을 캡쳐할 것임

 

근데 num이 Int형, 즉 Value Type일지라도

"Reference Capture"를 진행함

 

따라서 closure를 실행하기 전에 num의 값을 바꾸면,

closure는 num을 참조하고 있기 때문에 closure에서 실행하는 num의 값도 바뀜

 

클로저의 변수가 사용되는 시점의 변수의 값을 평가함

 

따라서 위 코드의 결과는 다음과 같음

 

 

 

 

 

 

캡쳐란 말 때매 ㅐ헷갈리는 거지 뭐 쉽게 말하면

Closure는 외부 값이 Value & Reference Type이든 모두 참조

 

 

 

 

2-1. Value 타입의 값을 복사해서 Capture 할 순 없나요?

 

가능함!

Capture List 라는 것을 이용하면 할 수 있움!

Capture List가 무엇이냐면  Copy해서 캡쳐할 변수를 명시해주는 것인데

 

 클로저의 시작인 { 의 바로 옆에  []를 이용해 나열한다

이때 in 키워드도 함께 작성한다

 

이렇게 선언함 예제로 보면

 

 

 

 

이런 식으로 캡쳐할 Value 타입의 변수를 [] 안에 나열하면 됨!

그렇게 하면

 

Closure를 선언할 당시의 num, num2 값을 Const Value Type으로 캡쳐함

 

자, 여기서 중요한 것은 Const Value Type,

"상수"로 캡쳐된다는 것임

 

따라서 다음과 같이

 

 

 

 

closure 내부에서 num, num2의 값을 변경할 수 없음

이것이 Closure의 Capture 방식임 🙃

 

 

Reference Type의 경우엔 Closure Capture를 이용해도 Reference Captur가 됨

이부분에 대해선 여기서 자세히 다룸 :)

 

 

 

 

3. Block의 캡쳐 방식

 

이또한 결론부터 얘기 하겠움

 

Block은 값을 캡쳐할 때

Value Type일 경우 값을 복사하여 Capture하고,

Reference Type일 경우 Reference Captrue를 한다

 

자, 이제 Closure와 Block의 차이점이 뭔지 알것임 ㅎㅎ..

Block의 경우 Value Type일 경우 값을 "복사" 해서 Capture하고 있음

 

에제로 보자 :)

 

 

- (void)doSomething {
    int num = 0;
    NSLog(@"num check #1 = %d", num);
    
    void (^block)(void= ^{
        NSLog(@"num check #3 = %d", num);
    };
 
    num = 20;
    NSLog(@"num check #2 = %d", num);
    block();
}
 

 

 

Closure와 똑같은 예제임!!

근데 결과를 보면

 

 

 

 

결과 값이 달라짐 ㅎㅎ

 

block을 선언할 당시의 num 값을 Const Value Type으로 캡쳐함

 

 

얘또한 "상수"로 캡쳐함!!!!

따라서 다음과 같이

 

 

 

 

값을 변경할 수 엄 따 

 

 

 

 

3-1. 값을 참조해서 Capture 할 순 없나요?

 

자, 이번엔 반대로 Block에서 Reference Capture를 하는 방법임

당연히 가능함~_~

 

바로

 

 

 

이 키워드를 통해서!

 

Reference Capture 하고 싶은 변수 선언부에

__block 를 접두사로 붙여준다

 

예제로 보면

 

 

- (void)doSomething {
    __block int num = 0;
    NSLog(@"num check #1 = %d", num);
    
    void (^testBlock)(void= ^{
        NSLog(@"num check #3 = %d", num);
    };
 
    num = 20;
    NSLog(@"num check #2 = %d", num);
    testBlock();
}
 

 

 

결과값이

 

 

 

 

요롷게 Referenc Capture가 되는 것을 볼 수 있다 :)

 

 

 

 

 

4. 정리

 

자.. 정리하자면

Closure & Block에선 주변 지역 변수를 Capture 방식이 2가지가 있음

 

Value Copy Capture - Closure & Block이 선언될 당시 변수 값을 Capture 한다
- Const Value Type으로, Closure & Block 내부에서
값을 변경하지 못한다 (Read Only)
Referenct Capture - Closure & Block 내부에서 변수가 사용되는 시점의 변수 값을 Capture 한다.
- Reference 형태로 Closure & Block 내부(외부)에서 값을 수정할 경우 외부(내부)의 값도 변경된다

 

 

또한 Closure vs Block의 Capture 방법은 다음과 같음

 

 

  Closure (Swift) Block (Objective-C)
Value Type Reference Capture Value Copy Capture
Reference Type Reference Capture Reference Capture
Value Type일 때
Reference Capture -> Value Copy Capture
Capture List  
Value Type일 때
Value Copy Capture -> Reference Capture 
  __block

 

 

 

 

 

.

.

.

 

저는 Swift와 Objective-C를 둘다 쓰는 입장에서

둘의 차이점에 대해서 명확하게 알지 못했었는데

이번 포스팅을 통해 자세히 알게 됐네요 :)

근데 아직 Closure ARC 부분에 대해 공부를 못해서 이부분은 따로 공부하고 포스팅 할게용 🌝

 

누군가에겐 도움이 되었길👀

20000

 

 



Calendar
«   2024/04   »
1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30
최근 댓글
Visits
Today
Yesterday