안녕하세요.
정말 오랜만에 글을 작성하는 것 같습니다.
요즘엔 개발에 대한 의지가 많이 줄어서 블로그 활동도 뜸해진 것 같습니다.
내가 지금 행복을 위해서 일하고 있는지 돈을 위해서 일하고 있는지 잘 모를 때가 있습니다 ㅎㅎㅎㅎ.
그래서 저 스스로를 다짐하기 위해서 블로그를 다시 시작하려 합니다.
https://www.youtube.com/watch?v=DMDi2S-PEP0
요즘 굉장히 자주 듣고 있는 정승환의 도망가자 입니다. 최근 들어서 도망가고 싶을 때가 있습니다 ㅎㅎㅎㅎ
** Capturing Value **
캡쳐링 벨류는 클로저 내부에 값을 이미지 처럼 사진을 찍고 있다가 나중에 지속적으로 사용하는 것을 의미합니다.
프로그래밍으로 따지면 주소값을 저장(캡쳐링) 했다가 사용 하는 것을 의미합니다.
바로 코드를 보시면 이해가 될 겁니다.
** 예제 **
func travel2() -> (String) -> Void {
var counter = 1
return { //중첩 함수라 생각하면 된다.
print("\(counter). I'm going to \($0)")
counter += 1
}
}
let result2 = travel2()
result2("London") // 0, I'm going to London
result2("Seoul") // 1, I'm going to Seoul
result2("Tokyo") // 2, I'm going to Tokyo
Travel2() 함수를 보면 Void -> String -> Void 인 것을 확인 할 수 있습니다.
즉, Void 값을 받고 내부 함수는 (String)을 받고 최종 적으로 Void를 반환 하는 것을 의미합니다.
counter의 갯수가 내부 함수에서 증가시는데, 지속적으로 증가하는 것을 볼 수 있습니다.
travel2() 함수는 끝나지만 그 내부의 counter는 계속 살아 있습니다.
func travel3() -> ((String) -> Void ) -> Void {
var list : [Int] = []
return { item in
item("Hello \(list.count) \(list)")
list.append(0)
}
}
let result = travel3()
let input : (String) -> Void = { item in
print("I'm in \(item)")
}
result(input)
result(input)
result(input)
이렇게 배열을 저장 할 수도 있습니다.
조금 다른 점은 이렇게 함수를 입력으로 넣을 수도 있다는 겁니다.
- 클로저 정리 -
여러개의 입력이 있는 클로저
var test : (String) -> (Int) -> (Bool) -> String = { item in
print(item)
return { itemInt in
print(itemInt)
return { itemBool in
print(itemBool)
return "Hello"
}
}
}
let aaa = testclass.test("World")(10)(false) // Hello
** 내가 활용한 방식 **
회사 일을 하면서 기능 구현을 해야하는데 그런적이 있었다.
함수가 끝나더라도, 배열에 함수를 저장해서 그 함수를 필요할 때 사용하고, 함수를 새롭게 정의하면 기존의 것이 사라지고,,,
그런 것을 구현 해보고 싶었다.
class Test {
//만약 결과 값을 특정 함수가 변형 되기 전 까지만 사용 하고 싶을 때, 사용하면 좋을 것 같다.
var realCaptureValue : () -> ( @escaping (String) -> (String) ) -> [(String) -> (String)] = {
var capturValue : [(String) -> (String)] = []
return { closure in
capturValue.append(closure)
return capturValue
}
}
}
//넣어줄 함수
let item : (String) -> String = { item in
return "haha \(item)"
}
//넣어줄 함수
let item2 : (String) -> String = { item in
return "yup \(item)"
}
let testclass = Test()
var result = testclass.realCaptureValue()
result(item) //[(String) -> String]
result(item2) // [(String) -> String, (String) -> String]
var list = result(item) // [(String) -> String, (String) -> String, (String) -> String]
list[0]("Hello") // "haha Hello"
list[1]("Hello")// "yup Hello"
result = testclass.realCaptureValue()
result(item2) // [(String) -> String] : 초기화 됨
** Capturing Closure의 기술? **
이건 캡쳐링 Value에서 주소값과 값 타입의 관계에 대한 정리한 코드들이다.
여기에 정말 자세히 정리 되어 있다.
- 기본 코드 -
class A {
var name : String
init(name : String){
self.name = name
}
deinit{
print("\(self.name) escaped!")
}
}
func delay(_ second : Int , clousre : @escaping () -> ()){
let time = DispatchTime.now() + .seconds(second)
DispatchQueue.main.asyncAfter(deadline: time, execute: {
print("째깍째깍")
clousre()
})
}
- 예제 1 -
func demo1(){
let a = A(name: "hello")
print("A init")
delay(1, clousre: {
print("inside closure :\(a)") //사용 할 때 a를 캡쳐링 했다. 따라서 사라지지 않는다.
})
print("bye")
}
demo1()
//
A init
bye
째깍째깍
inside closure :__lldb_expr_129.A
hello escaped!
- 예제 2 -
func demo2() {
var a = A(name: "a")
print("A init")
delay(1, clousre: {
print("inside closure : \(a)") //a를 캡처링 해서 사용하기 전에, a가 B로 바뀜 그래서 B가 출력 됨, // 주소값 동일
// 즉, a를 사용 할 때 캡쳐링을 한다.
})
a = A(name: "b")
print("after closure : \(a)")
}
demo2()
//
A init
a escaped!
after closure : __lldb_expr_131.A
째깍째깍
inside closure : __lldb_expr_131.A
b escaped!
- 예제 3 -
func demo3() {
var a = A(name: "a")
print("A init")
delay(1, clousre: { [a] in
print("inside closure : \(a)") // capture list를 사용하면 클로저 생성 시점에 캡쳐 할 수 있다.
})
a = A(name: "b")
print("after closure : \(a)")
}
demo3()
//
A init
after closure : __lldb_expr_133.A
b escaped!
째깍째깍
inside closure : __lldb_expr_133.A
a escaped!
- 예제 4 -
//value를 변경할 경우
//레퍼런트 타입
func demo4() {
let a = A(name: "a")
print("A init")
delay(1, clousre: { [a] in
print("inside closure : \(a)") //capture list를 사용해도 a의 내부 값은 변경이 된다.
//왜냐 레퍼런스 타입이기 때문에
})
a.name = "hello"
print("after closure : \(a)")
}
demo4()
//
A init
after closure : __lldb_expr_135.A
째깍째깍
inside closure : __lldb_expr_135.A
hello escaped!
- 예제 5 -
struct AS {
var name : String
init(name : String){
self.name = name
}
}
func demo5(){
var a = AS(name: "a")
print("A init")
delay(1, clousre: { [a] in
print("inside closure : \(a)") // 캡처하는 대상이 value 타입이라면 값을 받기 때문에 변경 되지 않는다.
})
a.name = "world"
print("after closure : \(a)")
}
demo5()
//
A init
after closure : AS(name: "world")
째깍째깍
inside closure : AS(name: "a")
참고 사이트 :
정의 글 :
https://onelife2live.tistory.com/7
정의 글 :
https://www.hackingwithswift.com/sixty/6/11/capturing-values
'Xcode > Swift - PlayGround' 카테고리의 다른 글
PlayGround) Notification Center의 사용법 (0) | 2021.09.03 |
---|---|
PlayGround) RxMvvm에서 Input과 Output에서 의문점 (0) | 2021.09.03 |
PlayGround) 런타임 프로토콜 AND 컴파일 프로토콜 (클로저 잠깐,,) (1) | 2021.04.25 |
PlayGround) Generic - Closure의 확장 (1) | 2021.04.11 |
PlayGround) 제너릭에 대해 알아보자 (0) | 2021.03.27 |
댓글