【Swift】「UnicodeScalar」とは、いわゆる「コードポイント !」だったのか ☀️

高校生のときに聞いたことある「スカラー」。

〘名〙 (scalar) 長さ、面積、重さなど、大きさだけで定まる量。常識上の数。ベクトルに対していう。スケーラー。

👉 スカラーとは? 意味や使い方 - コトバンク hatena-bookmark

「方向がない」という雰囲気だけ覚えていたけども。

 

☀️ UnicodeScalar

以下、サンプルコード。


let data = [
  ["61"],
  ["3042"],
  ["1F635", "200D", "1F4AB"],
  ["1F468", "200D", "2764", "FE0F", "200D", "1F468"],
  ["1F1EF", "1F1F5"]
]

for codepoints in data {
  let s = String(
    codepoints
      .map { Int($0, radix: 16)! }
      .map { UnicodeScalar($0)! }
      .map { Character($0) }
  )
  print(s)
  print(codepoints)
  print(
    s.unicodeScalars
      .map { String($0.value, radix: 16, uppercase: true) }
  )
  print()
}

変換の流れ的には以下の順序で変換。


[Int]

  ↕

[UnicodeScalar]

  ↕

[Character]

  ↕

String([Character])

 

☀️ まとめ

「UnicodeScalar」とは「コードポイント !」のことですね。

nil は許しません。

String.unicodeScalars() は、文字のコードポイントパーサーとしても使えます。

👉 Strings and Characters | Documentation hatena-bookmark


【Swift】「public」 を省略しない理由 🚫

iOS アプリの Apple 公式ドキュメントや著名作者のコードをあれこれ眺めていて気になっていたのは、

「なんで public を省略しないのか」

ということ。


public extension Image {
    static let fountain = Image(.fountain)
    static let fountainFill = Image(.fountainFill)
}

👉 sample-backyard-birds/BackyardBirdsUI/Images.swift at 1843d5655bf884b501e2889ad9862ec58978fdbe · apple/sample-backyard-birds hatena-bookmark

「はっきり明示する。」

のがポリシーなのかと思ったが省略してる箇所もある。

なんでなの ?

 

🚫 '***' is inaccessible due to 'internal' protection level

試しに消してみると、


extension Image {
    static let fountain = Image(.fountain)
    static let fountainFill = Image(.fountainFill)
}

呼んでいる場所でエラー発生。


'fountain' is inaccessible due to 'internal' protection level

見えてはいるけどアクセスができない。

 

🚫 まとめ

Java など他の言語とは違います。

アクセスレベルを省略した場合は「internal」。

同じモジュール内からしかアクセスできません。

移民はつらい。

しかし、さすが公式サンプルコードは勉強になります。

しっかりしています。

👉 Access Control | Documentation hatena-bookmark


【SwiftUI】@Observable と @Binding vs @Bindable 👀

例えば、Binding を含むこういうのがあったとして。


struct Parent: View {
  @State private var isOn = false

  var body: some View {
    VStack {
      Rectangle().fill(isOn ? .yellow : .gray)
      Toggle(isOn ? "ON" : "OFF", isOn: $isOn)
    }
  }
}

親子分けした場合。


struct Parent: View {
  @State private var isOn = false

  var body: some View {
    VStack {
      Rectangle().fill(isOn ? .yellow : .gray)
      Child(isOn: $isOn)
    }
  }
}

struct Child: View {
  @Binding var isOn: Bool

  var body: some View {
    Toggle(isOn ? "ON" : "OFF", isOn: $isOn)
  }
}

👉 【SwiftUI】再描画の伝播 - @State と @Binding hatena-bookmark

@State の数が増えてくるとつらいので、

まとめて外出しにする方法はないのかな、と。

そして、子 View などへ上手に持ち運びたい。

 

👀 @Observable と @Bindable

@Observable と @Bindable を使います。

Observable

Observable プロトコルの適合性を定義および実装します。

概要
このマクロは、カスタム タイプに監視サポートを追加し、タイプをObservableプロトコルに準拠させます。

👉 Observable() | Apple Developer Documentation hatena-bookmark

Bindable

監視可能なオブジェクトの可変プロパティへのバインディングの作成をサポートするプロパティラッパータイプ。

概要
このプロパティ ラッパーを使用して、Observable プロトコルに準拠するデータ モデル オブジェクトの可変プロパティへのバインディングを作成します。

👉 Bindable | Apple Developer Documentation hatena-bookmark

ドキュメントのコードを参考にしながら、

とりあえずは、クラスにまとめて外出しします。


@Observable
class StateModel: Identifiable {
  var isOn = false
  var label: String { isOn ? "ON" : "OFF" }
  var color: Color { isOn ? .yellow : .gray }
}

struct Parent: View {
  @Bindable private var model = StateModel()

  var body: some View {
    VStack {
      Rectangle().fill(model.color)
      Toggle(model.label, isOn: $model.isOn)
    }
  }
}

 

👀 子に渡す

Binding を含む @State は、子の @Binding で受けてましたが。

@Observable クラスはどうやって渡すのか。

知ってる範囲であれこれ試してみました。

どうやら、これが標準的で良さげです。


@Observable
class StateModel: Identifiable {
  var isOn = false
  var label: String { isOn ? "ON" : "OFF" }
  var color: Color { isOn ? .yellow : .gray }
}

struct Parent: View {
  private let model = StateModel()

  var body: some View {
    VStack {
      Rectangle().fill(model.color)
      Child(model: model) // *
    }
  }
}

struct Child: View {
  var model: StateModel

  var body: some View {
    @Bindable var model = model // *
    Toggle(model.label, isOn: $model.isOn)
  }
}

試しながら思ったのは、

「クラスインスタンスのまま持ち歩いて、使う直前で @Bindable で Binding 化する」

のが良いですわ。

持ち回りがシンプルで楽だから。

データ自体は @Bindable なくても変化を検知して順方向には流れる。

ただ、いきなり出てきて意味不明で気持ちが悪かった。


@Bindable var model = model

公式ドキュメントでもあちこちにあって、気にはなっていました。

 

👀 まとめ

最後に、ゴミを置いておきます。

どのコメントブロックもきちんと動きます。

いや、動いてるように見えているだけかもしれません。