无法将类型为'() -> _'的值转换为指定类型UIImageView。

19

我正在尝试使一个UIImage视图可点击,但是我没有成功。完成这项任务的最佳方法是什么?我得到的错误是"Cannot convert value of type '() -> _' to specified type 'UIImageView'"。

lazy var profileImageView: UIImageView = {
     let imageView = UIImageView()
     imageView.image = UIImage(named: "ic_file_upload_white_48pt")
     imageView.translatesAutoresizingMaskIntoConstraints = false
     imageView.contentMode = .scaleAspectFill

     imageView.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(handleSelectorProfileImage)))
     imageView.isUserInteractionEnabled = true
     return imageView
 }

3
尝试删除懒惰声明,并在闭括号后加上 ()。 - Leo Dabus
因为那是一个变量,而不是返回类型为UIImageView的函数。你应该创建一个带有返回类型的处理程序。 - mattd
3个回答

67
你告诉编译器你想让profileImageView包含一个闭包。如果你想让profileImageView包含该闭包的结果,你需要在后面加上括号来调用闭包:
lazy var profileImageView: UIImageView = {
  //your code here
  return imageView
}()

注意闭包后面的括号。这将调用闭包并将其结果分配给变量`profileImageView`,在第一次引用该变量时。

编辑:

每当你看到`(<something>) -> type`这样的类型时,它就是一个闭包。`->`部分将参数与返回类型分隔开。Swift的错误消息可能很难解读,但这是一个提示,你返回的是一个闭包,而不是预期的内容。

编辑 #2:

请注意,在Swift中,与闭包定义的变量相关的有两个类似的结构:计算属性和延迟变量。

计算属性

计算属性的声明方式为

var computed: type { closure_returning_result }

在计算属性中没有等号。每次从计算属性请求一个值时,闭包代码都会运行,并且闭包的返回值将成为属性的新值。
懒加载变量的写法如下:
lazy var lazy: type = expression_returning_result

表达通常是一个闭包,但不一定非要是这样。一个常见的懒惰变量的形式会使用闭包,就像这样:
lazy var lazy: type = { closure_returning_result }()

在声明懒惰变量时,需要使用等号。如果你使用闭包给懒惰变量赋值,你需要在闭包后面加上括号,这样懒惰变量将被赋予闭包返回的值,而不是闭包本身。当@jameel在他的代码中忘记闭合括号时,就会出现这个问题。
考虑以下代码:
var counter = 1

var computed: Int  {
    counter += 1
    return counter
}

lazy var lazy: Int = {
    counter += 1
    return counter
}()

print("lazy = \(lazy)")
print("lazy = \(lazy)")
print("lazy = \(lazy)")

print("computed = \(computed)")
print("computed = \(computed)")
print("computed = \(computed)")

这将打印输出:

lazy = 2
lazy = 2
lazy = 2
computed = 3
computed = 4
computed = 5

请注意,懒惰变量的值不会改变,但计算属性的值会改变。这是它们之间的关键区别。
懒惰变量在第一次被调用时进行评估,并且该值会“固定”。给出该值的表达式/闭包直到被调用时才会运行,而且只运行一次。
相比之下,计算属性始终使用闭包,每次请求计算属性的值时,都会执行该闭包。

编辑#3:(2023年9月28日)

还要注意,懒惰变量直到首次引用时才被初始化,这可能会产生后果。
如果您颠倒了上面的测试代码的顺序:
print("computed = \(aFoo.computed)")
print("computed = \(aFoo.computed)")
print("computed = \(aFoo.computed)")

print("lazy = \(aFoo.lazy)")
print("lazy = \(aFoo.lazy)")
print("lazy = \(aFoo.lazy)")

print("computed = \(aFoo.computed)")

print("lazy = \(aFoo.lazy)")

print("computed = \(aFoo.computed)")


输出将会是
computed = 2
computed = 3
computed = 4
lazy = 5
lazy = 5
lazy = 5
computed = 6
lazy = 5
computed = 7

通过这个示例代码,我们在调用计算属性3次之后才引用到`lazy`。一旦我们引用到`lazy`,它会递增`counter`并将该结果保存为其新值,永远不变。
如果我们再次引用`computed`,它会再次递增`counter`。
`lazy`的值在代码执行的整个生命周期中都固定为5。

6

为了执行计算属性,您应在其结尾处添加括号。

lazy var profileImageView: UIImageView = {
     let imageView = UIImageView()
     imageView.image = UIImage(named: "ic_file_upload_white_48pt")
     imageView.translatesAutoresizingMaskIntoConstraints = false
     imageView.contentMode = .scaleAspectFill

     imageView.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(handleSelectorProfileImage)))
     imageView.isUserInteractionEnabled = true
     return imageView
 }()

2
是的,没错。我一年多前也说过这个,但我也解释了为什么。 - Duncan C

6

看起来是语法问题,请尝试:

func profileImageView() -> UIImageView {
        let imageView = UIImageView()
        imageView.image = UIImage(named: "ic_file_upload_white_48pt")
        imageView.translatesAutoresizingMaskIntoConstraints = false
        imageView.contentMode = .scaleAspectFill

        imageView.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(handleSelectorProfileImage)))
        imageView.isUserInteractionEnabled = true
        return imageView
}

23
使用lazy var是完全有效的,但是闭包后面缺少括号。 - Duncan C

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接