🚀 iOS Version Market Share
各バージョンごとの比率を確認しておきます。
👉 iOS version history - Wikipedia
👉 🚀 iOS Version Market Share
各バージョンごとの比率を確認しておきます。
👉 iOS version history - Wikipedia
👉 🚀 iOS Version Market Share
ModelContainer セット時には便利な、
view extension と modifier のセットですが、
複数に重なってくると、
なんだか頭が痛くなる。
再度、ModelContainer の基本的な利用の流れを整理しておきます。
struct DataContainerViewModifier: ViewModifier {
private let container: ModelContainer
init() {
container = try! ModelContainer(
for: Schema([Plant.self, Bird.self]),
configurations: [ModelConfiguration()]
)
}
func body(content: Content) -> some View {
content
.modelContainer(container)
}
}
extension View {
func dataContainer() -> some View {
modifier(DataContainerViewModifier())
}
}
これ、#Preview など利用したい View で簡単に利用できて便利です。
@main
struct SampleApp: App {
var body: some Scene {
WindowGroup {
ContentView()
.dataContainer()
}
}
}
これで この View 以下の View では、
@Query, @Environment を利用して、
データ取得、監視、操作が行えるようになりました。
元のサンプルコードは、
以上の流れが、2層になっているので、
1層にして、少し見通し良くしてみました。
作成後の ModelContainer の ModelContext は、
container.mainContext
で、直接取得することができます。
SwiftData の基本的な構成を図でまとめておきます。

👉 Preserving your app’s model data across launches | Apple Developer Documentation
手順的には、
1. Scheme (@Model) と ModelConfiguration を作成する。
2. それらを使って ModelContainer を作成する。
3. それを使って extension View を作成する。
4. それを View にセットする。
というかんじで定型的にサンプルコードでは書いてます。
以下、参考記事。
👉 Dive deeper into SwiftData - WWDC23 - Videos - Apple Developer
👉 SwiftData Stack: Understanding Schema, Container & Context - swiftyplace
👉 View を拡張したい場合は原則として extension を使用し、状態保持が必要な場合のみ `ViewModifier` を実装する。 · YusukeHosonuma/Effective-SwiftUI · Discussion #31
高校生のときに聞いたことある「スカラー」。
〘名〙 (scalar) 長さ、面積、重さなど、大きさだけで定まる量。常識上の数。ベクトルに対していう。スケーラー。
「方向がない」という雰囲気だけ覚えていたけども。
以下、サンプルコード。
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() は、文字のコードポイントパーサーとしても使えます。
iOS アプリの Apple 公式ドキュメントや著名作者のコードをあれこれ眺めていて気になっていたのは、
「なんで public を省略しないのか」
ということ。
public extension Image {
static let fountain = Image(.fountain)
static let fountainFill = Image(.fountainFill)
}
「はっきり明示する。」
のがポリシーなのかと思ったが省略してる箇所もある。
なんでなの ?
試しに消してみると、
extension Image {
static let fountain = Image(.fountain)
static let fountainFill = Image(.fountainFill)
}
呼んでいる場所でエラー発生。

'fountain' is inaccessible due to 'internal' protection level
見えてはいるけどアクセスができない。
Java など他の言語とは違います。
アクセスレベルを省略した場合は「internal」。
同じモジュール内からしかアクセスできません。
移民はつらい。
しかし、さすが公式サンプルコードは勉強になります。
しっかりしています。
頻繁に見かけるんですけど、
いまいち分かってない以下のような記述。

これは一体なんなのか。
すごく冗長に見えるし。
ぱっと見、理解できなかったので、
基本的な部分を少し噛み砕いてみました。
順番にやっていきます。
まず、列挙型の enum。
enum Animal {
case dog
case cat
case monkey
}

また、次のように書いても同じ。
enum Animal {
case dog, cat, monkey
}
case がいるんですね !
extension で拡張して追加。
enum Animal {
case dog, cat, monkey
}
extension Animal {
var hiragana: String {
switch self {
case .dog: "いぬ"
case .cat: "ねこ"
case .monkey: "さる"
}
}
}
print(Animal.cat.hiragana)
// ねこ

紐づくんですね。
それぞれの enum 要素に。
enum Animal {
case dog, cat, monkey
}
extension Animal {
var hiragana: String {
switch self {
case .dog: "いぬ"
case .cat: "ねこ"
case .monkey: "さる"
}
}
var katakana: String {
switch self {
case .dog: "イヌ"
case .cat: "ネコ"
case .monkey: "サル"
}
}
}
print(Animal.cat.hiragana)
print(Animal.monkey.katakana)
// ねこ
// サル

そういうことか !
enum の「それぞれの要素から枝が生えていく」のか !
どうやら考え方としては、
ベースの enum のそれぞれの要素に extension で枝を生やしていく
ようなイメージでいいのでしょうか。
ネストしたデータ構成の編集時に便利に使えそうです。
推測できれば、クラス名の省略ができることも良い !
しかし、Swift の enum は機能豊富らしいけど、
まずは、これくらいでいいかな。