(※ hackingWithSwift의 글을 번역한 것으로 아래 출처를 남겨두었습니다. 약간의 오역이 있을 수 있으니 지적해주시면 감사드리겠습니다.)
if let을 이전보다 더 짧은 형태로 사용할 수 있게 되었다. '=' 표시없이 간결하게 사용할 수 있어서 훨씬 모던하게 느껴진다.
if let name = name { // 기존 if-let 사용법
Text("name: \(name)")
}
var name: String? = "Linda"
if let name { // 짧아진 if let 사용법
Text("name: \(name)")
}
기존 closure내에 '->' 표시로 리턴 타입을 명시했어야하는데 이제는 명시하지 않아도 실질적 return 타입을 스마트하게 인식하는 것 같다.
let scores = [100, 60, 30]
let newResutls = scores.map { score in // 리턴 타입 명시X
if let score > 85 {
return "Pass: \(score)"
} else {
return "Fail: \(score)"
}
}
let prevResults = scores.map { score -> String in
if let score > 85 {
return "Pass: \(score)"
} else {
return "Fail: \(score)"
}
}
time(시각)과 duration(지속시간)에 대해 Swift가 새롭고, 표준화된 방법을 선보였다고 하는데..
새롭게 업그레이드된 Task API에서 이를 적용하기 좋은데, 나노 초 단위보다 더 정밀하게 표현해주기 때문이다.
try await Task.sleep(until: .now() + .seconds(1), clock: .continuous)
또한, tolerance(성능을 극대화하기 위해 약간의 sleep deadline을 제공해줌)를 정확하게 표현하기도 좋다. 아래 코드를 보면, 적어도 1초 안에 sleep되는 것이 이상적이지만 0.5초 정도의 버퍼는 허용하는 것이다. (즉, 최대 1.5초 안에 sleep되기를 기대) tolerance를 사용할 때 명심할 것은 우리가 정의한 default sleep time에서 더 추가(+)되는 것을 의미한다.
try await Task.sleep(until: .now() + .seconds(1), tolerance: .seconds(0.5), clock: .continuous)
이렇게 되면, 근시일 내에 나노 초 단위가 없어질 것으로 보인다.
Clocks는 어떤 작업을 수행할 때 얼마나 걸렸는지 정확히 측정할 때 사용할 수 있는데, 예를 들면 사용자가 파일 '내보내기'할 때 얼마나 걸렸는지 등이 있다.
let clock = ContinuousClock()
let time = clock.measure {
// complex work here
}
print("Takes \(time.component.second) seconds")
(정규 표현식을 쓸 일이 아주 많지는 않지만, 알아두면 유용할 수 있으므로 어렵더라도 차근차근 알아보자!)
let message = "the cat sat on the mat"
// 평소에 익숙한 메소드
print(message.ranges(of: "at"))
print(message.replacing("cat", with: "dog"))
print(message.trimmingPrefix("the "))
// 정규 표현식에 대한 설명
// 소문자 a부터 z까지 at에 해당하는 range를 뽑아냄
print(message.ranges(of: /[a-z]at/))
// result: cat, sat, mat의 위치(인덱스) 추출
// 소문자 a부터 m까지 해당되는 at이 들어가는 단어를 dog로 바꿈
print(message.replacing(/a-m/at, with: "dog"))
// result: "the dog sat on the dog"
// The 혹은 the(대소문자 무시) 해당하는 단어를 trimmingPrefix
print(message.trimmingPrefix(/The/.ignoringCase()))
위에서 /[a-z]at/(regex literal) 로 표시한 방식과 비슷하게, Regex 타입을 사용하여 표현할 수 있다.
do {
let atSearch = try Regex("[a-z]at")
print(message.ranges(of: atSearch))
} catch {
print("fail to create Regex")
}
그러나, regex literal과 Regex의 큰 차이점은 정규 표현식을 사용할 때runtime에서 실행되는지, compiletime에서 실행되는지이다.
regex literal(/로 표기하기) 방식은 상당히 눈에 띄기 때문에, 반복을 견딘다. compiletime내에 유효성 검사를 하고, 정규 표현식을 parsing한다.
코드로 살펴보면,
let search1 = /My name is (.+?) and I'm (\d+) years old./
let greeting1 = "My name is Taylor and I'm 26 years old."
if let result = try search1.wholeMatch(in: greeting1) {
print("Name: \(result.1)") // Name: Taylor
print("Age: \(result.2)") // Age: 26
}
Swift는 Tuple방식으로 .1과 .2에 해당하는 것을 정확히 알고 리턴하게 된다. (궁금해할 경우를 대비하여, .0은 완전히 일치하는 String을 리턴한다.)
또한 정규 표현식을 사용할 때 명명할 수도 있는데, 바로 .1과 .2 라는 Tuple방식을 사용하는 것이 아닌 구체적인 이름으로 대신한다. (개인적으로 .1과 .2로 표현되는 Tuple방식이 깔끔해보일지 몰라도 웬만해선 naming을 사용해 구체적으로 명시하는 것이 좋다고 생각한다.)
let search2 = /My name is (?<name>.+?)/ and I'm (?<age>\d+) years old./
let greeting2 = "My name is Taylor and I'm 26 years old."
if let result = try search2.wholeMatch(in: greeting2) {
print("Name: \(result.name)")
print("Age: \(result.age)")
}
앞서 정규 표현식을 string으로 표현하는 법, regex literal로 표현하는 법을 알아봤는데 Swift는 한 발 더 나아가서, SwiftUI 코드와 유사하게 DSL(도메인 특화 언어,특정 도메인에만 국한되어 있는 언어)로도 정규 표현식을 만들 수 있다.
예를 들어, “My name is Taylor and I’m 26 years old” 와 동일시하기 위해 다음과 같이 코드를 쓸 수 있다.
let search3 = Regex {
"My name is"
Capture {
OneOrMore(.word)
}
" and I'm"
TryCapture {
OneOrMore(.digit)
} transform: { match in
Int(match)
}
Capture(.digit)
" years old."
}
이러한 접근 방식은 일종의 변형을 적용할 수 있는데, 예를 들어 String타입의 age를 Int형태로 타입을 변형하여 쓸 수 있다.
Capture말고도 TryCapture를 사용하면 실패 혹은 에러를 잡아내는 데 유용하다.
또한, 특정 타입과 함께 명명된 match를 찾고 싶은 경우 다음과 같이 표현될 수 있다.
let nameRef = Reference(Substring.self)
let ageRef = Reference(Int.self)
let search5 = Regex {
"My name is "
Capture(as: nameRef) {
OneOrMore(.word)
}
" and I'm"
TryCapture(as: ageRef) {
OneOrMore(.digit)
} transform: { match in
Int(match)
}
Capture(.digit)
" years old."
}
if let result = greeting.firstMatch(of: search5) {
print("Name: \(result[nameRef])")
print("Age: \(result[ageRef])")
}
(출처: https://www.hackingwithswift.com/articles/249/whats-new-in-swift-5-7)