【问题标题】:Memoization in SwiftUI?SwiftUI 中的记忆?
【发布时间】:2020-03-27 20:09:45
【问题描述】:

我来自 React,我使用 useMemo 来确保不会经常执行某些计算。我如何在 SwiftUI 中做这样的事情?

考虑这个例子:

struct MyView: View {
    var records: [Record]

    var body: some View {
        Text("expensive summary: \(self.expensiveSummary)")
    }

    var expensiveSummary: String {
        // based on records, return string
        // containing a summary of records

        return ""
    }
}

有什么方法可以确保我的 expensiveSummary 仅在我的记录数组更改时被调用?

【问题讨论】:

  • 我们可以假设父视图正在传入records 并且会发生变化。

标签: swiftui


【解决方案1】:

这是作为EquatableView 内置的。

struct MyView: EquatableView { ... }

这只会在 body 的属性(在本例中为 records)实际发生变化时重新计算 expensiveSummary,这将阻止重新评估 expensiveSummary

这不会避免对expensiveSummary insidebody 进行多次评估。如果您需要缓存此类信息,您通常应该创建一个局部变量(尽管有时函数构建器语法不允许这样做,除非将部分代码提取到单独的函数中),或者在init 中计算一个属性。

作为风格问题,我建议不要计算属性的评估成本过高。这令人困惑,因为属性语法通常表明该操作很便宜。相反,我建议这是一个函数或在 init 中计算一次。

【讨论】:

    【解决方案2】:

    我认为我们可以将包装视图创建为Equatable。 (也许,我们可以使用EquatableView.equatable() 修饰符吗?)

    struct UseMemo<KeyType: Equatable, ViewType: View>: View, Equatable {
        let key: KeyType
        let content: (KeyType) -> ViewType
    
        var body: some View {
            content(key)
        }
        
        static func ==(lhs: UseMemo, rhs: UseMemo) -> Bool {
            return lhs.key == rhs.key
        }
    }
    
    struct MyView: View {
        @State var records: [Int] = (Array<Int>)(1...10000)
        @State var other = false
    
        var body: some View {
            VStack {
                Button("Update other", action: { self.other.toggle() })
                Text("Other: \(String(other))") // This will be called everytime
    
                Button("Update records", action: { self.records.append(1) })
                
                UseMemo(key: records) { keys in
                    // This is not called even if updated "other"
                    // This is called when updates "records"
                    Text("expensive summary: \(expensiveSummary)")
                }
                
                // This will be called everytime
                Text("expensive summary: \(expensiveSummary)")
            }
        }
        
        var expensiveSummary: String {
            String(records.randomElement()!)
        }
    }
    

    以下内容对我有帮助。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-01-05
      • 2020-10-25
      • 2012-01-03
      • 2012-09-14
      • 2011-03-13
      • 1970-01-01
      相关资源
      最近更新 更多