iT邦幫忙

2023 iThome 鐵人賽

DAY 13
0
Mobile Development

SwiftUI 的大大小小系列 第 13

Day 13 - 在 SwiftUI 中利用 EnvironmentObject 進行 Dependency Injection

  • 分享至 

  • xImage
  •  

hero

前一篇第 12 天是提到「SwiftUI 中使用 transition Modifier」,雖然本系列文章基本上沒有前後關聯,如果你是還沒讀過前一篇的讀者,也推薦你去讀讀。

EnvironmentObject

EnvironmentObject 在 SwiftUI 中的原理是透過「環境」的概念來達成。我們可以利用這個特性,來達成類似相依性注入的行為。

注入 EnvironmentObject

想要建立一個能傳入作為 EnvironmentObject 的類別,就需要宣告一個繼承 ObservableObject 的類別,在這裡簡單宣告一個:

class MySettings: ObservableObject {
    @Published var isActive: Bool = false
}

當要注入的時候,只要像這樣即可:

MyView()
    .environmentObject(MySettings())

動態查找

以上面的範例,在 MyView 中要使用的時候,只要宣告一樣類別的的屬性,要使用的時候就會自動幫忙在環境中查找適合的來用

@EnvironmentObject var mySettings: MySettings

自動傳遞

因為是存放在一個「環境」中,所以被賦予的 EnvironmentObject 也能夠自動傳遞下去子畫面。

假使有個子畫面,當 parent view 有被加上一個 environment object ,在子畫面只要宣告,就能夠取用到。

來看範例,我們先建立兩個 View ,顯示上有親子關係:

struct ParentView: View {
    @EnvironmentObject var mySettings: MySettings
    
    var body: some View {
        VStack {
            Text("Parent: \(mySettings.isActive ? "ON" : "OFF" )")
            ChildView()
        }
    }
}
struct ChildView: View {
    @EnvironmentObject var mySettings: MySettings

    var body: some View {
        Text("Child: \(mySettings.isActive ? "ON" : "OFF" )")
    }
}

接著在 ContentView 中顯示,並透過 .environmentObject modifier 來傳入一開始宣告的 MySettings()

struct ContentView: View {
    var body: some View {
        ParentView()
            .environmentObject(MySettings())
    }
}

1301

執行後就會像是這樣,可以看到 MySettings 的值都有往下傳遞,而且值都正確。

事件傳遞

因為狀態共用的關係,所以透過在子畫面更改狀態,變更狀態的事件也就能自動被傳到有使用這個 environment object 的畫面,進而更新畫面。

來改一下 ChildView 成這樣

struct ChildView: View {
    @EnvironmentObject var mySettings: MySettings

    var body: some View {
        VStack {
            Text("Child: \(mySettings.isActive ? "ON" : "OFF" )")
            Button {
                mySettings.isActive.toggle()
            } label: {
                Text("切換")
                    .font(.system(size: 14, weight: .semibold))
                    .padding(.horizontal, 16)
                    .padding(.vertical, 4)
            }
            .tint(.white)
            .background(
                RoundedRectangle(cornerRadius: 8)
                    .foregroundColor(.indigo)
            )
        }
        .padding(.horizontal, 16)
        .padding(.vertical, 8)
        .background(
            RoundedRectangle(cornerRadius: 10)
                .stroke(lineWidth: 1)
                .foregroundColor(.gray)
                .opacity(0.3)
        )
    }
}

可以看到在 第 8 行 就是更改 mySettings.isActive 的布林值:

mySettings.isActive.toggle()

點擊切換就換會像是這樣的效果:

result

應用

像是這些情境都可以用到:

  • 顏色設定
  • 全域性的數值或設定

結語

到這裡就是在 SwiftUI 中如何使用 EnvironmentObject 。

那今天的 SwiftUI 的大大小小就到這邊,以上,明天見!

環境

  • Xcode 15 beta 8

本篇使用到的 UI 元件和 modifiers 基本上沒有受到版本更新影響

因此 Xcode 14 等環境下使用也是沒問題的。


上一篇
Day 12 - 在 SwiftUI 中使用 transition Modifier
下一篇
Day 14 - 在 SwiftUI 中為 Scroll View 加入下拉更新
系列文
SwiftUI 的大大小小30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言