在Swift中调用API时应该使用[weak self]吗

hlswsv35  于 2023-05-28  发布在  Swift
关注(0)|答案(2)|浏览(158)

我不确定在Swift中调用API时是否应该使用[weak self]。我正在使用Firebase创建一个用户,如果用户创建成功,我想使用self执行segue。
这是我的代码:

import UIKit 
import FirebaseAuth

class RegisterViewController: UIViewController {

  @IBOutlet weak var emailTextfield: UITextField!
  @IBOutlet weak var passwordTextfield: UITextField!

  @IBAction func registerPressed(_ sender: UIButton) {
    if let email = emailTextfield.text, let password = passwordTextfield.text {
        Auth.auth().createUser(withEmail: email, password: password) { authResult, error in
            if let e = error {
                print(e)
            } else {
                self.performSegue(withIdentifier: "registerToChat", sender: self)
            }
        }
    }
  }}

代码正在工作,但我不确定如果Firebase API请求不工作或延迟很长时间,并且RegisterViewController的self指针没有被释放,会发生什么。因此,我还想讨论一下使用可能会遇到延迟的API的一般做法,以及在这种情况下是否应该始终使用[weak self]。

8yparm6h

8yparm6h1#

在您的示例中,您几乎肯定会使用对self的弱引用。如果视图控制器已经被解除,那么执行segue就没有意义了。虽然这里没有持久的强引用周期风险,但是没有理由将这个视图控制器保留在内存中超过需要的时间。使用weak引用允许视图控制器在不再需要时立即释放,并且不必等待异步调用完成。使用weak引用是一种很好的防御性编程模式.
希望这回答了关于您的具体问题的问题,但更一般地说,有一些考虑因素:
1.这不是一个问题,但我们经常使用weak引用来消除持久的强引用循环的可能性(在这些情况下,闭包可能保存在某些属性中,并且API服务忽略了在完成时释放这个闭包)。这在成熟的API(如Firebase)中通常不是一个问题,但在自制的API或服务中更是一个问题,这些API或服务可能不会注意这些细节。当我们不能完全确定库在内存语义方面的规范性时,我们通常会以防御性的方式使用weak引用。
1.当处理一个不是视图控制器的调用者时(通常,视图控制器应该在相关的视图被解除时被释放;对于某些服务类可能不是这样),它会引发是否要在请求完成之前保留强引用。
例如,通过设计,如果您使用URLSession的委托,它会保持对其委托的强引用,直到会话无效。其他服务可能不会这样做。无论如何,肯定有这样的用例,在启动了一些异步请求之后,调用者可能希望将结果保存在一些模型对象或缓存中,而不管视图是否被解除。在这样的极端情况下,您可能有意识地需要一个临时的self强引用,直到请求完成。
1.当您关注内存语义时,通常更广泛的问题是“当调用者被释放时应该发生什么”。具体来说,在处理可取消的API时,我们不担心调用者的生命周期,而是关注被调用API的生命周期。具体来说,我们可能会在不再需要请求的结果时立即显式取消请求。在这种情况下,您不仅可以释放self的资源,还可以释放API服务的资源。
现在,在您的示例中,Auth可能不支持取消。如果没有,这个问题就没有意义了。但是在API确实支持取消的情况下,而不是纠缠于“我应该保持强引用直到请求完成”,你应该关注“如果调用者在异步请求完成之前被解散,我应该立即停止/取消异步API吗?””
所以,对于“我应该总是使用weak引用吗?”的简短回答是,“经常,但这取决于。”通常我们倾向于weak引用,但也有很多用例,我们可能会有意识地使用强引用或追求主动取消模式。
最后还有一个与内存语义无关的松散相关的问题。也就是说,如果用户在异步请求进行时完全离开应用程序,您希望发生什么?有时(尤其是上传、发布请求等),应用可能希望向操作系统请求一点额外时间,以防用户在请求进行时离开应用。例如,在iOS中,我们可以在后台继续前台工作。

42fyovps

42fyovps2#

你应该在一个闭包中使用[weak self],以避免给出强引用和避免引用循环。您可以查看此文档以了解是否应该始终在闭包内部使用[weak self]
参见You don’t (always) need [weak self]或Understanding Weak and Unowned References in Swift Closures。
对于API调用,使用[weak self]或执行异步操作是一个很好的实践,以防止强引用周期和潜在的内存泄漏。

相关问题