【Swift】サロンで学んだことまとめ

#はじめに
僕が参加しているオンラインサロンで学んだことを適宜書いていこうかと思います。

#学んだこと
・合計値を求めるときなどは積極的に高階関数を使う

```swift
let text1 = "1"
let text2 = "2"
let text3 = "3"
let text4 = "4"
let text5 = "5"
//合計値を求める
let array: [String?] = [text1, text2, text3, text4, text5]
let sum = array
    .map { $0 ?? "" }
    .map { Int($0) ?? 0 }
    .reduce(0, +)
print(sum) // 15
```
・enumで無闇にswitchを使わない

```swift
enum Weather {
    case sunny
    case cloudy
    case rainy
    var text: String {
        switch self {
        case .sunny: return "晴れです"
        case .cloudy: return "曇りです"
        case .rainy: return  "雨です"
        }
    }
}
print(Weather.sunny.text)
```
以下のようにすることで、メッセージを定義するだけなら足りる。

```swift
enum WeatherMessage {
    static let sunny = "晴れです"
    static let cloudy = "曇りです"
    static let rainy = "雨です"
}
print(Weather.sunny)
```

・正誤判定や成功失敗の判定の時はenumで結果を定義する、その判定結果をenumの連想値に持たせることで、扱いやすくする。

```swift
enum CalculationResult {
    case success(Double)
    case failure(String)
}

enum Calculation {
    case addition
    case subtraction
    case multiplication
    case division
    func calculate(_ num1: Double, _ num2: Double) -> CalculationResult {
        switch self {
        case .addition:
            return .success(num1 + num2)
        case .subtraction:
            return .success(num1 - num2)
        case .multiplication:
            return .success(num1 * num2)
        case .division:
            guard !num2.isZero else { return .failure("0で割れません") }
            return .success(num1 / num2)
        }
    }
}
```

・guardを連ねる時はflatMapを使えないか考える

```swift
func someFunc() {
    let optionalText: String? = "1000"
    guard let text = optionalText,
          let num = Int(text) else { return }
    print(num)
}
```
以下のようにすることで、Optional(Optional())から2回アンラップしないといけないところをflatMapを使い、一行で済ませることができます。

```swift
func someFunc() {
    let optionalText: String? = "1000"
    guard let num = optionalText.flatMap({ Int($0) }) else { return }
    print(num)
}
```

・使わないoutletなどは消去する
・guardをまとめる

```swift
guard let a = Int(str) else { return }
guard let b = Int(str2) else { return }
```
を以下のようにまとめることができる

```swift
guard let a = Int(str),
      let b = Int(str2) else { return }
```

・LayoutSubViewsを理解する
ViewControllerの表示、画面の向きの変更など、ViewControllerのViewのframeが更新された時に呼び出される。

```swift
private let label: UILabel!

override func viewDidLoad() {
    super.viewDidLoad()
    
    let label = UILabel()
    self.view.addSubview(label)
    
}

override func viewDidLayoutSubviews() {
    super.viewDidLayoutSubviews()
    
    setupLabel()
            
}

private func setupLabel() {
    label.text = "text"
    label.textAlignment = .center
    label.backgroundColor = .red
    label.frame = CGRect(x: 0,
                         y: 0,
                         width: self.view.frame.size.width,
                         height: self.view.frame.size.height
    )
}
```

・boundsとframeの違い ([参考](https://selection9.blogspot.com/2016/06/uiviewframebounds.html#:~:text=%E7%B0%A1%E5%8D%98%E3%81%AB%E8%A8%80%E3%81%A3%E3%81%A6%E3%81%97%E3%81%BE%E3%81%86,%E5%BA%A7%E6%A8%99%E7%B3%BB%E3%81%AB%E3%81%AA%E3%82%8A%E3%81%BE%E3%81%99%E3%80%82))
bounds: 基準はローカルビュー
frame: 基準はスーパービュー

・StackViewの切り替え方法[(参考)](https://developer.apple.com/documentation/uikit/uistackview)

```swift
//StackViewに管理されているsomeViewを非表示にするとき
someView.isHidden = true
```

・invalidateLayout()とreloadData()
invalidateLayout: レイアウトに関してのみ再度読み込みをする
reloadData: 全てのデータを再度読み込みする
・indexPathをセルに渡すと密結合になるため、良くない
・extensionの範囲を広くしない(private extensionでファイル内に閉じ込める)
・allCasesの型はAllCasesにできる
・
・
・
・
・
・
・
・
・
・
・
・
・
・
・
・
・
・
・
・
・
・
・
・
・
・
・
・
・
・
・
・
・
・
・
・

#おわりに
随時更新予定
オンラインサロンに入ってよかった！！！