Skip to content

Latest commit

ย 

History

History

Folders and files

NameName
Last commit message
Last commit date

parent directory

..
ย 
ย 

README.md

ํด๋กœ์ €(Closure)

๐Ÿ’ก ํด๋กœ์ €๋ž€? ์ด๋ฆ„์—†๋Š” ํ•จ์ˆ˜๋ผ๊ณ  ์ƒ๊ฐํ•˜๋ฉด๋œ๋‹ค! ํ•จ์ˆ˜์™€ ์™„์ „ํžˆ ๊ธฐ๋Šฅ์ด ๋™์ผํ•˜๋ฉฐ, ํ˜•ํƒœ๋งŒ ๋‹ค๋ฅด๋‹ค.


ํด๋กœ์ € ๊ธฐ๋ณธ

  • ์Šค์œ„ํ”„ํŠธ๋Š” ํ•จ์ˆ˜๋ฅผ ์ผ๊ธ‰๊ฐ์ฒด๋กœ ์ทจ๊ธ‰โ†’ ํ•จ์ˆ˜๋„ ํƒ€์ž…์ด๋ผ๋Š” ๋œป์ด๋‹ค.
// ํ•จ์ˆ˜์˜ ํƒ€์ž… ํ‘œ๊ธฐ๋ฒ•
let functionA: (String) -> (String)
let functionB: (Int) -> ()

  • ํด๋กœ์ €์˜ ๊ธฐ๋ณธํ˜•ํƒœ
// ํ•จ์ˆ˜
func aFunction(str: String) -> String {
	return "Hello, \(str)"
}

// ๊ฐ™์€ ๊ธฐ๋Šฅ์œผ๋กœ, ํด๋กœ์ €์ผ๋•Œ
let _ = {(str: String) -> String in 
	return "Hello, \(str)"
}

// ํ•จ์ˆ˜์ฒ˜๋Ÿผ ์•ˆ๋ณด์ด์ง€๋งŒ ํด๋กœ์ €์ด๋‹ค.
let aClosureType = { print("์•ˆ๋…•") }

aClosureType() // ์•ˆ๋…•

์ค‘๊ด„ํ˜ธ๋Š” ํด๋กœ์ €(ํ•จ์ˆ˜)์ด๋‹ค ๋ผ๋Š” ์ƒ๊ฐ์˜ ์ „ํ™˜์ด ํ•„์š”ํ•˜๋‹ค.


  • ๋ณ€์ˆ˜์— ํ•จ์ˆ˜(ํด๋กœ์ €) ๋‹ด๊ธฐ
func aFunction1(_ param: String) -> String {
	return param + "!"
}

var a: (String) -> String = aFunction1

a("์•ˆ๋…•") // ์•ˆ๋…•!

ํ•จ์ˆ˜๋Š” ์ผ๊ธ‰๊ฐ์ฒด์ด๊ธฐ ๋•Œ๋ฌธ์— ๋ณ€์ˆ˜์— ํ• ๋‹น์ด ๊ฐ€๋Šฅํ•˜๋‹ค.


  • ๊ฐ€์žฅ ๋งŽ์ด ์‚ฌ์šฉํ•˜๋Š” ํ˜•ํƒœ
let aClosure1 = { (str: String) in
	return "Hello, \(str)"
}

let aClosure2 = { param in
	return param + "!"
}

์œ„ ์ฝ”๋“œ๋ฅผ ๋ณด๋ฉด ๋ฆฌํ„ดํ˜•์— ๋Œ€ํ•œ ํ‘œ๊ธฐ, ํŒŒ๋ผ๋ฏธํ„ฐ ํƒ€์ž… ์ƒ๋žต์ด ๊ฐ€๋Šฅํ•˜๋‹ค.


  • ํด๋กœ์ €๋ฅผ ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ ๋ฐ›์„ ๊ฒฝ์šฐ โ†’ ํด๋กœ์ €์˜ ์‚ฌ์šฉ์ด์œ 
func closureParamFunction(closure: () -> ()) {
	print("ํ”„๋ฆฐํŠธ ์‹œ์ž‘")
	closure()
}

// ์ผ๋ฐ˜์ ์œผ๋กœ ํด๋กœ์ €๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•
closureParamFunction(closure: {
	print("ํ”„๋ฆฐํŠธ ์ข…๋ฃŒ")
})

์ด๋ ‡๊ฒŒ ๋”ฐ๋กœ ๋ณ€์ˆ˜์— ๋‹ด์ง€ ์•Š์•„๋„ ๋งค๊ฐœ๋ณ€์ˆ˜์— ๋ฐ”๋กœ ํด๋กœ์ €๋ฅผ ์ •์˜ํ•˜์—ฌ ์ „๋‹ฌํ•  ์ˆ˜ ์žˆ๋‹ค. ์ด๋•Œ, ํ•จ์ˆ˜๋ฅผ ์‹คํ–‰ํ• ๋•Œ ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ ์ „๋‹ฌํ•˜๋Š” ํ•จ์ˆ˜๋ฅผ Callbackํ•จ์ˆ˜๋ผ๊ณ  ํ•œ๋‹ค.


ํด๋กœ์ € ๋ฌธ๋ฒ• ์ตœ์ ํ™”


  • ํ›„ํ–‰ ํด๋กœ์ € ๋ฌธ๋ฒ•(trailing closure)
func closureParamFunction(closure: () -> ()) {
	print("ํ”„๋ฆฐํŠธ ์‹œ์ž‘")
	closure()
}

closureParamFunction {
	print("ํ”„๋ฆฐํŠธ ์ข…๋ฃŒ")
}

์†Œ๊ด„ํ˜ธ๋ฅผ ์•„์˜ˆ ์ƒ๋žตํ•ด๋ฒ„๋ฆด ์ˆ˜ ์žˆ๋‹ค.


  • ํ›„ํ–‰ ํด๋กœ์ €์—์„œ ํ•จ์ˆ˜ ์ด์™ธ์— ๋งค๊ฐœ๋ณ€์ˆ˜๋„ ๋ฐ›๋Š” ๊ฒฝ์šฐ
func closureCaseFunction(a: Int, b: Int, closure: (Int) -> Void) {
	let c = a + b
	closure(c)
}

closureCaseFunction(a: 5, b: 2) { number in
	print("์ถœ๋ ฅํ• ๊นŒ์š”? \(number)")
}

  • ์•„๊ทœ๋จผํŠธ ์ด๋ฆ„ ์ถ•์•ฝ
func performClosure(param: (String) -> Int) {
	pram("Swift")
}

performClosure { $0.count }

ํด๋กœ์ € ์‹ค์ œ ํ™œ์šฉ ์˜ˆ์‹œ

  • Timer์˜ scheduledTimer๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๋ฐ˜๋ณต์ ์œผ๋กœ ํŠน์ • ํด๋กœ์ €๋ฅผ ๋ฐ˜๋ณตํ•  ์ˆ˜ ์žˆ๋‹ค.
// repeats๋ฅผ true๋กœ ํ•˜๋ฉด 1์ดˆ๋งˆ๋‹ค ๋ฐ˜๋ณตํ•จ
Timer.scheduledTimer(withTimeInterval: 1, repeats: false) { t in
	print("1์ดˆ๋’ค ์ถœ๋ ฅํ•˜๊ธฐ")
}

  • ๋ฉ€ํ‹ฐํ”Œ ํŠธ๋ ˆ์ผ๋ง ํด๋กœ์ €
func multipleclosure(first: () -> (), second: () -> (), third: () -> ()) {
	first()
	second()
	third()
}

multipleClosure {
	// code
} second: {
	// code
} third: {
	// code
}

  • ํ”„๋กœ์ ํŠธ์—์„œ ๋งŽ์ด ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ์‹
let emailTextField: UITextField = {
	let tf = UITextField()
	tf.placeholder = "Email"
	tf.backgroundColor = UIColor(...)
	tf.font = UIFont.systemFont(ofSize: 14)
	return tf
}()

@escaping / @autoclosure ํ‚ค์›Œ๋“œ

  • @escaping ํ‚ค์›Œ๋“œ โ†’ ํด๋กœ์ €๋ฅผ ์ œ๊ฑฐํ•˜์ง€ ์•Š๊ณ  ํ•จ์ˆ˜์—์„œ ํƒˆ์ถœ ์‹œํ‚ค๊ฒŒํ•ด์ฃผ๋Š” ํ‚ค์›Œ๋“œ
var aSavedFunction: () -> () = { print("์ถœ๋ ฅ") }

func perfomrEscaping(closure: @escaping: () -> ()) {
	aSavedFunction = closure
}

performEscaping2(closure: { print("๋‹ค๋ฅด๊ฒŒ ์ถœ๋ ฅ") })

aSavedFunction() // print("๋‹ค๋ฅด๊ฒŒ ์ถœ๋ ฅ")

@escapingํ‚ค์›Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•จ์œผ๋กœ์จ ํž™ ์˜์—ญ์— ์ €์žฅํ•ด์„œ ๋” ์˜ค๋ž˜ ์œ ์ง€ํ•  ์ˆ˜ ์žˆ๋‹ค.


  • @autoclosure ํ‚ค์›Œ๋“œ โ†’ ์ž๋™์œผ๋กœ ํด๋กœ์ €๋ฅผ ๋งŒ๋“ค์–ด์ฃผ๋Š” ํ‚ค์›Œ๋“œ
func someFunction(closure: @autoclosure () -> Bool) {
	if closure() {
		print("์ฐธ์ž…๋‹ˆ๋‹ค.")
	} else {
		print("๊ฑฐ์ง“์ž…๋‹ˆ๋‹ค.")
	}
}

var num = 1

// ์ž๋™ ์™„์„ฑ์‹œ someFunction(closure: Bool)๋กœ ๋œธ
someFunction(closure: { true })

์ผ๋ฐ˜์ ์œผ๋กœ ํด๋กœ์ € ํ˜•ํƒœ๋กœ ์จ๋„ ๋˜์ง€๋งŒ, ๋„ˆ๋ฌด ๋ฒˆ๊ฑฐ๋กœ์šธ ๋•Œ ์‚ฌ์šฉํ•œ๋‹ค. ๋ฒˆ๊ฑฐ๋กœ์›€์„ ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ์ง€๋งŒ ์‹ค์ œ ์ฝ”๋“œ๊ฐ€ ๋ช…ํ™•ํ•ด ๋ณด์ด์ง€ ์•Š์„ ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ ์‚ฌ์šฉ์„ ์ง€์–‘ํ•ด์•ผ ํ•œ๋‹ค.


ํด๋กœ์ €์™€ ๋ฉ”๋ชจ๋ฆฌ

๐Ÿ’ก ์บก์ฒ˜ํ˜„์ƒ ํด๋กœ์ €๋Š” ํž™์˜ ์˜์—ญ์— ์กด์žฌํ•ด์•ผํ•˜๊ณ , ํด๋กœ์ € ๋‚ด๋ถ€์—์„œ ์™ธ๋ถ€์— ์กด์žฌํ•˜๋Š” ๋ณ€์ˆ˜๋ฅผ ๊ณ„์† ์‚ฌ์šฉํ•ด์•ผํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์ž์‹ ์ด ์ฐธ์กฐํ•˜๋Š” ์™ธ๋ถ€ ๋ณ€์ˆ˜๋ฅผ ์บก์ฒ˜ํ•˜๋Š” ํ˜„์ƒ์ด๋‹ค.


  • ์บก์ฒ˜ ํ˜„์ƒ
func calculate() -> ((Int) -> Int) {
	var sum = 0

	func square(num: Int) -> Int {
		sum += (num * num)
		return sum
	}

	return square
}

// ํ•จ์ˆ˜๋ฅผ ๋ณ€์ˆ˜์— ํ• ๋‹นํ•˜๋Š” ์ˆœ๊ฐ„ ํด๋กœ์ €์™€ ๋˜‘๊ฐ™์ด ๋™์ž‘ํ•œ๋‹ค.
var squareFunc = calculateFunc()

squareFunc(10) // 100
squareFunc(20) // 500
squareFunc(30) // 1400

// ๋ณ€์ˆ˜ sum์ด ์บก์ณํ˜„์ƒ์œผ๋กœ ๋ˆ„์ ๋จ

  • ๊ฐ’ ํƒ€์ž… ์บก์ฒ˜์™€ ์บก์ฒ˜ ๋ฆฌ์ŠคํŠธ
var num = 1

let valueCaptureClosure = {
	print("๋ฒจ๋ฅ˜๊ฐ’ ์ถœ๋ ฅ: \(num)")
}

num = 7
valueCaptureclosure() // ๋ฒจ๋ฅ˜๊ฐ’ ์ถœ๋ ฅ: 7

num = 1

let valueCaptureListClosure = { [num] in
	print("๋ฒจ๋ฅ˜๊ฐ’ ์ถœ๋ ฅ(์บก์ฒ˜๋ฆฌ์ŠคํŠธ): \(num)")
}
num = 7
valueCaptureListClosure() // ๋ฒจ๋ฅ˜๊ฐ’ ์ถœ๋ ฅ(์บก์ฒ˜๋ฆฌ์ŠคํŠธ): 1

ํด๋กœ์ €๋Š” ์ž์‹ ์ด ์‚ฌ์šฉํ•  ์™ธ๋ถ€์˜ ๋ณ€์ˆ˜๋ฅผ ์บก์ณํ•œ๋‹ค. ๋”ฐ๋ผ์„œ ๋ฒจ๋ฅ˜ํƒ€์ž…์˜ ๋ฉ”๋ชจ๋ฆฌ ์ฃผ์†Œ๋ฅผ ์บก์ฒ˜ํ•˜์—ฌ 7์ด ๋‚˜์˜ค๋Š” ๊ฒƒ์„ ๋ณผ ์ˆ˜ ์žˆ๋‹ค. ํ•˜์ง€๋งŒ ์บก์ฒ˜ ๋ฆฌ์ŠคํŠธ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๊ฐ’์„ ๋ณต์‚ฌํ•ด์„œ ๋‹ด๊ธฐ ๋•Œ๋ฌธ์—


  • ์ฐธ์กฐ ํƒ€์ž… ์บก์ฒ˜์™€ ์บก์ฒ˜ ๋ฆฌ์ŠคํŠธ
class SomeClass {
	var num = 0
}

var x = SomeClass()
var y = SomeClass()

// x.num = 0, y.num = 0

let refTypeCapture = { [x] in
	print(x.num, y.num)
}

x.num = 1
y.num = 1

refTypeCapture() // x.num = 1, y.num = 1

์œ„ ์ฝ”๋“œ๋ฅผ ๋ณด๋ฉด ์บก์ฒ˜๋ฆฌ์ŠคํŠธ์—์„œ x๋Š” ์ง์ ‘ ์ฐธ์กฐ, y๋Š” ๋ณ€์ˆ˜๋ฅผ ์บก์ณํ•ด์„œ y ๋ณ€์ˆ˜๋ฅผ ๊ฐ€๋ฅดํ‚ค๋Š” ๊ฒƒ์„ ๋ณผ ์ˆ˜ ์žˆ๋‹ค. ๊ฒฐ๊ตญ ๊ฑฐ์ณ์„œ ์ฐธ์กฐํ•˜๋ƒ ์•„๋‹ˆ๋ฉด ์ง์ ‘ ์ฐธ์กฐํ•˜๋ƒ์˜ ์ฐจ์ด์ด๊ธฐ ๋•Œ๋ฌธ์— ๋‘˜๋‹ค 1๋กœ ๋ฐ”๋€Œ๋Š” ๊ฒƒ์„ ๋ณผ ์ˆ˜ ์žˆ๋‹ค.


๊ฐ์ฒด ๋‚ด์—์„œ ํด๋กœ์ €์˜ ์‚ฌ์šฉ

  • ์ผ๋ฐ˜์ ์ธ ํด๋กœ์ €์˜ ์‚ฌ์šฉ
class Dog {
	var name = "์ดˆ์ฝ”"

	func doSomething() {
		// ๋น„๋™๊ธฐ ์‹คํ–‰ ํด๋กœ์ € ==> ๋ณ€์ˆ˜๋ฅผ ์˜ค๋žซ๋™์•ˆ ์ €์žฅํ•  ํ•„์š”๊ฐ€ ์žˆ์Œ
		DispatchQueue.global().async { [self] in
			print("๋‚˜์˜ ์ด๋ฆ„์€ \(name)์ž…๋‹ˆ๋‹ค.") // ๋˜๋Š” self.name
		}
	}
	func doSomething1() {
		// ์•ฝํ•œ ์ฐธ์กฐ๋กœ RC๊ฐ€ ์˜ฌ๋ผ๊ฐ€์ง€ ์•Š์Œ
		DispatchQueue.global().async { [weak self] in
			print("๋‚˜์˜ ์ด๋ฆ„์€ \(self?.name)์ž…๋‹ˆ๋‹ค.")
		}
	}
	func doSomething2() {
		// 
		DispatchQueue.global().async { [weak self] in
			guard let weakSelf = self else { return }
			print("๋‚˜์˜ ์ด๋ฆ„์€ \(weakSelf.name)์ž…๋‹ˆ๋‹ค.")
		}
	}
}

var choco = Dog()
choco.doSomething()