为啥提了这个问题
SwiftUI 中的 MVVM 大部分讨论的是VM ,但是对于Model 的可变 和不可变的问题还是有点问题没有说的很明确。 最近遇到一个问题,在对于VM的数据处理部分,我看到老代码很多地方对于Array的数据里面一个 数据的Model的 具体属性的Updata,特别是不涉及到array 的数据number 变化的情况下。
- 1 发现 用Struct的Model 的确有 array remvoe & insert 的情况
- 2 在MainThread 里面进行因为 VM 的list是@Publsh
- 3 卡顿
这一切的问题在于Model是Struct ,哪怕VM 已经是一个StateObject
Class 版本,代码如图,同样的疑问
[stackoverFlow](stackoverflow.com/questions/5…)
import Foundation
import SwiftUI
import Combine
class Person: Equatable, Hashable ,Identifiable,ObservableObject{
var id = UUID()
@Published var name: String = ""
static func == (lhs: Person, rhs: Person) -> Bool {
lhs.id == rhs.id
}
func hash(into hasher: inout Hasher) {
hasher.combine(id)
hasher.combine(name)
}
init(name: String) {
self.name = name
}
}
class VModel: ObservableObject{
@Published var people: [Person]
init(){
self.people = [
Person(name:"Juan"),
Person(name:"Pedro"),
Person(name:"Luis"),
Person(name:"Javier1"),
]
}
}
struct ListRow: View {
@ObservedObject var people : Person
var body: some View {
HStack {
Text("\(people.name)")
Spacer()
Button(action: {
people.name = people.name + "1"
}, label: {
Text("Change Name")
})
}
}
}
struct ContentView1: View {
@StateObject var vmodel = VModel()
var body: some View {
VStack{
List {
ForEach(vmodel.people ,id: \.self){ person in
ListRow(people: person)
}
}
}
.environmentObject(vmodel)
}
}
#Preview {
ContentView1()
}
Struct
如果model 是struct 那就必须 自己去寻找对应的 ViewModel 里面的数据 var 变量 这样的有很多不方便的地方,在子view里面必须把VM 给带上,没有很好的利用swiftUI 的关键字 @ObservableObject ,@environmentObject 等一系列组合
struct ContentView: View {
@StateObject var vm = FileViewModel()
var body: some View {
HStack {
Button(action: {
vm.changeOneName(index: 2, name: "hahahh ")
}, label: {
Text("改名1 ")
})
Button(action: {
vm.changeOneName(index: 3, name: "hahahh ")
}, label: {
Text("改名2 ")
})
}
List {
Section {
ForEach(self.vm.files) { file in
Text("\(file.name)")
}
} header: {
Text("\(self.vm.files.count)")
}
}
.padding()
.onAppear {
for i in 0..<100 {
let f = File(name: "\(i)", path: "path is \(i)")
vm.files.append(f)
}
}
}
}
extension Array {
subscript(safe range: Range<Index>) -> ArraySlice<Element> {
if range.endIndex > endIndex {
if range.startIndex >= endIndex {
return []
} else {
return self[range.startIndex..<endIndex]
}
} else {
return self[range]
}
}
}
#Preview {
ContentView()
}
struct ContentView: View {
@StateObject var vm = FileViewModel()
var body: some View {
HStack {
Button(action: {
vm.changeOneName(index: 2, name: "hahahh ")
}, label: {
Text("改名1 ")
})
Button(action: {
vm.changeOneName(index: 3, name: "hahahh ")
}, label: {
Text("改名2 ")
})
}
List {
Section {
ForEach(self.vm.files) { file in
Text("\(file.name)")
}
} header: {
Text("\(self.vm.files.count)")
}
}
.padding()
.onAppear {
for i in 0..<100 {
let f = File(name: "\(i)", path: "path is \(i)")
vm.files.append(f)
}
}
}
}
extension Array {
subscript(safe range: Range<Index>) -> ArraySlice<Element> {
if range.endIndex > endIndex {
if range.startIndex >= endIndex {
return []
} else {
return self[range.startIndex..<endIndex]
}
} else {
return self[range]
}
}
}
#Preview {
ContentView()
}
感觉 AI 说的对
AI : When it comes to SwiftUI, both classes and structs can be used as model types. However, there are some differences between them.
-
Reference vs Value:
- Classes are reference types, meaning that when you pass a class instance around, you are passing a reference to the same instance.
- Structs are value types, meaning that when you pass a struct instance around, you are passing a copy of the instance.
-
Mutability:
- Classes can be mutable or immutable. You can change the properties of a class instance even if it is declared as a constant (using
let
). - Structs are immutable by default. If you want to modify the properties of a struct instance, you need to mark it as
var
instead oflet
.
- Classes can be mutable or immutable. You can change the properties of a class instance even if it is declared as a constant (using
-
Inheritance:
- Classes support inheritance, allowing you to create a hierarchy of classes with shared properties and behaviors.
- Structs do not support inheritance. They cannot be subclassed.
In general, if you need reference semantics, inheritance, or mutability, you may prefer using classes. On the other hand, if you prefer value semantics, immutability, and simpler data structures, structs can be a good choice. The decision between classes and structs ultimately depends on the specific requirements and design of your SwiftUI application.
但是对于 情况,AI 没有举出很好例子。我自己当了回ai注解
引用: