Closure - ehrldyd15/Swift_Skills GitHub Wiki
ํด๋ก์ (Closure)๋?
-
ํด๋ก์ ๋ ์ฌ์ฉ์์ ์ฝ๋ ์์์ ์ ๋ฌ๋์ด ์ฌ์ฉํ ์ ์๋ ๋ก์ง์ ๊ฐ์ง ์ค๊ดํธโ{}โ๋ก ๊ตฌ๋ถ๋ ์ฝ๋์ ๋ธ๋ญ์ด๋ฉฐ, ์ผ๊ธ ๊ฐ์ฒด์ ์ญํ ์ ํ ์ ์๋ค.
-
์ผ๊ธ ๊ฐ์ฒด๋ ์ ๋ฌ ์ธ์๋ก ๋ณด๋ผ ์ ์๊ณ , ๋ณ์/์์ ๋ฑ์ผ๋ก ์ ์ฅํ๊ฑฐ๋ ์ ๋ฌํ ์ ์์ผ๋ฉฐ, ํจ์์ ๋ฐํ ๊ฐ์ด ๋ ์๋ ์๋ค.
-
์ฐธ์กฐ ํ์ ์ด๋ค.
-
ํจ์๋ ํด๋ก์ ์ ํ ํํ๋ก, ์ด๋ฆ์ด ์๋ ํด๋ก์ ์ด๋ค.
ํด๋ก์ ํํ
let reverseNames = names.sorted(by: { (s1: String, s2: String) -> Bool in return s1 > s2})
์์ ํํ์ ํด๋ก์ ๋ ํจ์๋ก ๋ฐ๋ก ์ ์๋ ํํ๊ฐ ์๋ ์ธ์๋ก ๋ค์ด๊ฐ ์๋ ์ธ๋ผ์ธ ํด๋ก์ ๋ผ๊ณ ๋ถ๋ฅธ๋ค.
ํด๋ก์ ์ถ์ฝ
- ํ์ ์๋ต
์์ ์์ ์์ sorted(by:)์ ๊ฒฝ์ฐ๋ ์ด๋ฏธ (string, string) -> Bool ํ์ ์ ์ธ์๊ฐ ๋ค์ด์์ผ ํ๋์ง ์๊ณ ์๊ธฐ ๋๋ฌธ์
ํด๋ก์ ์์ ํ์ ์ ๋ช ์ํ๋ ๊ฒ์ ์๋ต ํ ์ ์๋ค.
let reverseNames = names.sorted(by: {s1, s2 in return s1 > s2})
ํ์ง๋ง ์ฝ๋๋ฅผ ์์๋ณด๊ธฐ ํ๋ค๊ณ ๊ฐ์์ฑ์ด ์์ด์ ํ์ ์ ๋๋ ๋ช ์ํ๋๊ฒ์ด ์ข์
- ๋ฐํํ์ ์๋ต
๋ฐํ ํค์๋๋ฅผ ์๋ตํ๋๊ฒ์ด ๊ฐ๋ฅํ๋ค.
let reverseNames = names.sorted(by: {s1, s2 in s1 > s2})
- ์ธ์์ด๋ฆ ์๋ต
์ธ์ ๊ฐ์ ์ถ์ฝํด์ ์ฌ์ฉํ ์ ์๋ค. (์ธ์์ ํ๊ธฐ๋ $0๋ถํฐ ์์๋๋ก)
let reversedNames = names.sorted(by: { $0 > $1 })
- ์ฐ์ฐ์ ๋ฉ์๋
์ฐ์ฐ์๋ฅผ ์ฌ์ฉํ ์ ์๋ ํ์ ์ ์ฐ์ฐ์๋ง ๋จ๊ธธ ์ ์๋ค.
let reversedNames = names.sorted(by: > )
- ํํํด๋ก์
์ธ์๋ก ํด๋ก์ ๋ฅผ ๋ฃ๊ธฐ๊ฐ ๊ธธ๋ค๋ฉด ํํ ํด๋ก์ ๋ฅผ ์ฌ์ฉํ์ฌ ํจ์์ ๋ค์ ํํ ๊ฐ๋ฅ
let reversedNames = names.sorted() { $0 > $1 }
ํจ์์ ๋ง์ง๋ง ์ธ์๊ฐ ํด๋ก์ ์ด๊ณ , ํํ ํด๋ก์ ๋ฅผ ์ฌ์ฉํ๋ฉด ๊ดํธ"()"๋ฅผ ์๋ตํ ์ ์๋ค.
let reversedNames = names.sorted { $0 > $1 }
let reversedNames = names.sorted { (s1: String, s2: String) -> Bool in return s1 > s2 }
Value ์บก์ณ
ํด๋ก์ ๋ ํน์ ๋ฌธ๋งฅ์ ์์๋ ๋ณ์๊ฐ์ ์บ ์ณํ ์ ์๋ค.
์๋ณธ ๊ฐ์ด ์์ด์ ธ๋ ํด๋ก์ ๋ด๋ถ์์ ๊ทธ ๊ฐ์ ํ์ฉ ๊ฐ๋ฅํจ
func makeIncrementer(forIncrement amount: Int) -> () -> Int {
var runningTotal = 0
func incrementer() -> Int {
runningTotal += amount
return runningTotal
}
return incrementer
}
let plusTen = makeIncrementer(forIncrement: 10)
let plusSeven = makeIncrementer(forIncrement: 7)
// ํจ์๊ฐ ๊ฐ๊ธฐ ์คํ๋์ด๋ ์ค์ ๋ก๋ ๋ณ์ runnigTotal๊ณผ amount๊ฐ ์บก์ณ๋์ ๊ทธ ๋ณ์๋ฅผ ๊ณต์ ํ๊ธฐ ๋๋ฌธ์ ๋์ ๋ ๊ฒฐ๊ณผ๋ฅผ ๊ฐ์ง๋ค.
let plusedTen = plusTen() // 10
let plusedTen2 = plusTen() // 20
// ๋ค๋ฅธ ํด๋ก์ ์ด๊ธฐ ๋๋ฌธ์ ๊ณ ์ ์ ์ ์ฅ์์ runningTotal๊ณผ amount๋ฅผ ์บก์ณํด์ ์ฌ์ฉํ๋ค.
let plusedSeven = plusSeven() // 7
let plusedSeven2 = plusSeven() // 14
-
plusTen, plusSeven์ด ์์์ด์ง๋ง runningTotal์ ์ฆ๊ฐ์ํฌ ์ ์์๋ ์ด์ ๋ ํด๋ก์ ๊ฐ ์ฐธ์กฐํ์ ์ด๊ธฐ ๋๋ฌธ์ด๋ค.
ํจ์์ ํด๋ก์ ๋ฅผ ์์๋ ๋ณ์์ ํ ๋นํ ๋ ์ค์ ๋ก๋ ์์์ ๋ณ์์ ํด๋น ํจ์๋ ํด๋ก์ ์ ์ฐธ์กฐ๊ฐ ํ ๋น๋๋ค.
๋ง์ฝ ํ ํด๋ก์ ๋ฅผ ๋ ์์๋ ๋ณ์์ ํ ๋นํ๋ฉด ๊ทธ ๋ ์์๋ ๋ณ์๋ ๊ฐ์ ํด๋ก์ ๋ฅผ ์ฐธ์กฐํ๊ณ ์๊ฒ๋๋ ๊ฒ์ด๋ค.
-
์ต์ ํ๋ฅผ ์ด์ ๋ก Swift๋ ๊ทธ ๊ฐ์ด ํด๋ก์ ์ ์ํด ๋ณ๊ฒฝ๋์ง ์๊ณ , ํด๋ก์ ๊ฐ ์์ฑ๋ ํ ๊ฐ์ด ๋ณ๊ฒฝ๋์ง ์๋ ๊ฒฝ์ฐ ๊ฐ์ ๋ณต์ฌ๋ณธ์ ์บก์ณํ์ฌ ์ ์ฅํ๋ค.
-
๋ํ Swift๋ ๋ณ์๋ฅผ ๋ ์ด์ ํ์ํ์ง ์์ ๋ ์ฒ๋ฆฌํ๋ ๋ชจ๋ ๋ฉ๋ชจ๋ฆฌ ๊ด๋ฆฌ๋ฅผ ์ฒ๋ฆฌํ๋ค.
๋ง์ฝ ํด๋ก์ ๋ฅผ ์ด๋ค ํด๋์ค ์ธ์คํด์ค์ ํ๋กํผํฐ๋ก ํ ๋นํ๊ณ ๊ทธ ํด๋ก์ ๊ฐ ๊ทธ ์ธ์คํด์ค๋ฅผ ์บก์ณํ๋ฉด ๊ฐํ ์ํ ์ฐธ์กฐ์ ๋น ์ง๊ฒ ๋๋ค.
์ฆ, ์ธ์คํด์ค์ ์ฌ์ฉ์ด ๋๋๋ ๋ฉ๋ชจ๋ฆฌ๋ฅผ ํด์ ํ์ง ๋ชปํ๋ ๊ฒ์ด๋ค. ๊ทธ๋์ swift๋ ์ด ๋ฌธ์ ๋ฅผ ๋ค๋ฃจ๊ธฐ ์ํด ์บก์ณ ๋ฆฌ์คํธ๋ฅผ ์ฌ์ฉํ๋ค.
Escaping Closure
ํด๋ก์ ๊ฐ ํจ์์ ์ธ์๋ก ์ ๋ฌ๋์ง๋ง ํจ์ ๋ฐ์์ ์คํ๋๋๊ฒ(ํจ์๊ฐ ๋ฐํ๋ ํ ์คํ๋๋ ๊ฒ)์ Escapeํ๋ค๊ณ ํ๋ค.
์ด๋ฌํ ๊ฒฝ์ฐ ๋งค๊ฐ๋ณ์์ ํ์ ์์ @excaping์ด๋ผ๋ ํค์๋๋ฅผ ๋ช ์ํด์ผ ํ๋ค.
๋น๋๊ธฐ๋ก ์คํ๋๊ฑฐ๋ completionHandler(์๋ฃ์ ๋ฐ๋ฅธ ์ฒ๋ฆฌ)๋ก ์ฌ์ฉ๋๋ ํด๋ก์ ์ ๊ฒฝ์ฐ ์์ฃผ ์ฌ์ฉ๋๋ค.
์ผ๋ฐ ์ง์ญ๋ณ์๊ฐ ํจ์ ๋ฐ์์ ์ด์์๋ ๊ฒ์ ์ ์ญ๋ณ์๋ฅผ ํจ์์ ๊ฐ์ ธ์์ ๊ฐ์ ์ฃผ๋ ๊ฒ๊ณผ ๋ค๋ฆ์ด ์์ง๋ง,
ํด๋ก์ ์ Escaping์ ํ๋์ ํจ์๊ฐ ๋ง๋ฌด๋ฆฌ๋ ์ํ์์๋ง ๋ค๋ฅธ ํจ์๊ฐ ์คํ๋๋๋ก ํจ์๋ฅผ ์์ฑํ ์ ์๋ค๋ ์ ์์ ์ ๋ฆฌํ๋ค.
์ฆ, ์ด๋ฅผ ํ์ฉํด์ ํจ์ ์ฌ์ด์ ์คํ ์์๋ฅผ ์ ํ ์ ์๋ค.
var completionHandlers: [() -> Void] = []
func someFunctionWithEscapingClosure(completionHandler: @escaping () -> Void) {
completionHandlers.append(completionHandler)
}
์ ํจ์์์ ์ธ์๋ก ์ ๋ฌ๋ completionHandler๋ someFunctionWithEscapingClosureํจ์๊ฐ ๋๋๊ณ ๋์ค์ ์ฒ๋ฆฌ ๋๋ค.
๋ง์ฝ ํจ์๊ฐ ๋๋๊ณ ์คํ๋๋ ํด๋ก์ ์ @escapingํค์๋๋ฅผ ๋ถ์ด์ง ์์ผ๋ฉด ์ปดํ์ผ์ ์ค๋ฅ๊ฐ ๋ฐ์ํ๋ค.
@escaping์ ์ฌ์ฉํ๋ ํด๋ก์ ์์๋ self๋ฅผ ๋ช ์์ ์ผ๋ก ์ธ๊ธํด์ผํ๋ค.
var completionHandlers: [() -> Void] = []
func someFunctionWithEscapingClosure(completionHandler: @escaping () -> Void) {
completionHandlers.append(completionHandler)
}
func someFunctionWithNonescapingClosure(closure: () -> Void) {
closure() // ํจ์ ์์์ ๋๋๋ ํด๋ก์
}
class SomeClass {
var x = 10
func doSomething() {
someFunctionWithEscapingClosure { self.x = 100 } // ๋ช
์์ ์ผ๋ก self๋ฅผ ์ ์ด์ค์ผ ํ๋ค.
someFunctionWithNonescapingClosure { x = 200 }
}
}
let instance = SomeClass()
instance.doSomething()
print(instance.x) // 200
completionHandlers.first?()
print(instance.x) // 100
AutoClosure
์๋ ํด๋ก์ ๋ ์ธ์ ๊ฐ์ด ์์ผ๋ฉฐ ํน์ ํํ์ ๊ฐ์ธ์ ๋ค๋ฅธ ํจ์์ ์ ๋ฌ ์ธ์๋ก ์ฌ์ฉํ ์ ์๋ ํด๋ก์ ๋ฅผ ๋งํ๋ค.
์๋ ํด๋ก์ ๋ ํด๋ก์ ๋ฅผ ์คํํ๊ธฐ ์ ๊น์ง ์ค์ ์คํ์ด ๋์ง ์๋๋ค.
์ฆ, ์ค์ ๊ณ์ฐ์ด ํ์ํ ๋ ํธ์ถ์ด ๋๊ธฐ ๋๋ฌธ์ ๊ณ์ฐ์ด ๋ณต์กํ ์ฐ์ฐ์ ํ๋๋ฐ ์ ์ฉํ๋ค.
var customersInLine = ["Chris", "Alex", "Ewa", "Barry", "Daniella"]
print(customersInLine.count) // 5
let customerProvider = { customersInLine.remove(at: 0) } // ํด๋น ์ฝ๋๊ฐ ์ง๋๋ count๊ฐ ์ค์ง ์๋๋ค.
print(customersInLine.count) // 5
// customerProvider๊ฐ ์คํ๋์์๋๋ง ๋์
print("Now serving \(customerProvider())!") // "Now serving Chris!"
print(customersInLine.count) // 4
์๋ํด๋ก์ ๋ฅผ ํจ์์ ์ธ์ ๊ฐ์ผ๋ก ๋ฃ๋ ์์ ๋ ์๋์ ๊ฐ๋ค.
// customersInLine is ["Alex", "Ewa", "Barry", "Daniella"]
func serve(customer customerProvider: () -> String) {
print("Now serving \(customerProvider())!")
}
serve(customer: { customersInLine.remove(at: 0) } ) // "Now serving Alex!"
Serve ํจ์๋ ์ธ์๋ก () -> String(์ธ์๊ฐ ์๊ณ , Strign์ ๋ฐํํ๋ ํด๋ก์ )๋ฅผ ๊ฐ์ง๋ค.
๊ทธ๋ฆฌ๊ณ ์ด ํจ์๋ฅผ ์คํํ ๋ serve(customer: { customersInLine.remove(at: 0) } )์ ๊ฐ์ด ํด๋ก์ ๋ฅผ ๋ช ์์ ์ผ๋ก ์ง์ ๋ฃ์ ์ ์๋ค.
@autoclosure ํค์๋๋ฅผ ์ด์ฉํด์ ๋ณด๋ค ๊ฐ๊ฒฐํ๊ฒ ์ฌ์ฉํ ์ ์๋ค.
// customersInLine is ["Ewa", "Barry", "Daniella"]
func serve(customer customerProvider: @autoclosure () -> String) {
print("Now serving \(customerProvider())!")
}
serve(customer: customersInLine.remove(at: 0)) // "Now serving Ewa!"
@autoclosure ํค์๋๋ฅผ ๋ถ์์ผ๋ก์จ ์ธ์ ๊ฐ์ ์๋์ผ๋ก ํด๋ก์ ๋ก ๋ณํ ๋๋ค. ๊ทธ๋ก์ธํด ์ธ์์ ์ค๊ดํธ๋ฅผ ๋ฃ์ง ์์๋ ๋๋ค.
์๋ํด๋ก์ ๋ฅผ ๋๋ฌด ๋จ์ฉํ๋ฉด ์ฝ๋๋ฅผ ์ดํดํ๊ธฐ ์ด๋ ค์ธ ์ ์๋ค. ๋ฐ๋์ autoclosure๋ฅผ ์ฌ์ฉํ๊ธฐ ๋ถ๋ช ํ ๊ฒฝ์ฐ์๋ง ์ฌ์ฉํด์ผ ํ๋ค.
@autoclosure๋ @escaping๊ณผ ๊ฐ์ด ์ฌ์ฉํ ์ ์๋ค.
var customersInLine = ["Barry", "Daniella"]
var customerProviders: [() -> String] = [] // ํด๋ก์ ๋ฅผ ์ ์ฅํ๋ ๋ฐฐ์ด์ ์ ์ธ
func collectCustomerProviders(_ customerProvider: @autoclosure @escaping () -> String) {
customerProviders.append(customerProvider)
} // ํด๋ก์ ๋ฅผ ์ธ์๋ก ๋ฐ์ ๊ทธ ํด๋ก์ ๋ฅผ customerProviders ๋ฐฐ์ด์ ์ถ๊ฐํ๋ ํจ์๋ฅผ ์ ์ธ
collectCustomerProviders(customersInLine.remove(at: 0)) // ํด๋ก์ ๋ฅผ customerProviders ๋ฐฐ์ด์ ์ถ๊ฐ
collectCustomerProviders(customersInLine.remove(at: 0))
print("Collected \(customerProviders.count) closures.") // 2๊ฐ์ ํด๋ก์ ๊ฐ ์ถ๊ฐ ๋จ
// Prints "Collected 2 closures."
for customerProvider in customerProviders {
print("Now serving \(customerProvider())!") // ํด๋ก์ ๋ฅผ ์คํํ๋ฉด ๋ฐฐ์ด์ 0๋ฒ์งธ ์์๋ฅผ ์ ๊ฑฐํ๋ฉฐ ๊ทธ ๊ฐ์ ์ถ๋ ฅ
}
// Prints "Now serving Barry!"
// Prints "Now serving Daniella!"
๊ณ ์ฐจ ํจ์
ํจ์์ ์ธ์๋ก ๋ค๋ฅธ ํจ์๋ฅผ ๋ฐ๋ ํจ์
1. map
์ฝ๋ ์ ๋ด๋ถ์ ๊ธฐ์กด ๋ฐ์ดํฐ๋ฅผ ๋ณํํ์ฌ ์๋ก์ด ์ฝ๋ ์ ์์ฑ
let numbers: [Int] = [2,8,15]
var newNumbers: [Int] = numbers.map { $0 + 1 } // [3, 9, 16]
2. fillter
์ฝ๋ ์ ๋ด๋ถ์ ๋ฐ์ดํฐ๋ฅผ ์กฐ๊ฑด์ ๋ง๋ ์๋ก์ด ์ฝ๋ ์ ์ผ๋ก ์์ฑ
let numbers: [Int] = [2,8,15]
var newNumbers: [Int] = numbers.filter { $0 % 2 == 0} // [2, 8]
3. reduce
์ปจํ ์ด๋ ๋ด๋ถ์ ์ฝํ ์ธ ๋ฅผ ํ๋๋ก ํตํฉ(ex. Element๋ค์ ์ดํฉ, ์ด๊ณฑ ๋ฑ)
let numbers: [Int] = [2,8,15]
// ์ด๊ธฐ๊ฐ์ด 3์ ์ ์ ๋ฐฐ์ด์ ๋ชจ๋ ๊ฐ์ ๋ํ๋ค.
var sum: Int = numbers.reduce(3) { $0 + $1 } // 28
์ฐธ๊ณ ์๋ฃ
https://medium.com/@jgj455/%EC%98%A4%EB%8A%98%EC%9D%98-swift-%EC%83%81%EC%8B%9D-closure-aa401f76b7ce