【问题标题】:SwiftUI View doesn't update in a seperate ViewSwiftUI 视图不会在单独的视图中更新
【发布时间】:2020-06-27 11:55:03
【问题描述】:

我正在使用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 班级:

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
        }
    }
}

【问题讨论】:

  • content.uniqueIdentifier 是否在 message.content.readStatus 更改时更改?如果没有,那么你isEqual 不起作用。
  • @Asperi 当然它没有改变为它的 uniqueIdentifier
  • @Asperi 你有别的想法吗?
  • 我已经写过 - 你的 isEqual 不起作用,因为对于 readStatus .loading.read 它返回 true,但必须 false.
  • 即使我明确返回 false 它也不起作用@Asperi

标签: ios swift xcode swiftui swift5


【解决方案1】:

如果您的Message 是一个类,那么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
}

【讨论】:

  • Message 需要是一个类,因为它需要符合 NSCoding,所以我可以将它与 CoreData 的 Transformable 一起使用
  • @jsbeginnerNodeJS,这不是问题,那么你需要覆盖isEqual,因为它是一个NSObject
  • 还是不行。我在上面的问题中附加了 Message 类。请看看@Asperi
【解决方案2】:

我将我的消息 class 更改为 struct 并使用 binary data 作为 CoreData 中的数据类型,而不是需要模型符合 @ 的 Transformable 987654324@

【讨论】:

    【解决方案3】:

    它不会更新,因为 Message 不是 ObservableObject。如果您传递一个类实例,则需要将 @ObservedObject 添加到视图属性。否则,SwiftUI 不知道发生了变化。 此外,该类必须使用 @Published 包装器标记更改的属性,或手动调用 objectWillChange.send()

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-04-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多