能否改用函数来避免闭包内存泄漏?

Can you avoid closure memory leaks by using functions instead?

提问人:Joakim Sjöstedt 提问时间:2/24/2023 最后编辑:Joakim Sjöstedt 更新时间:2/24/2023 访问量:118

问:

所以我正在使用并有一个看起来像这样的:RxSwiftfunction

private func setAndVerifyTestmode(isOn: Bool) {
    parameterService.setTestMode(value: isOn)
      .flatMap { _ in self.parameterService.requestTestMode() }
      .subscribe( { [weak self] _ in
        //do stuff })
      .disposed(by: disposeBag)
}

我注意到我忘记在 中使用,所以我这样添加它:[weak self].flatMap

private func setAndVerifyTestmode(isOn: Bool) {
    parameterService.setTestMode(value: isOn)
      .flatMap { [weak self] (_: Int?) in 
          guard let self = self else { return .just(nil) }
          self.parameterService.requestTestMode() }
      .subscribe( { [weak self] _ in
        //do stuff })
      .disposed(by: disposeBag)
}

但后来它给了我一个错误:Generic parameter Result could not be infered

我无法绕过它,所以我尝试使用嵌套而不是 ,最终得到这个:functionclosure

private func setAndVerifyTestMode(isOn: Bool) {
    func requestTestMode(_: Int?) -> Single<Int?> {
      parameterService.requestTestMode()
    }
     
parameterService.setTestMode(value: isOn)
      .flatMap(requestTestMode(_:))
      .subscribe( { [weak self] _ in
        //do stuff })
      .disposed(by: disposeBag)
}

太好了,编译器很高兴,它可以工作。在我的世界里,这解决了内存泄漏问题,因为我不再使用需要引用 .但是,我的一个同事告诉我,这与不在 ;并且您仍然需要使用嵌套的 .我真的看不出它们是一回事,因为甚至不再有参考了。closureself[weak self]closurememory leaksfunctionself

无论如何,我的问题是:我是否使用 ,并使用上面的嵌套函数来解决这个问题,或者我的同事是对的:这是一回事;我所做的没有好处吗?memory leaksself[weak self]

iOS Swift 内存泄漏 闭包 RX-SWIFT

评论

1赞 matt 2/24/2023
对不起,我知道这不是你问的,但让我们退后一步。 确实错了。你为什么不直接修复它?更改为 .我的意思是,重点是它变成了一个可选的,这样它就不会被保留。说而不是,即使编译器没有阻止你,也会否定练习的全部目的:你正在联系,你说你不想做的事情。weak self] (_: Int?) in self.parameterService.requestTestMode()self.parameterServiceself?.parameterServiceweak selfselfselfself?self
0赞 Sweeper 2/24/2023
如果没有被捕获,最终如何被调用?selfparameterService.requestTestMode()
0赞 matt 2/24/2023
然而,我确实认为这个问题的整个前提是错误的。之所以需要这种舞蹈,是因为否则对自我的强烈引用就会被自我存储起来,从而导致一个保留循环,在这个循环中,自我在应该释放的时候没有被释放。要了解这种情况是否正在发生,请实施并记录它。如果发生这种情况,请修复它。如果不是,则不执行任何操作。但不要继续以这种下意识的、可怕的、自动的方式使用。回答你自己的问题:首先是内存问题吗?如果是这样,也只有如果是这样,你的句法游戏解决了吗?是或否?weak selfdeinitweak self
0赞 matt 2/24/2023
相关>保留
0赞 matt 2/24/2023
另外,这个弥漫在你的代码中的神秘咒语到底是什么?请摆脱它。它什么都不做,而且会惹恼编译器。(_: Int?)

答:

1赞 Daniel T. 2/24/2023 #1

但是,我的一位同事告诉我,这与在闭合中不使用[弱我]是一回事;并且您仍然会使用嵌套函数进行内存泄漏。

你的同事是对的。(这让我很惊讶。

幸运的是,有更简单的方法:

最明显的是:通过直接捕获 parameterService 而不是通过 self 间接捕获,可以避免捕获 self。.flatMap { [parameterService] _ in parameterService.requestTestMode() }

另一种选择:要发出的值是有问题的,因为你使用了 Single,所以你必须发出一些东西。如果您使用了 Might 或 Observable,则可以只使用.flatMap { [weak self] _ in self?.parameterService.requestTestMode() ?? .just(0) }.empty()

喜欢这个:.asMaybe().flatMap { [weak self] _ in self?.parameterService.requestTestMode().asMaybe() ?? .empty() }

最后,您可以使用一个自由函数(一个不绑定到任何类或结构的函数):

func requestTestMode(parameterService: ParameterService) -> (Int?) -> Single<Int?> {
    { _ in parameterService.requestTestMode() }
}

可以这样使用: 这实际上与我上面给出的第一个选项相同。.flatMap(requestTestMode(parameterService: parameterService))

评论

0赞 Joakim Sjöstedt 2/24/2023
我只是在想,“希望丹尼尔 T. 做出回应,因为他总是给出非常棒、清晰、易于理解的答案”。非常感谢 T@Daniel。
0赞 Daniel T. 2/24/2023
@JoakimSjöstedt我不得不更新我的答案。我的初步评估是错误的。
0赞 Joakim Sjöstedt 2/24/2023
这太令人惊讶了!谢谢你清理它!