SwiftUI 视图不会在单独的视图中更新
SwiftUI View doesn't update in a seperate View
我正在使用 List
来显示消息的复选标记。问题是如果我将复选标记视图分离到一个子视图中,该视图不会更新。如果我将 完全相同的代码 直接放入 List
它会按预期工作。我在多个地方使用该复选标记视图,因此它需要在子视图中。
示例:
这个不工作:
List(filteredMessages, id: \.content.uniqueIdentifier) { message in
DoubleCheckmark(message: message)
}
但这确实有效:
List(filteredMessages, id: \.content.uniqueIdentifier) { message in
HStack(spacing: 0) {
if message.content.readStatus == .loading {
Text("loading")
} else if message.content.readStatus == .sent {
Image(systemName: "checkmark")
.resizable()
.scaledToFit()
.foregroundColor(message.content.readStatus == .read ? .blue : .gray)
} else if message.content.readStatus == .received {
Image(systemName: "checkmark")
.resizable()
.scaledToFit()
.foregroundColor( .gray)
Image(systemName: "checkmark")
.resizable()
.scaledToFit()
.padding(.leading, -7)
.foregroundColor(.gray)
} else if message.content.readStatus == .read {
Image(systemName: "checkmark")
.resizable()
.scaledToFit()
.foregroundColor(.blue)
Image(systemName: "checkmark")
.resizable()
.scaledToFit()
.padding(.leading, -7)
.foregroundColor(.blue)
} else {
Text("error")
}
}
.height(11)
.width(15)
.yOffset(-1)
}
这是我的 DoubleCheckmark
视图:
struct DoubleCheckmark: View {
var message: Message
var body: some View {
HStack(spacing: 0) {
if message.content.readStatus == .loading {
Text("loading")
} else if message.content.readStatus == .sent {
Image(systemName: "checkmark")
.resizable()
.scaledToFit()
.foregroundColor(message.content.readStatus == .read ? .blue : .gray)
} else if message.content.readStatus == .received {
Image(systemName: "checkmark")
.resizable()
.scaledToFit()
.foregroundColor( .gray)
Image(systemName: "checkmark")
.resizable()
.scaledToFit()
.padding(.leading, -7)
.foregroundColor(.gray)
} else if message.content.readStatus == .read {
Image(systemName: "checkmark")
.resizable()
.scaledToFit()
.foregroundColor(.blue)
Image(systemName: "checkmark")
.resizable()
.scaledToFit()
.padding(.leading, -7)
.foregroundColor(.blue)
} else {
Text("error")
}
}
.height(11)
.width(15)
.yOffset(-1)
}
}
这是我的 Message
class:
public class Message: NSObject, Codable, NSCoding {
public var content: MessageContent
public var fromUser: User
public var toUser: User
public init(content: MessageContent, fromUser: User, toUser: User) {
self.content = content
self.fromUser = fromUser
self.toUser = toUser
}
enum Keys: String {
case content, fromUser, toUser
}
public func encode(with aCoder: NSCoder) {
aCoder.encode(content, forKey: Keys.content.rawValue)
aCoder.encode(fromUser, forKey: Keys.fromUser.rawValue)
aCoder.encode(toUser, forKey: Keys.toUser.rawValue)
}
public required convenience init?(coder aDecoder: NSCoder) {
let content = aDecoder.decodeObject(forKey: Keys.content.rawValue) as! MessageContent
let fromUser = aDecoder.decodeObject(forKey: Keys.fromUser.rawValue) as! User
let toUser = aDecoder.decodeObject(forKey: Keys.toUser.rawValue) as! User
self.init(content: content, fromUser: fromUser, toUser: toUser)
}
public override func isEqual(_ object: Any?) -> Bool {
if let object = object as? Message {
return self.content.uniqueIdentifier == object.content.uniqueIdentifier
} else {
return false
}
}
}
如果您的 Message
是 class,那么 List
很可能不会更新相同消息的行,因为 message
属性 的引用相等.尝试明确地使您的观点符合 Equatable
并在 Message
中覆盖相同的观点以进行深入比较
struct DoubleCheckmark: View, Equatable {
static func == (lhs: DoubleCheckmark, rhs: DoubleCheckmark) -> Bool {
lhs.message == rhs.message
}
...
和
class Message: ObservableObject, Equatable {
static func == (lhs: Message, rhs: Message) -> Bool {
// compare here all important properties
}
...
对此进行更改,可能还需要明确提及您的自定义视图是自定义等同的
List(filteredMessages, id: \.content.uniqueIdentifier) { message in
DoubleCheckmark(message: message).equatable() // try with & w/o
}
我将消息 class
更改为 struct
并使用 binary data
作为 CoreData 中的数据类型而不是 Transformable 需要模型符合 NSCoding
它不会更新,因为 Message 不是 ObservableObject。如果传递 class 实例,则需要将 @ObservedObject 添加到视图 属性。否则,SwiftUI 不知道发生了变化。
此外,class 必须标记使用 @Published 包装器更改的属性,或者手动调用 objectWillChange.send()
我正在使用 List
来显示消息的复选标记。问题是如果我将复选标记视图分离到一个子视图中,该视图不会更新。如果我将 完全相同的代码 直接放入 List
它会按预期工作。我在多个地方使用该复选标记视图,因此它需要在子视图中。
示例:
这个不工作:
List(filteredMessages, id: \.content.uniqueIdentifier) { message in
DoubleCheckmark(message: message)
}
但这确实有效:
List(filteredMessages, id: \.content.uniqueIdentifier) { message in
HStack(spacing: 0) {
if message.content.readStatus == .loading {
Text("loading")
} else if message.content.readStatus == .sent {
Image(systemName: "checkmark")
.resizable()
.scaledToFit()
.foregroundColor(message.content.readStatus == .read ? .blue : .gray)
} else if message.content.readStatus == .received {
Image(systemName: "checkmark")
.resizable()
.scaledToFit()
.foregroundColor( .gray)
Image(systemName: "checkmark")
.resizable()
.scaledToFit()
.padding(.leading, -7)
.foregroundColor(.gray)
} else if message.content.readStatus == .read {
Image(systemName: "checkmark")
.resizable()
.scaledToFit()
.foregroundColor(.blue)
Image(systemName: "checkmark")
.resizable()
.scaledToFit()
.padding(.leading, -7)
.foregroundColor(.blue)
} else {
Text("error")
}
}
.height(11)
.width(15)
.yOffset(-1)
}
这是我的 DoubleCheckmark
视图:
struct DoubleCheckmark: View {
var message: Message
var body: some View {
HStack(spacing: 0) {
if message.content.readStatus == .loading {
Text("loading")
} else if message.content.readStatus == .sent {
Image(systemName: "checkmark")
.resizable()
.scaledToFit()
.foregroundColor(message.content.readStatus == .read ? .blue : .gray)
} else if message.content.readStatus == .received {
Image(systemName: "checkmark")
.resizable()
.scaledToFit()
.foregroundColor( .gray)
Image(systemName: "checkmark")
.resizable()
.scaledToFit()
.padding(.leading, -7)
.foregroundColor(.gray)
} else if message.content.readStatus == .read {
Image(systemName: "checkmark")
.resizable()
.scaledToFit()
.foregroundColor(.blue)
Image(systemName: "checkmark")
.resizable()
.scaledToFit()
.padding(.leading, -7)
.foregroundColor(.blue)
} else {
Text("error")
}
}
.height(11)
.width(15)
.yOffset(-1)
}
}
这是我的 Message
class:
public class Message: NSObject, Codable, NSCoding {
public var content: MessageContent
public var fromUser: User
public var toUser: User
public init(content: MessageContent, fromUser: User, toUser: User) {
self.content = content
self.fromUser = fromUser
self.toUser = toUser
}
enum Keys: String {
case content, fromUser, toUser
}
public func encode(with aCoder: NSCoder) {
aCoder.encode(content, forKey: Keys.content.rawValue)
aCoder.encode(fromUser, forKey: Keys.fromUser.rawValue)
aCoder.encode(toUser, forKey: Keys.toUser.rawValue)
}
public required convenience init?(coder aDecoder: NSCoder) {
let content = aDecoder.decodeObject(forKey: Keys.content.rawValue) as! MessageContent
let fromUser = aDecoder.decodeObject(forKey: Keys.fromUser.rawValue) as! User
let toUser = aDecoder.decodeObject(forKey: Keys.toUser.rawValue) as! User
self.init(content: content, fromUser: fromUser, toUser: toUser)
}
public override func isEqual(_ object: Any?) -> Bool {
if let object = object as? Message {
return self.content.uniqueIdentifier == object.content.uniqueIdentifier
} else {
return false
}
}
}
如果您的 Message
是 class,那么 List
很可能不会更新相同消息的行,因为 message
属性 的引用相等.尝试明确地使您的观点符合 Equatable
并在 Message
中覆盖相同的观点以进行深入比较
struct DoubleCheckmark: View, Equatable {
static func == (lhs: DoubleCheckmark, rhs: DoubleCheckmark) -> Bool {
lhs.message == rhs.message
}
...
和
class Message: ObservableObject, Equatable {
static func == (lhs: Message, rhs: Message) -> Bool {
// compare here all important properties
}
...
对此进行更改,可能还需要明确提及您的自定义视图是自定义等同的
List(filteredMessages, id: \.content.uniqueIdentifier) { message in
DoubleCheckmark(message: message).equatable() // try with & w/o
}
我将消息 class
更改为 struct
并使用 binary data
作为 CoreData 中的数据类型而不是 Transformable 需要模型符合 NSCoding
它不会更新,因为 Message 不是 ObservableObject。如果传递 class 实例,则需要将 @ObservedObject 添加到视图 属性。否则,SwiftUI 不知道发生了变化。 此外,class 必须标记使用 @Published 包装器更改的属性,或者手动调用 objectWillChange.send()