0
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

SwiftUIでプレビュー時にprivateな変数にアクセスする方法

Last updated at Posted at 2024-08-31

SwiftUIでビューを作成する際、@Stateを使ってビューの状態を管理することが多いです。しかし、@State変数は通常privateとして扱われるため、プレビュー時に直接アクセスして変更することができません。この記事では、privateな@State変数にアクセスして、プレビュー時に表示内容や表示状態を変更する方法を紹介します。

問題の背景

通常、@State変数はprivateであり、外部から直接変更することができません。そのため、プレビュー時に特定の状態を再現したい場合でも、その状態にアクセスできず、手動で状態を変更しなければなりません。

例えば、以下のようなコードがあるとします。

struct MainView: View {
    @State private var isTextVisible: Bool = false
    @State private var displayText: String = "Default Text"

    var body: some View {
        VStack {
            if isTextVisible {
                Text(displayText)
                    .font(.headline)
                    .padding()
            }
        }
    }
}

このコードでは、isTextVisibleがfalseであるため、プレビュー時にはテキストが表示されません。しかし、プレビューでテキストが表示される状態を確認したい場合、この変数にアクセスする方法が必要です。
また、Textの内容もprivateでアクセスできないです。

解決策: extensionを使ったapplyメソッド
この問題を解決するために、extensionを使ってビューにapplyメソッドを追加します。このメソッドを使うことで、プレビュー時にprivateな変数を簡単に設定できるようになります。

extension MainView {
    func apply(isVisible: Bool, text: String) -> Self {
        var copy = self
        copy._isTextVisible = State(initialValue: isVisible)
        copy._displayText = State(initialValue: text)
        return copy
    }
}

本番環境で拡張したコードの情報を含めたくない場合は"#if DEBUG #endif DEBUG"で囲むことも視野。
また、Previewのみ動かす方法として

ProcessInfo.processInfo.environment["XCODE_RUNNING_FOR_PREVIEWS"] == "1"

という文を条件として使用することができる。

全体のコードと実行結果

import SwiftUI

struct MainView: View {
    @State private var isTextVisible: Bool = false
    @State private var displayText: String = "Default Text"

    var body: some View {
        VStack {
            if isTextVisible {
                Text(displayText)
                    .font(.headline)
                    .padding()
            }
        }
    }
}

extension MainView {
    func apply(isVisible: Bool, text: String) -> Self {
        var copy = self
        copy._isTextVisible = State(initialValue: isVisible)
        copy._displayText = State(initialValue: text)
        return copy
    }
}

struct MainView_Previews: PreviewProvider {
    static var previews: some View {
        MainView().apply(isVisible: true, text: "This text is visible in Preview!")
    }
}

simulatorでの実行結果
Simulator Screenshot - iPhone 15 Pro Max - 2024-08-31 at 11.22.55.png
これだと分かりにくいので、isTextVisibleをtrueにして実行
Simulator Screenshot - iPhone 15 Pro Max - 2024-08-31 at 11.25.22.png
そして、Previewでは
スクリーンショット 2024-08-31 11.25.48.png

これを活用してsnapshot testなどを進めていきたい。

0
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?