繁体   English   中英

当视图可以在 SwiftUI 中使用时,为什么我不能在我的视图中使用 Equatable function?

[英]Why I can not use Equatable function in my View when the View can use it in SwiftUI?

我正在尝试将 EquatableView 用于我的视图,但 SwiftUI 不使用我的 == function,看来我做的一切都正确,但不起作用,需要帮助。 我想停止 SwiftUI 进行不必要的渲染,也使用我的 == function,但它每次都渲染并且不使用给定的 function,为什么?

import SwiftUI

extension Int { var isEven: Bool { return self % 2 == 0 } }

struct ContentView: View {
    
    @State private var number = 3
    
    var body: some View {
        VStack {
            
            // EquatableView ( content: NumberView(number: number) )  // <<: Here
            // NumberView(number: number).equatable()   // <<: Or Here
            

            Button("New Random Number") {
                number = Int.random(in: 1...100)
            }
            
            Text(number.description).bold().padding()
        }
    }
}

struct NumberView: View, Equatable {
    
    let number: Int
    
    init(number: Int) {
        
        print("initializing")
        
        self.number = number
    }

    var body: some View {
        
        print("rendering")

        return VStack {
            
            if number.isEven {
                Text("EVEN").bold().foregroundColor(Color.green)
            } else {
                Text("ODD").bold().foregroundColor(Color.red)
            }
            
        }
        .padding()
  
    }

    static func == (lhs: NumberView, rhs: NumberView) -> Bool {
        
        print("Equatable used!")
        
        return lhs.number.isEven == rhs.number.isEven
    }
  
}

(Xcode 12.4、macOS 11.2.3)

equatable()的机制有点不透明。 事实上,所有标题都有这个(当然不是详细的)定义:

当新值与旧值相同时,防止视图更新其子视图。

例如,人们会假设对于您的原始示例,您的==将被调用以评估视图是否相等。 但是,显然这不会发生。

它可以以多种(有时令人惊讶的)方式被迫发生。 例如(这个并不令人惊讶),如果您在NumberView上添加一个附加属性,即@State属性,则您的==每次都会被调用:


struct NumberView: View, Equatable {
    
    var number: Int = 0
    @State var additionalProp: Int = 0
    
    var body: some View {
        print("rendering \(Date()): \(number)")
        return VStack {
            Text("\(number)")
            if number.isEven {
                Text("EVEN").bold().foregroundColor(Color.green)
            } else {
                Text("ODD").bold().foregroundColor(Color.red)
            }
        }
        .padding()
    }

    static func == (lhs: NumberView, rhs: NumberView) -> Bool {
        print("Equatable used!")
        return lhs.number.isEven == rhs.number.isEven
    }
}

它的行为与以下不同(其中==未被调用):

var number: Int = 0
var additionalProp: Int = 0

由此,我认为我们可以推断出以下几点:

  1. 在没有其他属性的情况下,SwiftUI 将对道具进行平等检查,如果它们不相等,它甚至不会同时调用您的equatable
  2. 如果有@State 属性,SwiftUI调用您的等价 function。

这是对我来说更有趣的案例:

struct NumberView: View, Equatable {
    
    var number: Int = 0
    var additionalProp: String = ""
    
    var body: some View {
        print("rendering \(Date()): \(number)")
        return VStack {
            Text("\(number)")
            if number.isEven {
                Text("EVEN").bold().foregroundColor(Color.green)
            } else {
                Text("ODD").bold().foregroundColor(Color.red)
            }
        }
        .padding()
    }

    static func == (lhs: NumberView, rhs: NumberView) -> Bool {
        print("Equatable used!")
        return lhs.number.isEven == rhs.number.isEven
    }
}

在上述情况下,即使String是 Swift 中的值类型(和 Equatable)并且不使用 @State ,也会再次使用可相等的@State 我对那部分没有很好的解释。


此页面 (https://swiftui-lab.com/equatableview/) 引用了一位 Apple 工程师关于何时使用 `==` 的引用:

SwiftUI 假定任何 Equatable.== 是真正的相等检查,因此对于 POD 视图,它直接比较每个字段(通过反射)。 对于非 POD 视图,它更喜欢视图的 ==,但如果没有 ==,则回退到其自己的字段比较。 EqView 是一种强制使用 == 的方法。 当它对每个字段进行比较时,相同的规则会递归地应用于每个字段(选择直接比较或 == 如果已定义)。 (POD = 纯数据,参见 Swift 的 _isPOD() function。)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM