【问题标题】:Holding a Strong ref to local object that uses closure [Swift]持有对使用闭包的本地对象的强引用 [Swift]
【发布时间】:2019-05-16 16:17:22
【问题描述】:

我有一个关于持有使用闭包的本地对象的强引用的问题。 我有以下代码,其中对象 B 使用了一个关闭类型 A 的本地对象的方法。 对象 A 中的方法使用异步操作执行一些网络任务,然后将闭包返回给对象 b。 由于对象 A 在 B 的方法中是本地的,并且由于我在对象 A 异步任务中使用 [weak self](以防止保留循环),因此该对象被释放。

为了确保本地 A 对象只有在闭包完成后才会被释放,我应该在以下代码中进行哪些更改?

这是重要代码的一部分:

class A {
    var restAPI: RestAPI?

    func fetchNews(completion: (_ json: [String:Any])->()) {
        // .....
        self.restAPI.fetch(url: url, results: { [weak self] (json) in // 
            completion(json)
        })
        // .....
    }
}

class B {
    // .... 
    // ... call to updateNews()

    func updateNews() {
        let aFetcher: A() 
        aFetcher.fetchNews(completion : { 
            // <<<< // aFetcher gets released and closue never called
            // parse...
        }
    }
}

【问题讨论】:

  • 其实这个问题没有好的解决办法。主要问题是线程安全。您最好在 A 类实例中定义和初始化变量 restAPI“outside”,该变量必须超过 B 类实例。您还需要在创建它的同一线程上销毁它。最好在 A 类的实例中再次这样做。

标签: ios swift memory closures strong-parameters


【解决方案1】:

你需要在类的顶层有一个强引用。

但是,不要永久保留引用,而是要可靠地保留和释放它,在 class B 中添加一个可选的存储属性,并在完成闭包中将其设置为 nil

class B {

    var fetcher : A?

    // MARK: - Public
    func updateNews() {
        fetcher = A()
        fetcher!.fetchNews(completion : { [unowned self] in
            // parse...

            self.fetcher = nil
        }
    }
}

【讨论】:

  • 谢谢大家,但是如果我希望变量是本地变量而不是类属性怎么办?那我该怎么办?
  • 其实它不是一个 class 属性它是一个 instance 属性。不过,您需要对 A 类的实例进行强引用(不能是本地的)
  • 恕我直言,这不是一个好的模式。它还带有一个微妙的问题:如果完成处理程序保留了对象的最后一个强引用,那么当完成处理程序执行时,它将在该线程上被破坏。由于创建它的线程(将调用updateNews())可能是另一个线程,这会产生数据竞争。为了让它工作,你需要“线程限制”(另一种不好的模式),但是你不需要 B 类中的 var fetcher。
【解决方案2】:

您将 aFetcher 声明为 func updateNews() 范围内的 let
updateNews() 的范围到达其末尾时,aFetcher 将被释放。 您的内部 fetch 函数中有 [weak self]。 在这个阶段 aFetcher 将被释放,因为 updateNews() 完成了它的执行并且没有对该对象的强引用。

您只需将变量 aFetcher 添加到 B 类,以确保您对 aFetcher 具有强引用。

class B {

    // MARK: - Vars
    private let aFetcher = A()

    // MARK: - Public
    func updateNews() {
        aFetcher.fetchNews(completion : {
            // parse...
        }
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-08-18
    • 2014-08-12
    • 1970-01-01
    • 1970-01-01
    • 2016-02-04
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多