Swift에서 함수는 값을 어떠한 방식으로 전달을 하며 클로저는 어떠한 방식으로 값을 캡처하는지에 대하여 실험을 해 보고 알아보자
환경: XCode 12.3(Swift 5.3)
[실험]
Closure
실험 1. (String 전달)
var name = "Lee"
let closure = { [name] in
print("closure: \(name)")
}
name = "Jang"
let doing = closure
doing()
// 어떤 것이 출력 될까요?
// 1. Lee
// 2. Jang
// 3. Compiler Error
실험 2. (Class 전달)
class Person {
var name: String?
}
let person = Person()
person.name = "Lee"
let closure = { [person] in
print("closure: \(person.name!)")
}
person.name = "Jang"
let doing = closure
doing()
// 어떤 것이 출력 될까요?
// 1. Lee
// 2. Jang
// 3. Compiler Error
실험 3. (Class property 전달)
class Person {
var name: String?
}
let person = Person()
person.name = "Lee"
let closure = { [person.name] in
print("closure: \(person.name!)")
}
person.name = "Jang"
let doing = closure
doing()
// 어떤 것이 출력 될까요?
// 1. Lee
// 2. Jang
// 3. Compiler Error
실험 4. (Struct 전달)
struct Person {
var name: String?
}
var person = Person()
person.name = "Lee"
let closure = { [person] in
print("closure: \(person.name!)")
}
person.name = "Jang"
let doing = closure
doing()
// 어떤 것이 출력 될까요?
// 1. Lee
// 2. Jang
// 3. Compiler Error
실험 5, 6, 7. (nonParams)
//실험 5. Class
class Person {
var name: String?
}
let person = Person()
person.name = "Lee"
let closure = {
print("closure: \(person.name!)")
}
person.name = "Jang"
let doing = closure
doing()
// 어떤 것이 출력 될까요?
// 1. Lee
// 2. Jang
// 3. Compiler Error
//실험 6. String
var name = "Lee"
let closure = {
print("closure: \(name)")
}
name = "Jang"
let doing = closure
doing()
// 어떤 것이 출력 될까요?
// 1. Lee
// 2. Jang
// 3. Compiler Error
//실험 7. Struct
struct Person {
var name: String?
}
var person = Person()
person.name = "Lee"
let closure = {
print("closure: \(person.name!)")
}
person.name = "Jang"
let doing = closure
doing()
// 어떤 것이 출력 될까요?
// 1. Lee
// 2. Jang
// 3. Compiler Error
정답:
1. String 전달 - Lee
2. Class 전달 - Jang
3. Class Property 전달 - Compiler Error (Expected 'weak', 'unowned', or no specifier in capture list)
4. Struct 전달 - Lee
5,6,7. nonParams - Jang
Function
실험 1, 2, 3, 4.(String, Class, Struct 전달)
당연히 아실거라고 생각하지만 그래도 빼 먹으면 섭섭하니....
//실험 1
var name = "Lee"
func function(name: String) {
print("func: \(name)")
}
name = "Jang"
function(name: name)
// 어떤 것이 출력 될까요?
// 1. Lee
// 2. Jang
// 3. Compiler Error
//답: 2
//실험 2
var name = "Lee"
func function(name: String) {
print("func: \(name)")
}
function(name: name)
name = "Jang"
// 어떤 것이 출력 될까요?
// 1. Lee
// 2. Jang
// 3. Compiler Error
//답: 1
//실험 3(struct 동일)
class Person {
var name: String?
}
var person = Person()
person.name = "Lee"
func function(person: Person) {
print("func: \(person.name!)")
}
person.name = "Jang"
function(person: person)
// 어떤 것이 출력 될까요?
// 1. Lee
// 2. Jang
// 3. Compiler Error
//답: 2
//실험 4(struct 동일)
class Person {
var name: String?
}
var person = Person()
person.name = "Lee"
func function(person: Person) {
print("func: \(person.name!)")
}
function(person: person)
person.name = "Jang"
// 어떤 것이 출력 될까요?
// 1. Lee
// 2. Jang
// 3. Compiler Error
//답: 1
실험 5. (String 전달 + 함수 변수에 저장)
var name = "Lee"
func function(name: String) {
print("func: \(name)")
}
let call: () = function(name: name)
name = "Jang"
call
// 어떤 것이 출력 될까요?
// 1. Lee
// 2. Jang
// 3. Compiler Error
실험 6. (Class 전달 + 함수 변수에 저장)
class Person {
var name: String?
}
var person = Person()
person.name = "Lee"
func function(person: Person) {
print("func: \(person.name!)")
}
let call: () = function(person: person)
person.name = "Jang"
call
// 어떤 것이 출력 될까요?
// 1. Lee
// 2. Jang
// 3. Compiler Error
실험 7. (Struct 전달 + 함수 변수에 저장)
struct Person {
var name: String?
}
var person = Person()
person.name = "Lee"
func function(person: Person) {
print("func: \(person.name!)")
}
let call: () = function(person: person)
person.name = "Jang"
call
// 어떤 것이 출력 될까요?
// 1. Lee
// 2. Jang
// 3. Compiler Error
실험 7, 8, 9. (nonParams + 함수 변수에 저장)
//실험 7. String
var name = "Lee"
func function() {
print("func: \(name)")
}
let call: () = function()
name = "Jang"
call
// 어떤 것이 출력 될까요?
// 1. Lee
// 2. Jang
// 3. Compiler Error
//실험 8. Class
class Person {
var name: String?
}
var person = Person()
person.name = "Lee"
func function() {
print("func: \(person.name!)")
}
let call: () = function()
person.name = "Jang"
call
// 어떤 것이 출력 될까요?
// 1. Lee
// 2. Jang
// 3. Compiler Error
//실험 9. Struct
struct Person {
var name: String?
}
var person = Person()
person.name = "Lee"
func function() {
print("func: \(person.name!)")
}
let call: () = function()
person.name = "Jang"
call
// 어떤 것이 출력 될까요?
// 1. Lee
// 2. Jang
// 3. Compiler Error
답:
1, 3. - Jang
2, 4. - Lee
5. String 전달 + 함수 변수에 저장 - Lee
6. Class 전달 + 함수 변수에 저장 - Lee
7, 8, 9. NonParams - Lee
[결론]
위의 결과로 작동방식을 정리하자면
1. Class는 주소값의 참조가 일어나며, Struct와 String은 값의 복사가 일어난다
2. Closure는 변수에 할당을 했을 시에 파라미터만 캡쳐가 된다.
3. 일반 함수는 변수에 할당 시에 함수의 실행까지 이루어진다.
더욱 정확히 말하자면 일반 함수의 실행로직 자체를 변수에 담는 것이 불가능하다
디버깅으로 어떠한 프로세스로 실행이 되는지 확인해 보겠습니다.
Closure
1. Closure(익명함수)의 파라미터가 캡처된다.
2. 변수에 담은 클로저 실행
클로저를 저장해 놓은 변수를 이용하여 실행을 해야 클로저 내부 로직이 실행이 된다.
Function
1. 함수를 저장한다(클로저랑 같아보일 수도 있지만 엄연히 다른 부분입니다. 밑에서 추가 설명을 할게요)
2. 함수가 실행이 된다
3. 함수를 담은 변수를 호출한다.
//Func
let call: ()- > () = function(person: person) //compiler Error
let call: () = function(person: person)
//Closure
let closure : () = { [person] in
print("closure: \(person.name!)")
} //compiler Error
let closure : () -> () = { [person] in
print("closure: \(person.name!)")
}
타입을 명시하여서 코드를 작성하게 되면 두 개의 결과가 왜 다른지 명확히 알 수 있다.
이 글로 인해 값이 어떤식으로 전달이 되는지 파악하는 데 조금이라도 도움이 됬으면 합니다.
다음 시간에는 함수 내부에서의 값 변경에 대해 다뤄보겠습니다.
다음 시간에 봐요 ^_^
'개발 > Swift(IOS)' 카테고리의 다른 글
[실험실-1] Delegate를 여러 번 정의하면 어떻게 될까? (2) | 2022.01.13 |
---|---|
Clean Architecture + MVVM(ReactorKit) - 1 (1) | 2021.06.08 |