闭包不能隐式捕获变异的 self 参数 [英] Closure cannot implicitly capture a mutating self parameter

查看:42
本文介绍了闭包不能隐式捕获变异的 self 参数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我使用 Firebase 观察事件,然后在完成处理程序中设置图像

FirebaseRef.observeSingleEvent(of: .value, with: { (snapshot) in如果让 _ = snapshot.value 作为?NSNull {self.img = UIImage(named:"Some-image")!} 别的 {self.img = UIImage(named: "some-other-image")!}})

但是我收到此错误

<块引用>

Closure 不能隐式捕获变异的 self 参数

我不确定这个错误是关于什么的,搜索解决方案也没有帮助

解决方案

简短版

拥有您对 FirebaseRef.observeSingleEvent(of:with:) 的调用的类型很可能是值类型(struct?),在这种情况下是一个可变上下文可能不会在 @escaping 闭包中显式捕获 self.

简单的解决方案是将您拥有的类型更新为一次引用(class).

<小时>

更长的版本

observeSingleEvent(of:with:) Firebase 的方法声明如下

<块引用>

func observeSingleEvent(of eventType: FIRDataEventType,带块:@escaping (FIRDataSnapshot) ->空白)

block 闭包标有 @escaping 参数属性,这意味着它可能会转义其函数体,甚至是 self<的生命周期/code>(在您的上下文中).使用这些知识,我们构建了一个更小的例子,我们可以分析:

struct Foo {private func bar(with block: @escaping () -> ()) { block() }变异 func bax() {bar { print(self) }//这个闭包可能比self"更长寿/* 错误:闭包不能隐式捕获一个变异自参数 */}}

现在,错误信息变得更有说服力,我们转向以下在 Swift 3 中实现的进化提议:

声明[强调我的]:

<块引用>

捕获一个 inout 参数,在变异中包含 self方法,成为可转义闭包文字中的错误,除非捕获是明确的(因此是不可变的).

现在,这是一个关键点.对于 value 类型(例如 struct),我相信拥有对 observeSingleEvent(...) 在您的示例中,这样的显式捕获是不可能的,afaik(因为我们正在使用值类型,而不是引用类型).

解决这个问题的最简单的方法是使拥有 observeSingleEvent(...) 的类型成为引用类型,例如一个 class,而不是一个 struct:

class Foo {在里面() {}private func bar(with block: @escaping () -> ()) { block() }功能 bax() {酒吧{打印(自我)}}}

请注意,这将通过强引用捕获self;根据您的上下文(我自己没有使用过 Firebase,所以我不知道),您可能希望弱地明确捕获 self,例如

FirebaseRef.observeSingleEvent(of: .value, with: { [weak self] (snapshot) in ...

I am using Firebase to observe event and then setting an image inside completion handler

FirebaseRef.observeSingleEvent(of: .value, with: { (snapshot) in
        if let _ = snapshot.value as? NSNull {
            self.img = UIImage(named:"Some-image")!
        } else {
            self.img = UIImage(named: "some-other-image")!
        }
})

However I am getting this error

Closure cannot implicitly capture a mutating self parameter

I am not sure what this error is about and searching for solutions hasn't helped

解决方案

The short version

The type owning your call to FirebaseRef.observeSingleEvent(of:with:) is most likely a value type (a struct?), in which case a mutating context may not explicitly capture self in an @escaping closure.

The simple solution is to update your owning type to a reference once (class).


The longer version

The observeSingleEvent(of:with:) method of Firebase is declared as follows

func observeSingleEvent(of eventType: FIRDataEventType, 
     with block: @escaping (FIRDataSnapshot) -> Void)

The block closure is marked with the @escaping parameter attribute, which means it may escape the body of its function, and even the lifetime of self (in your context). Using this knowledge, we construct a more minimal example which we may analyze:

struct Foo {
    private func bar(with block: @escaping () -> ()) { block() }

    mutating func bax() {
        bar { print(self) } // this closure may outlive 'self'
        /* error: closure cannot implicitly capture a 
                  mutating self parameter              */
    }
}

Now, the error message becomes more telling, and we turn to the following evolution proposal was implemented in Swift 3:

Stating [emphasis mine]:

Capturing an inout parameter, including self in a mutating method, becomes an error in an escapable closure literal, unless the capture is made explicit (and thereby immutable).

Now, this is a key point. For a value type (e.g. struct), which I believe is also the case for the type that owns the call to observeSingleEvent(...) in your example, such an explicit capture is not possible, afaik (since we are working with a value type, and not a reference one).

The simplest solution to this issue would be making the type owning the observeSingleEvent(...) a reference type, e.g. a class, rather than a struct:

class Foo {
    init() {}
    private func bar(with block: @escaping () -> ()) { block() }

    func bax() {
        bar { print(self) }
    }
}

Just beware that this will capture self by a strong reference; depending on your context (I haven't used Firebase myself, so I wouldn't know), you might want to explicitly capture self weakly, e.g.

FirebaseRef.observeSingleEvent(of: .value, with: { [weak self] (snapshot) in ...

这篇关于闭包不能隐式捕获变异的 self 参数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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