map(), filter(), compactMap()이 예시이다.
예시로 아래 코드가 있다.
// 1
let numbers = [1, 2, 3, 4, 5]
var evens = [Int]()
for number in numbers {
if number.isMultiple(of: 2) {
evens.append(number)
}
}
// 2
let numbers = [1, 2, 3, 4, 5]
let evens = numbers.filter { $0.isMultiple(of: 2) }
2의 경우 filter를 사용해서 상수로 evens
를 간단히 설정할 수 있다.
let numbers = ["1", "2", "fish", "3"]
let evensMap = numbers.map(Int.init)
let evensCompactMap = numbers.compactMap(Int.init)
거기에 더해 compactMap()은 nil을 제외하고 evensCompactMap
을 생성한다.
Result는 Optional과 닮았지만, if let과 같은 syntactic sugar가 없다. 그리고 throw 함수와 바꿔 사용할 수 있고, Result의method인 map(), mapError()를 사용할 수 있다.
Your challenge this time can be easy or hard depending on how far you want to take it, but at its core the project is simple: you need to build an app that helps users roll dice then store the results they had.
At the very least you should lets users roll dice, and also let them see results from previous rolls. However, if you want to push yourself further you can try one or more of the following:
textfield에서 정수를 입력받고 0 이하 값은 에러 메시지를 보여준다.
@State private var maxNumber = 6
@State private var isShowingErrorMessage = false
var body: some View {
VStack {
Spacer()
VStack(alignment: .leading) {
TextField("Max number of the dice", value: $maxNumber, formatter: NumberFormatter())
.font(.largeTitle)
.keyboardType(.numberPad)
if isShowingErrorMessage {
Text("Only numbers bigger than 0 is possible")
.foregroundStyle(.secondary)
}
}
Spacer()
Button(action: {
if maxNumber < 1 {
isShowingErrorMessage = true
} else {
isShowingErrorMessage = false
}
}, label: {
Text("Let's Roll")
.font(.title)
})
}
.padding()
}
State인 totalNumber
를 설정해서 나오는 주사위 숫자를 더해서 화면에 나타냈다.
Text("Total: \(totalNumber) / Roll Count: \(rollCount)")
// ...
func rollDice() {
newNumber = Int.random(in: 1...6)
rollCount += 1
totalNumber += newNumber!
}
프로젝트에서 제안한 건 SwiftData나 JSON이지만, 현재 값과 총합 두 가지만 저장하고 사용하기에 UserDefaults를 간단히 활용하는 게 적절해서 UserDefaults를 사용했다.
@State private var rollCount = UserDefaults.standard.integer(forKey: "RollCount")
@State private var totalNumber = UserDefaults.standard.integer(forKey: "TotalNumber")
// ...
func rollDice() {
newNumber = Int.random(in: 1...6)
rollCount += 1
UserDefaults.standard.set(rollCount, forKey: "RollCount")
totalNumber += newNumber!
UserDefaults.standard.set(totalNumber, forKey: "TotalNumber")
}
.sensoryFeedback()으로 버튼을 실행하면 햅틱이 실행되도록 설정했다.
Button(action: {
rollDice()
}, label: {
Text(newNumber == nil ? "?" : String(newNumber!))
.font(.largeTitle)
.padding(50)
.background(.white)
.clipShape(Circle())
.shadow(radius: 5)
})
.sensoryFeedback(.impact, trigger: newNumber)