ํด๋ก์ (Closure) vs ๋ธ๋ก(Block) ํจ์๋ฅผ ๋น๊ตํด๋ณด์
Swift์ Closure์ Objective-C์ ๋ธ๋กํจ์๋ ์ด๋ฆ์ด ์๋ ํจ์๋ก ๊ฐ๋ ์ด ๊ฐ์ต๋๋ค.
ํ์ง๋ง, ๋์ ๊ฐ์ ์บก์ณํ๋ ๋ฐฉ์์ ์ฐจ์ด๊ฐ ์์ต๋๋ค. ๐ญ
'๊ฐ์ ์บก์ณํ๋ค'์ ์๋ฏธ๋ถํฐ ๋์ ์ฐจ์ด์ ์ ๋น๊ตํด์ ์์๋ณด๋๋ก ํ๊ฒ ์ต๋๋ค.
1. Capturing Values: ํด๋ก์ ์บก์ณ๋?
๋จผ์ ์๋ ์ฝ๋๋ฅผ ๋ณด๋ฉด, closure๋ ๋ด๋ถ์์ ์ธ๋ถ ๋ณ์์ธ runningTotal, amount ๋ผ๋ Value ํ์ ์ ๋ณ์๋ฅผ ์ฌ์ฉํ๊ธฐ ๋๋ฌธ์
๋ ๋ณ์์ ๊ฐ์ ๋ด๋ถ์ ์ผ๋ก ์ ์ฅํ๊ณ ์์ต๋๋ค.
์ด๋, runningTotal, amount์ ๊ฐ์ด ์บก์ณ๋์๋ค ๋ผ๊ณ ํํํฉ๋๋ค.
๋ฐ๋ฉด์ message๋ ๋ณ์๋ closure ๋ด๋ถ์์ ์ฌ์ฉํ์ง ์๊ธฐ ๋๋ฌธ์ ์บก์ณ๋์ง ์์ต๋๋ค.
func makeIncrementer(forIncrement amount: Int) -> () -> Int {
var runningTotal = 0
var message = "test"
func incrementer() -> Int {
runningTotal += amount
return runningTotal
}
return incrementer
}
์ฆ, makeIncrementer๊ฐ ํธ์ถ์ด ๋๋ฉด makeIncremeter์ ๋งค๊ฐ๋ณ์์ธ amount์ ์ง์ญ๋ณ์์ธ runningTotal์ incrementer๋ผ๋ ํด๋ก์ ์์ ์บก์ณํด์ ์ฌ์ฉํ๊ณ ์๋ค๋ ๋ป์ ๋๋ค.
2. Closure์ ์บก์ณ ๋ฐฉ์
: Closure๋ ๊ฐ์ ์บก์ณํ ๋, Value/Reference ํ์ ์ ๊ด๊ณ ์์ด ๋ชจ๋ Reference Capture ํ๋ค.
์๋๋ Reference Type์ธ ๊ฒฝ์ฐ์ ๊ฐ์ ์ ์ฅํ ๋ ์ฐธ์กฐ(์ฃผ์๊ฐ์ ์ ์ฅ)ํ๊ณ ,
Int, Double, Struct ๊ฐ์ Value Type์ ๊ฐ์ ๊ฐ์ ์ ์ฅํ ๋ Copy๋์ด ์ ์ฅ๋๋ ๊ฒ์ด ๋น์ฐํฉ๋๋ค.
ํ์ง๋ง, ์์์ ๋ดค๋ฏ์ด Swift Closure์์๋ ์ด Value Type ๊ฐ๋ ์บก์ณํ ๋ Reference ์บก์ณ!! ์ฆ, '์ฐธ์กฐ' ํฉ๋๋ค.
์๋ ์ฝ๋์์ closure์์์ num์ Intํ(Value Type)์์๋ ๋ถ๊ตฌํ๊ณ Reference ์บก์ณ๋ฅผ ํฉ๋๋ค.
๋ฐ๋ผ์ closure๋ฅผ ์คํํ๊ธฐ ์ ์ num ๊ฐ์ ๋ฐ๊พธ๋ฉด closure์์ ์คํํ๋ num์ ๊ฐ๋ ๋ฐ๋๋๋ค!!(์ฐธ์กฐํ๋ฏ๋ก!!)
var num: Int = 0
print("num check #1 = \(num)")
let closure = {
print("num check #3 = \(num)")
}
closure()
num = 20
print("num check #2 = \(num)")
closure()
์ ์ฝ๋์ ๊ฒฐ๊ณผ๊ฐ
๋ง์ฝ, ํด๋ก์ ๋ฅผ ํตํด Reference ์บก์ณ๊ฐ ์๋ Copy ์บก์ณ๋ฅผ ํ๊ณ ์ถ๋ค๋ฉด, (๊ฐ ๋ณ๊ฒฝ ์๋๊ฒ ํ๊ณ ์ถ๋ค!)
์๋ ์ฝ๋์ ๊ฐ์ด copyํ ๋ณ์๋ฅผ ๋ฏธ๋ฆฌ list๋ก ์ ์ธํด์ฃผ๋ฉด ๊ฐ์ด ๋ณ๊ฒฝ๋๋ ํด๋ก์ ๋ด๋ถ์ ๊ฐ์ด ๋ณํ์ง ์๊ณ ๋ณ๊ฒฝ์ด ์๋ฉ๋๋ค.
var num: Int = 0
print("num check #1 = \(num)")
let closure = { [num] in
print("num check #3 = \(num)")
}
closure()
num = 20
print("num check #2 = \(num)")
closure()
๊ฒฐ๊ณผ๊ฐ
3. Block์ ์บก์ณ ๋ฐฉ์
๋ฐ๋ฉด์, Block์ ๊ฐ์ ์บก์ณํ ๋
Value Type์ผ ๊ฒฝ์ฐ ๊ฐ์ ๋ณต์ฌํ์ฌ Captureํ๊ณ ,
Reference Type์ผ ๊ฒฝ์ฐ Reference Captrue๋ฅผ ํฉ๋๋ค.
Objective-C์ Block ํจ์๋ Value Type์ผ ๊ฒฝ์ฐ ์ฐธ์กฐ๊ฐ ์๋ "๋ณต์ฌ"๋ก ๊ฐ์ ์บก์ณํฉ๋๋ค.
๋ฐ๋ผ์ ๊ฐ์ ์ฝ๋๋ฅผ Objective-C๋ก ์์ฑํ์์ ๋, ๊ฐ์ด ๋ณํ์ง ์๋๋ค๋ ๊ฒ์ ์ ์ ์์ต๋๋ค!
- (void)doSomething {
int num = 0;
NSLog(@"num check #1 = %d", num);
void (^testBlock)(void) = ^{
NSLog(@"num check #3 = %d", num);
};
testBlock();
num = 20;
NSLog(@"num check #2 = %d", num);
testBlock();
}
๊ฒฐ๊ณผ ํ๋ฉด
Value Type์ ๊ฐ์ ๋ณต์ฌํ์ฌ ์บก์ณํ๋ฏ๋ก ๋ธ๋กํจ์ ๋ด๋ถ์์ ๊ฐ์ ๋ณ๊ฒฝํ ์ ์์ต๋๋ค.
ํ์ง๋ง ๋ณ๊ฒฝํ๊ณ ์ถ์ ๋, Copy ์บก์ณ๊ฐ ์๋ Reference ์บก์ณ๋ฅผ ํ๊ณ ์ถ๋ค๋ฉด, (๊ฐ ๋ณ๊ฒฝ ๋๊ฒ ํ๊ณ ์ถ๋ค!)
์๋ ์ฝ๋์ ๊ฐ์ด ๋ณ๊ฒฝํ๊ณ ์ ํ๋ ๋ณ์ ์์ __block ํค์๋๋ฅผ ์ฌ์ฉํ์ฌ ๋ณ๊ฒฝ ๊ฐ๋ฅํฉ๋๋ค.
- (void)doSomething {
__block int num = 0;
NSLog(@"num check #1 = %d", num);
void (^testBlock)(void) = ^{
NSLog(@"num check #3 = %d", num);
};
testBlock();
num = 20;
NSLog(@"num check #2 = %d", num);
testBlock();
}
๊ฒฐ๊ณผ ํ๋ฉด
Closure vs Block ์ ํ๋ก ์์ฝํ๋ฉด ๋ค์๊ณผ ๊ฐ์ต๋๋ค.๐
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 ๋ณ๊ฒฝ |
Closure List | |
Value Type์ผ ๋ Value Copy Capture -> Reference Capture ๋ณ๊ฒฝ |
__block |