Swift Closure 이해하기

Flamozzi·2023년 1월 19일
0

Swift

목록 보기
1/2
post-thumbnail

Swift Closure 이해하기

  • Closure는 함수를 변수의 형태로 만든 것이라고 이해하면 쉽다.
  • 일반적인 함수 형태와 비교해서 보면 구조가 더 명확하게 보인다.

Normal Function vs Closure

// normal function
func someFunction(name: String, age: Int) -> String {
    print("Normal Function")
    return "name: \(name), age: \(age)"
}

// closure
let someClosure: (_ name: String, _ age: Int) -> String = { name, age in
    print("Closure Form")
    return "name: \(name), age: \(age)"
}
  • normal function과 마찬가지로, 선언을 위해 이름을 정하고, 매개변수 여부를 정한 후 return type을 정한다.
  • closure는 함수의 기능을 하는 변수라고 봤을 때 = 이후에 {} 블록을 이용하여 값을 표기한다.
  • closure의 경우 매개변수 앞에 ‘_’를 붙임으로써 매개변수로 들어올 값들의 의미를 명시할 수 있다.

Closure의 축약된 형태

let someClosure: (String) -> Void = {
    print("name: \($0)")
    return
}
  • 매개변수의 의미를 명시하지 않아도 되는 경우는 생략하고 type만으로 사용할 수 있다.
  • closure의 경우 매개변수의 값을 그대로 값에서 사용할 수 없기에 name in 과 같은 형태로 값 내에서 사용할 이름을 정해주어야 하는데, 생략하고 싶은 경우 생략하고 매개변수의 순서를 $0 와 같은 형태로 사용할 수도 있다. ($0, $1, $2, .. 매개변수의 순서를 명시한 숫자다.)
  • Closure의 예시 뿐만 아니라 지나치게 생략된 코드는 가독성을 심각하게 저하 시킬 수 있으니 주의해서 사용하는 것이 좋다.

매개변수와 반환 여부에 따른 Closure의 형태

  • Closure 형태 - 매개변수 x, 반환 x
    // 매개변수가 없고, 반환하는 것이 없기 때문에 자료형은 () -> Void
    func someFunction() {
    	...
    }
    
    let someClosure : () -> Void = {
    	...
    }
  • Closure 형태 - 매개변수 o, 반환 x
    // 매개변수가 있고, 반환하는 것이 없기 때문에 형태 예시는 (_ name: String) -> Void
    
    func someFunction(name: String) {
    	...
    }
    
    let someClosure : (_ name: String) -> Void = { name in
    	...
    }
  • Closure 형태 - 매개변수 x, 반환 o
    // 매개변수가 없고, 반환하는 것이 있기 때문에 형태 예시는 () -> String
    
    func someFunction() -> String {
    	...
    	return "someFunction"
    }
    
    let someClosure : () -> String = {
    	...
    	return "someClosure"
    }
  • Closure 형태 - 매개변수 o, 반환 o
    // 매개변수와 반환 값이 있기에 (_ name: String) -> String
    
    func someFunction(name: String) {
    	...
    	return "name: \(name)"
    }
    
    let someClosure : (_ name: String) -> String = { name in
    	...
    	return "name: \(name)"
    }

Closure의 Void type 명시

let someClosure: () -> Void = {
    print("someClosure 입니다")
    return
}

let someClosure: () -> () = {
    print("someClosure 입니다")
    return
}
  • 자료형이 Void인 경우 () → () 혹은 () → Void 모두 가능하다.

Closure 사용 예시

// xcode playground

func someFunction(name: String, age: Int) -> String {
    print("Normal Function")
    return "name: \(name), age: \(age)"
}

let someClosure: (_ name: String, _ age: Int) -> String = { name, age in
    print("Closure Form")
    return "name: \(name), age: \(age)"
}

let value = someFunction(name: "Flamozzi", age: 10)
let result = someClosure("플라모찌", 10)

print(value)
print(result)
// result
Normal Function
Closure Form
name: Flamozzi, age: 10
name: 플라모찌, age: 10
  • let result = someClosure("플라모찌", 10) 에서 볼 수 있는 것 처럼 closure의 매개변수 값을 정할 때는 name: “플라모찌” 와 같은 형태로 이름을 명시할 수 없다. (바로 값을 입력하면 된다.)
  • 따라서 코드 가독성을 위해선 let someClosure: (_ name: String, _ age: Int) -> String 과 같은 형태로 매개변수 앞에 ‘_’을 사용하여 의미 명시를 해주는 것이 좋다.

Closure를 실제 프로젝트에서 사용하는 경우

  • 함수가 사용되는 모든 곳에서 사용
    • 함수를 만들지 않고, closure의 형태로 만들어서 바로 호출하여 사용하는 경우가 많음
  • 이벤트 처리
  • 고차함수에서 사용
    • 비동기 처리할 때 보통 사용
    • 콜렉션의 연산자들에서 사용

고차함수(high order function)에서 Closure를 매개변수로 사용하는 경우

  • 함수에서 Closure를 매개변수로 사용하는 경우의 일반적 이해
    // 일반적인 함수의 경우
    // 자료 형이 () -> Void고 값이 {} 니까 호출할 때 그대로 값을 넣어줌
    func saySomething(name: String) {
    	...
    }
    
    saySomething(name: "문자열 값")
    // Closure의 경우도 마찬가지라고 생각하면 쉬움
    func someFunction(completion: () -> Void) {
        print(#function)
        completion()
    }
    
    // someFunction을 호출할 때 saySomething(name: "문자열 값")과 마찬가지
    // 값을 그대로 넣어주는데, closure는 값이 {} 블럭이니까 {}을 그대로 넣어줌
    someFunction(completion: {
        print("completion 터트려짐")
    })
  • 코드에서 딜레이를 주는 예시
    // 현재로부터 2초의 딜레이 후 excute Closure를 실행
    // Closure를 밖에서 받게 하기 위해 @escaping 사용
    func someFunction(completion: @escaping () -> Void) {
        print(#function)
        DispatchQueue.main.asyncAfter(deadline: .now() + 2, execute: {
            completion()
        })
    }
    
    someFunction(completion: {
        print("completion 터트려짐")
    })
    
    // 호출시 다음과 같이 축약해서도 사용 가능 (가능하면 정석적인 방법을 사용하자)
    someFunction({
        print("completion 터트려짐")
    })
    
    someFunction{
        print("completion 터트려짐")
    }
    
    someFunction() {
        print("completion 터트려짐")
    }
  • 함수에서 Closure를 매개변수 및 반환 값이 있는 예시
    func someFunction(completion: (_ name: String) -> Void) {
        print(#function)
        completion("호롤롤로")
    }
    
    someFunction(completion: { name in
        print("completion 터트려짐 name: \(name)")
    })
    func someFunction(completion: (_ name: String) -> String) {
        print(#function)
        let result = completion("호롤롤로")
    		print(#function + "result: \(result)")
    }
    
    someFunction(completion: { (name: String) -> String in
        return "completion 터트려짐 name: \(name)"
    })
    
    //호출하는 부분에서 (name: String) -> String in 부분을 축약하여 name in 으로도 사용 가능
    someFunction(completion: { name in
        return "completion 터트려짐 name: \(name)"
    })

고차함수(high order function)에서 반환을 Closure로 하는 경우

  • 함수의 반환으로 Closure를 갖는 경우의 일반적 이해
    // 일반적인 함수의 경우
    func saySomething() -> String {
        return "리턴 스트링"
    }
    
    let value : String = satSomething()
    // 함수 반환으로 closure를 갖는 경우
    // Closure는 자료 형이다. Closure는 함수고, 함수는 Closure다.
    // Closure는 단순히 함수를 변수의 형태로 쓰는 것이다.
    // Closure는 값이 {} 블럭 형태이기에 return을 할 때 {}으로 리턴.
    func someFunction() -> () -> Void {
        return {
    				print("호호호")
    		}
    }
    
    let result : () -> Void = someFunction()
    
    result() 
    
    //결과
    호호호
  • 반환 클로저의 매개변수가 있는 예시
    func someFunction() -> (_ name: String) -> Void {
        return { (name: String) in
            print("안녕하세요! name: \(name)")
        }
    }
    
    let result : (_ name: String) -> Void = someFunction()
    
    result("Flamozzi")
    
    // 결과
    안녕하세요! name: Flamozzi
  • 매개변수 및 반환이 있는 예시
    func someFunction() -> (_ name: String) -> String {
        return { (name: String) in
            return "안녕하세요! name: \(name)"
        }
    }
    
    let result : (_ name: String) -> String = someFunction()
    
    let finalResult : String = result("Flamozzi")
    
    print(finalResult)
    
    // 결과
    안녕하세요! name: Flamozzi
profile
개발도 하고, 글도 적고

0개의 댓글