Swift 5.7버전이 발표되면서 새로 갱신된 기능에 대한 소개를 받았다.
<if let(var) 후 신규 변수명 생성 생략>
// 옵셔널이 되면 nil 값이 될 수도 있고 아닐 수도 있다
var name: String?
if let myName = name {
print("\(myName)")
} else {
print("nil입니다")
}
name = "ned"
if let name = name {
print("\(name)")
} else {
print("nil입니다")
}
// Swift 5.7의 신기능!
if let name {
print("\(name)")
} else {
print("nil입니다")
}
<???>
func sayHello(name: String?) {
guard let name else {
return print("nil입니다")
}
print("Hello World!")
}
sayHello(name: "ned")
sayHello(name: nil)
func sayHello(name: String?) {
guard let _ = name else {
return print("nil입니다")
}
print("Hello World!")
}
sayHello(name: "ned")
sayHello(name: nil)
1. 오전일정 : 클로저
클로저
- 함수와 역할은 같지만 생긴 구조가 다르다. 함수를 결과(return)으로 반환한다.
- 아래 코드에서 functionA는 functionB라는 이름의 함수( () -> Int )를 반환한다.
func functionA() -> () -> Int {
var counter = 0
func functionB() -> Int {
return counter + 10
}
return functionB
}
let myClosure = functionA()
let result = functionB()
// 간단한 클로저 예제
func functionA() -> () -> Int {
var counter = 5
// functionA 함수 안에 functionB 함수 선언 - 중첩된 함수
func functionB() -> Int {
// functionB 밖의 counter를 사용한 계산값을 반환한다
return counter + 30
}
let result = functionB()
print("\(result)")
// functionB() 이것은 functionB를 호출하는 문구
// functionB 이것은 functionB 함수 그 자체를 지칭함
return functionB
}
// functionA() 호출의 결과는 functionB 함수이고
// functionB 함수 안에는 counter값이 계속 붙잡혀 활용이 된다
// myClosure가 곧 functionB이기 때문에 myClosure가 존재하는 동안 counter도 붙잡혀 존재한다
let myClosure = functionA()
print("\(myClosure())")
- map, reduce, filter, sorted 기능을 클로저를 통해서 확장을 할 수 있음
- Swift의 클로저는 다른 프로그래밍 언어의 람다와 유사함
- 클로저는 참조타입이다.(Class 작성과 같이 동작함) 따라서 참조가 없는 다른 클로저는 만들려면 새로 생성해야 한다.
/ 캡처값 예제
func makeIncrementer(forIncrement amount: Int) -> () -> Int {
var runningTotal: Int = 0
func incrementer() -> Int {
runningTotal += amount
return runningTotal
}
return incrementer
}
// 생성된 반환되는 함수는 runningTotal = 0,amount = 10으로 캡쳐되어 작동
let increFuncTen = makeIncrementer(forIncrement: 10)
// 생성된 반환되는 함수는 runningTotal = 0,amount = 7로 캡쳐되어 작동
let increFuncSeven = makeIncrementer(forIncrement: 7)
print("\(increFuncTen())") // 0 + 10 = 10
print("\(increFuncSeven())") // 0 + 7 = 7
print("\(increFuncTen())") // 10 + 10 = 20
print("\(increFuncSeven())") // 7 + 7 = 14
print("\(increFuncTen())") // 20 + 10 = 30
print("\(increFuncSeven())") // 14 + 7 = 21
// 두 함수의 관계는 참조 타입이라는 걸 알아보려 한다.
// 동일한 runningTotal 값을 공유하고 있다.
let alsoIncreFuncTen = increFuncTen
print("\(increFuncTen())") // 30 + 10 = 40
print("\(alsoIncreFuncTen())") // 0 + 10 = 10 ? -> 실제로는 50
print("\(increFuncTen())") // 40 + 10 = 50 ? -> 실제로는 60
// 필요하면 새로 만들어야...
let myIncreFuncTen = makeIncrementer(forIncrement: 10)
print("\(myIncreFuncTen())") // 0 + 10 = 10
정렬 메서드
- Swift 표준 라이브에서 sorted(by:) 메서드 제공함
- 기존 배열은 sorted(by:)로 수정되지 않고, 정렬된 요소를 새로운 배열로 반환함
- sorted(by:)에서 by의 매개변수로 클로저가 들어가야 한다.
ex) sorted(by: (self.String , self.String) -> Bool)
let names1 = ["one", "two", "three", "four", "five"]
var defualtSorted = names1.sorted(by: >) //내림차순 출력, '>' 가 최소한의 클로저 표현식이다
print(defualtSorted)
func backward(s1:String, s2:String) -> Bool {
return s1 > s2
}
let names2 = ["one", "two", "three", "four", "five"]
var reverseSorted = names2.sorted(by: backward)
print(reverseSorted) //내림차순 출력
//해당 정렬 클로저는 (String, String) -> Bool 타입의 함수를 필요로 함
- 클로저 표현식 예시.... 이거 음... 화이팅...?
// 배열 정렬 예제
let names = ["Chris", "Alex", "Ewa", "Barry", "Daniella"]
var defaultNames = names.sorted()
print(defaultNames)
// 정렬 기준을 만들어주는 함수 만들기
func backward(_ s1: String, _ s2: String) -> Bool {
print("\(s1)과 \(s2)를 비교합니다")
return s1 > s2
}
var reverseNames = names.sorted(by: backward)
print(reverseNames)
//전역함수 backwarddhk 똑같이 작동하는 클로저 표현식
//인라인 클로저라는 구현법으로 by: 에 바로 써서 보낸다
reverseNames = names.sorted(by: { (_ s1: String, _ s2: String) -> Bool in
return s1 > s2
})
print(reverseNames)
//한줄로 가능
reverseNames = names.sorted(by: { (_ s1: String, _ s2: String) -> Bool in return s1 > s2 })
print(reverseNames)
//더 짧게
//배열이 String으로 채워진걸 아니까... 타입추론...?
reverseNames = names.sorted(by: { (_ s1, _ s2) -> Bool in return s1 > s2 })
print(reverseNames)
//더더 짧게
//정렬 클로저는 메서드에 인자로 전달되기 때문에 Swift는 파라미터 타입과 반환 값의 타입을 유추할 수 있다.
reverseNames = names.sorted(by: { s1, s2 in return s1 > s2 })
print(reverseNames)
//더더더 짧게
//ㅇㅅㅇ
reverseNames = names.sorted(by: { s1, s2 in s1 > s2 })
print(reverseNames)
//더더더더 짧게
//짧은 인자이름으로 대체 ㅇㅅㅇ??
reverseNames = names.sorted(by: { $0 > $1 }) //첫번째, 두번째 요소값을 사용하는 Swift 약속
//더더더더더 짧게
//연산자 메소드 사용 ㅇㅅㅇ;;
reverseNames = names.sorted(by: >)
/*
Alex과 Chris를 비교합니다
Ewa과 Alex를 비교합니다
Ewa과 Chris를 비교합니다
Barry과 Alex를 비교합니다
Barry과 Chris를 비교합니다
Daniella과 Alex를 비교합니다
Daniella과 Barry를 비교합니다
Daniella과 Chris를 비교합니다
Daniella과 Ewa를 비교합니다
["Ewa", "Daniella", "Chris", "Barry", "Alex"]
*/
2. 오후일정 : 이스케이프 클로저 & Objective-C
이스케이프 클로저
// 이스케이프 클로저 (Escaping Closures) 예제
var completionHandlers: [() -> Void] = []
func someFunctionWithEscapingClosures(completionHandler: @escaping () -> Void ) {
completionHandlers.append(completionHandler)
}
func someFunctionWithNonescapingClosures(closure: () -> Void) {
closure()
}
class SomeClass {
var x = 0
func doSomething() {
someFunctionWithEscapingClosures { () -> Void in
print("Hello")
self.x = 100
}
someFunctionWithNonescapingClosures { () -> Void in
print("World")
x = 200
}
}
}
let instance = SomeClass()
instance.doSomething()
print("someFunctionWithNonescapingClosures - x : \(instance.x)") // 당연히 200
if let completionHandler = completionHandlers.first {
completionHandler()
print("someFunctionWithEscapingClosures - x : \(instance.x)") // 200이 아니라 100
}
Objective-C 미리보기 (내일 배울거 소개)
3. 오늘의 리뷰
맨날 블로그 다 써놓고 등록을 안하는 이유는 뭘까... 빠른 퇴근을 원하기 때문인가....ㅎㅎ
'멋쟁이사자처럼 앱스쿨 1기' 카테고리의 다른 글
[멋쟁이사자처럼] 앱스쿨 1기 - Objective-C (16일차 22.10.07) (0) | 2022.10.07 |
---|---|
[멋쟁이사자처럼] 앱스쿨 1기 - Objective-C (15일차 22.10.06) (2) | 2022.10.06 |
[멋쟁이사자처럼] 앱스쿨 1기 - Swift 에러 핸들링&열거형(Enum)&제너릭(Generics) (13일차 22.10.04) (0) | 2022.10.04 |
[멋쟁이사자처럼] 앱스쿨 1기 - 구조체(Struct)&Swift 컬렉션&property wrapper (12일차 22.09.29) (2) | 2022.09.30 |
[멋쟁이사자처럼] 앱스쿨 1기 - 클래스&프로토콜 (10일차 22.09.27) (0) | 2022.09.27 |