안녕하세요 :) 소들입니다!
오늘은 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
'iOS > Swift' 카테고리의 다른 글
Swift) Localizing - 다국어 처리하기 (16) | 2020.11.28 |
---|---|
Swift 5+) String - Raw String (String 안에서 " \ 사용하기) (0) | 2020.11.11 |
Swift) String에 대한 고찰 (1) - Struct인데 Heap에 저장 된다고? (8) | 2020.10.07 |
Swift) Optional 부수기 (6) - Optional Chaining (옵셔널 체이닝) (9) | 2020.09.24 |
Swift) 튜플(Tuple)에 대해 알아보자 (4) | 2020.09.22 |