I am already aware of the strong/weak reference concept in swift.
yet after running the next code, and tapping on the Button (and dismissing the screen), the TestViewModel stayed in memory! I was expecting that using [weak viewmodel] will be enough to prevent it. in the second example I managed to fix it - but I don't understand why it worked

import SwiftUI
import Resolver

struct TestScreen: View {
    
    @StateObject var viewmodel = TestViewModel()
    @Injected var testStruct: TestStruct
    @Environment(\.presentationMode) var presentationMode
    
    var body: some View {
        NavigationView {
            
            VStack(spacing: 0) {
                
                Button("go back") { [weak viewmodel] in
                        testStruct.saveActionGlobaly(onAsyncAction:  viewmodel?.someAsyncAction )
                        presentationMode.wrappedValue.dismiss()
                    }
            }
        }
    }
}


import Foundation
import Resolver
import SwiftUI

public class TestStruct {
   var onAsyncAction: (() async throws -> Void)?
    
    public func saveActionGlobaly(onAsyncAction: (() async throws -> Void)?) {
        self.onAsyncAction = onAsyncAction
    } 
}

EXAMPLE 2:
I managed to prevent the leak by changing the code this way: (notice the changes in the callback passed to onAsyncAction)

import Resolver

struct TestScreen: View {
    
    @StateObject var viewmodel = TestViewModel()
    @Injected var testStruct: TestStruct
    @Environment(\.presentationMode) var presentationMode
    
    var body: some View {
        NavigationView {
            
            VStack(spacing: 0) {
                
                Button("go back") { [weak viewmodel] in
                        testStruct.saveActionGlobaly(onAsyncAction:  { await viewmodel?.someAsyncAction() } )
                        presentationMode.wrappedValue.dismiss()
                    }
            }
        }
    }
}

我不明白为什么第二个TestScreen成功地应用了弱引用,而第一个没有, 谢谢(:

环境: SWIFT 5 Xcode 14.2

推荐答案

您的第一个版本:

testStruct.saveActionGlobaly(onAsyncAction:  viewmodel?.someAsyncAction )

相当于:

let action: (() async throws -> Void)?
if let vm = viewmodel {
    // vm is a strong non-nil reference, so this closure
    // has a strong non-nil reference to a TestViewModel.
    action = vm.someAsyncAction
} else {
    action = nil
}
testStruct.saveActionGlobaly(onAsyncAction: action)

只要TestScreen是视图层次 struct 的一部分,只要Button是视图层次 struct 的一部分,SwiftUI就会一直持有您的@StateObject.因此,SwiftUI会一直保持对您的TestViewModel的强引用,直到它调用您的Button的操作.因此,在您的第一个版本中,您在Button操作中的弱viewmodel引用将永远不会为零.因此,vm永远不会是零,action永远不会是零,action永远会强烈地引用TestViewModel.

你的第二个版本:

testStruct.saveActionGlobaly(onAsyncAction:  { await viewmodel?.someAsyncAction() } )

保留了viewmodel变量的弱点.它只在每次调用时立即创建对TestViewModel的强引用,并在someAsyncAction返回后立即丢弃该强引用.

Swift相关问答推荐

纹理资源加载问题(图像解码失败)

按Esc键时执行操作(工作表)

从后台线程获取@发布属性的值(不更改它)是正确的吗?

RxSwift .debounce,.throttle用于分页

在SwiftUI中,我如何确保带有符号的单词不会被拆分为两行?

如何在SwiftUI的文本视图中显示NSMutableAttributedString?

如何绑定环境变量ios17

SwiftUI路径平滑连接两条线

在 Swift 5.7 中使用协议作为类型时什么时候需要写 `any`

(Swift)混淆了函数内 for-in 循环的返回值和循环后(函数内)的返回值)

覆盖一个子元素的 HStack 对齐方式

如何在 Combine 合并运算符的输出上使用 eraseToAnyPublisher

关于变量的视图的 SwiftUI 生命周期

闭包 - deinit self 对象的时间

数组使用偏移量对自身执行 XOR

为什么 Apple Scrumdinger Sample App 使用两个事实来源?

`let case(value)` 和 `case(let value)` 之间的区别 (Swift)

在 Xcode 中自动实现 Swift 协议方法

为 UIActivityViewController Swift 设置不同的活动项

使用相机进行人脸检测