SwiftUI 使用EnvironmentObject減少傳遞變量
xcode 13.4.1, swift 5.5, iOS 15.4
2022-09-27
在
SwiftUI List元件的基本使用學習List,今次會以這個為基礎講講如何使用EnvironmentObject來減少傳遞變量。
1. 首先把items打包成一個repository:
import Foundation
class ItemRepository : ObservableObject {
@Published var items : [String] = []
init() {
}
func appendItem() {
self.items.insert("Item \(items.count)", at: 0)
}
func remove(_ indexSet : IndexSet) {
self.items.remove(atOffsets: indexSet)
}
func move(_ indexSet : IndexSet, _ offset : Int) {
self.items.move(fromOffsets: indexSet, toOffset: offset)
}
func size() -> Int {
return items.count
}
}
2. 把ListViewExample中的items改成ItemRepository,並把詳情從Text改為ItemView:
import SwiftUI
struct ItemView: View {
@ObservedObject var itemRepository : ItemRepository
let index : Int
var body: some View {
Group {
if index < itemRepository.size() {
Text("\(index)/\(itemRepository.size()) : \(itemRepository.items[index])")
} else {
Text("No Data")
}
}
}
}
import SwiftUI
struct ListViewExample : View {
@ObservedObject var itemRepository : ItemRepository
var body: some View {
NavigationView {
List {
ForEach(0..<itemRepository.size(), id:\.self) { index in
NavigationLink {
ItemView(itemRepository: itemRepository, index: index)
} label: {
Text(itemRepository.items[index])
}
}
.onDelete { indexSet in
self.itemRepository.remove(indexSet)
}
.onMove { indexSet, offset in
self.itemRepository.move(indexSet, offset)
}
}
.toolbar {
ToolbarItem(placement: .navigationBarTrailing) {
EditButton()
}
ToolbarItem(placement: .navigationBarLeading) {
Button {
withAnimation {
self.itemRepository.appendItem()
}
} label: {
Image(systemName: "plus")
}
}
}
}
}
}
import SwiftUI
@main
struct Tutorial20220927App: App {
var body: some Scene {
WindowGroup {
ListViewExample(itemRepository: ItemRepository())
}
}
}
3. 從程式代碼上看,由App到ListViewExampe,再到ItemView,要把itemRepository一層一層的傳下去,如果在多幾層,傳遞的深度會更深。
4.為了解決這樣傳遞的問題,可以將需要一層層傳遞的變量使用環境變量來代替。
5. 首先用environmentObject來把ItemRepository放到環境變量中。
import SwiftUI
@main
struct Tutorial20220927App: App {
var body: some Scene {
WindowGroup {
ListViewExample()
.environmentObject(ItemRepository())
}
}
}
6. 然後使用EnvironmentObject來獲得環境變量中的ItemRepository。
import SwiftUI
struct ListViewExample : View {
@EnvironmentObject var itemRepository : ItemRepository
var body: some View {
NavigationView {
List {
ForEach(0..<itemRepository.size(), id:\.self) { index in
NavigationLink {
ItemView(index: index)
} label: {
Text(itemRepository.items[index])
}
}
.onDelete { indexSet in
self.itemRepository.remove(indexSet)
}
.onMove { indexSet, offset in
self.itemRepository.move(indexSet, offset)
}
}
.toolbar {
ToolbarItem(placement: .navigationBarTrailing) {
EditButton()
}
ToolbarItem(placement: .navigationBarLeading) {
Button {
withAnimation {
self.itemRepository.appendItem()
}
} label: {
Image(systemName: "plus")
}
}
}
}
}
}
import SwiftUI
struct ItemView: View {
@EnvironmentObject var itemRepository : ItemRepository
let index : Int
var body: some View {
Group {
if index < itemRepository.size() {
Text("\(index)/\(itemRepository.size()) : \(itemRepository.items[index])")
} else {
Text("No Data")
}
}
}
}
7. 以上學習了使用EnvironmentObject構制減少變量的傳遞。