使用苹果公司的新Combine框架时如何防止强参考周期(.assign引起问题) [英] How to prevent strong reference cycles when using Apple's new Combine framework (.assign is causing problems)

查看:48
本文介绍了使用苹果公司的新Combine框架时如何防止强参考周期(.assign引起问题)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我不太了解如何正确地将订阅者存储在类中,以使它们持久化,但又不阻止对象被初始化.这是一个对象不会取消初始化的示例:

I don't quite understand how to properly store subscribers inside a class so that they persist but don't prevent the object from being deinitialized. Here's an example where the object won't deinit:

import UIKit
import Combine

class Test {
    public var name: String = ""

    private var disposeBag: Set<AnyCancellable> = Set()

    deinit {
        print("deinit")
    }

    init(publisher: CurrentValueSubject<String, Never>) {
        publisher.assign(to: \.name, on: self).store(in: &disposeBag)
    }
}

let publisher = CurrentValueSubject<String, Never>("Test")

var test: Test? = Test(publisher: publisher)
test = nil

当我将 assign 替换为 sink (在其中我正确声明了 [weak self] )时,它实际上确实可以正确初始化(可能是因为 assign 会以导致问题的方式访问 self .

When I replace the assign with a sink (in which I properly declare [weak self]) it actually does deinit properly (probably because the assign accesses self in a way that causes problems).

例如,在使用 .assign 时如何防止强参考循环?

How can I prevent strong reference cycles when using .assign for instance?

谢谢

推荐答案

您可以用接收器(.sink)替换.asign(to :),其中其关闭中的[weak self]会阻止内存循环.在Playground尝试一下,看看有什么不同

you can replace .asign(to:) with sink where [weak self] in its closure brake the memory cycle. Try it in Playground to see the difference

final class Bar: ObservableObject {
    @Published var input: String = ""
    @Published var output: String = ""

    private var subscription: AnyCancellable?

    init() {
        subscription = $input
            .filter { $0.count > 0 }
            .map { "\($0) World!" }
            //.assignNoRetain(to: \.output, on: self)
            .sink { [weak self] (value) in
                self?.output = value
        }

    }

    deinit {
        subscription?.cancel()
        print("\(self): \(#function)")
    }
}

// test it!!
var bar: Bar? = Bar()
let foo = bar?.$output.sink { print($0) }
bar?.input = "Hello"
bar?.input = "Goodby,"
bar = nil

它打印

Hello World!
Goodby, World!
__lldb_expr_4.Bar: deinit

所以我们没有内存泄漏!

so we don't have the memory leak !

最终在forums.swift.org上,有人做出了一个可爱的

finally at forums.swift.org someone make a nice little

extension Publisher where Self.Failure == Never {
    public func assignNoRetain<Root>(to keyPath: ReferenceWritableKeyPath<Root, Self.Output>, on object: Root) -> AnyCancellable where Root: AnyObject {
        sink { [weak object] (value) in
        object?[keyPath: keyPath] = value
    }
  }
}

这篇关于使用苹果公司的新Combine框架时如何防止强参考周期(.assign引起问题)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆