📰

SwiftUIのPreviewは同じメモリ上で繰り返し描画されているっぽい

2023/07/31に公開

Realm+SwiftUIを使う機会があり、ドキュメントを読んでいたところ気になるソースコードがありました。
https://www.mongodb.com/docs/realm/sdk/swift/swiftui/swiftui-previews/#create-a-realm-with-data-for-previews

static var previewRealm: Realm {
    var realm: Realm
    let identifier = "previewRealm"
    let config = Realm.Configuration(inMemoryIdentifier: identifier)
    do {
        realm = try Realm(configuration: config)
        // Check to see whether the in-memory realm already contains a Person.
        // If it does, we'll just return the existing realm.
        // If it doesn't, we'll add a Person append the Dogs.
        let realmObjects = realm.objects(Person.self)
        if realmObjects.count == 1 {
            return realm
        } else {
            try realm.write {
                realm.add(person)
                person.dogs.append(objectsIn: [Dog.dog1, Dog.dog2, Dog.dog3])
            }
            return realm
        }
    } catch let error {
        fatalError("Can't bootstrap item data: \(error.localizedDescription)")
    }
}

struct ProfileView_Previews: PreviewProvider {
    static var previews: some View {
        let realm = Person.previewRealm
        let profile = realm.objects(Profile.self)
        ProfileView(profile: profile.first!)
    }
}

このコードでは、メモリ上で展開されるRealmを生成し、Preview用にオブジェクトを追加しています。
追加処理に関して気になるところは無いのですが、追加処理の前にオブジェクトの数をチェックしている部分が気になりました。
コメントを見ると複数回この処理が動くことがあるようです。
実際にどうなっているかが気になったので調べてみました。

確認したみた

以下のようなコードを用意して試してみました。

struct ContentView: View {
    let count: Int
    
    var body: some View {
        Text(String(count))
    }
}

struct ContentView_Previews: PreviewProvider {
    static var _count: Int = 0
    static var count: Int {
        _count += 1
        return _count
    }
    static var previews: some View {
        ContentView(count: count)
            .previewLayout(.fixed(width: 200, height: 150))
    }
}

Xcodeを開いた直後はこんな表示になっていました。

つまり、最終的な表示までに5回描画されているようです。

また、PreviewをSelectableにすると、こんな表示になりました。

LiveとSelectableでどういう差分があるのか謎ですが、描画回数に違いがあるようです。
Realmのサンプルコードように、Preview用にメモリ上でデータを増減させる場合、ここを考慮しておく必要がありそうです。

Discussion