在 super.init 中引用 self

2023-11-26

我有以下代码(编辑:更新了代码,以便每个人都可以编译并查看):

import UIKit

struct Action
{
    let text: String
    let handler: (() -> Void)?
}

class AlertView : UIView
{
    init(actions: [Action]) {
        super.init(frame: .zero)

        for action in actions {
//            let actionButton = ActionButton(type: .custom)
//            actionButton.title = action.title
//            actionButton.handler = action.handler
//            addSubview(actionButton)
        }
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
}

class TextAlertView : AlertView
{
    init() {
        super.init(actions: [
            Action(text: "No", handler: nil),
            Action(text: "Yes", handler: { [weak self] in
                //use self in here..
            })
        ])
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
}

class MyViewController : UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()

        let alert = TextAlertView()
        view.addSubview(alert)
        self.view = view
    }
}

每次我实例化TextAlertView,它崩溃了super.init访问不良。但是,如果我改变:

Action(title: "Yes", { [weak self] in
    //use self in here..
})

to:

Action(title: "Yes", {
    //Blank.. doesn't reference `self` in any way (weak, unowned, etc)
})

有用!

有没有办法可以参考self在超级初始化期间,它是否弱于操作块内(在上面我在参数中执行此操作)super.init?

代码编译......它只是在运行时随机崩溃。


简短回答:

您无法捕获和使用self作为之前的值super.init返回。就您而言,您正在尝试“通过”self to super.init作为一个论点。

至于为什么第二部分有效,只是因为不使用self在其中,它没有捕获self,因此它不使用self作为一个值。

如果你不想使用self在闭包中,那么你不需要担心strong/weak那里有参考,因为没有参考self根本就在那里(因为它没有被捕获)。没有保留周期的危险。


关于“使用self作为一个值” - 你可以使用self在赋值的左侧来引用属性self初始化它们时:

let myProperty: String

init(with myProperty: String) {
    // this usage of self is allowed
    self.myProperty = myProperty
    super.init(nibName: nil, bundle: nil)
}

带有参考资料和内容的更长答案:

As per 文档:

安全检查4

初始化程序不能调用任何实例方法、读取任何实例属性的值或将 self 视为一个值直到第一阶段初始化完成后。

初始化的第一阶段通过调用结束super.init, 当。。。的时候

来自同一文档:

Phase 1

在类上调用指定的或方便的初始值设定项。

为该类的新实例分配内存。内存尚未初始化。

该类的指定初始值设定项确认该类引入的所有存储属性都有一个值。这些存储属性的内存现已初始化。

指定的初始值设定项移交给超类初始值设定项,以对其自己的存储属性执行相同的任务。

这沿着类继承链继续向上,直到到达链的顶部。

一旦到达链的顶部,并且链中的最终类已确保其所有存储的属性都有值,则认为实例的内存已完全初始化,并且阶段 1 完成。

所以只有在打电话之后super.init你可以使用self作为值:

Phase 2

从链的顶部开始,链中的每个指定的初始化程序都可以选择进一步自定义实例。初始化程序现在能够访问 self 并可以修改其属性、调用其实例方法等。

最后,链中的任何便利初始化程序都可以选择自定义实例并使用self.

现在,当你尝试使用时,我一点也不感到惊讶self作为闭包捕获列表中的值,表明它崩溃了。更令我惊讶的是,编译器确实允许您这样做 - 现在我猜这是未实现错误处理的边缘情况。

在第二种情况下:

Action(title: "Yes", {
    //Blank.. doesn't reference `self` in any way (weak, unowned, etc)
})

你并没有真正捕捉到self,这就是它被允许并且有效的原因。但您无权访问self那里。尝试添加一些使用的代码self编译器会抱怨:

enter image description here

所以最后,如果你想使用self在闭包中,您必须找到一种方法如何首先调用super.init并且只有在那之后添加self捕获属性的闭包。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

在 super.init 中引用 self 的相关文章

随机推荐

  • 纹理视图获取表面

    我正在使用 ExoPlayer 库 它需要一个 Surface 但是我找不到任何方法来检索 Textureview 的底层 Surface 有任何想法吗 Surfaceview 有一个方法 surfaceView getHolder get
  • 可以物理访问源生成器创建的文件吗?

    是否有任何标准方法 选项 如何排列通过生成的文件Source Generators并添加到构建过程中也在项目结构中物理可见 因此开发人员可以查看结果代码 例如通过 VS 解决方案资源管理器窗口 我的意思是除了将代码直接保存到生成器的文件中之
  • Spring Data - 如果参数具有空值,则忽略该参数

    我想要一个带有两个参数的 Spring 数据存储库接口 有没有办法让它具有以下行为 MyObject findByParameterOneAndParameterTwo String parameterOne String paramete
  • Javac 缺少有效最终优化

    Fact javac被编程来检测变量是否final或者如果它可以被视为有效地 final Proof 这段代码说明了这一点 public static void finalCheck String str1 hello Runnable r
  • WiX RemoveFolderEx 不起作用?

    我希望 WiX 在卸载时删除 AppData 文件夹 因此我查看了 RemoveFolderEx 并遵循了一些有关如何使其工作的帖子 指南 据我所知 我的实现应该有效 但事实并非如此 我正在使用以下内容
  • 如何一次构建多个包二进制文件

    我在不同的地方看到过这个讨论 答案包括 使用 cmd foo cmd bar 类型的文件夹结构 这对我不起作用 这有效 du a 8 src cmd bin1 main go 8 src cmd bin1 8 src cmd bin2 ma
  • ESLint 与 React 给出 `no-unused-vars` 错误

    我已经设置了eslint eslint plugin react 当我运行 ESLint 时 linter 返回no unused vars每个 React 组件的错误 我假设它没有识别出我正在使用 JSX 或 React 语法 有任何想法
  • android 显示软键盘时如何向上移动布局

    我的登录屏幕有两个EditTexts和我的布局中的登录按钮 问题是 当我开始打字时 会显示软键盘并覆盖登录按钮 当布局出现时 如何将布局向上或键盘上方推 我不想使用ScrollView 只想实现它而不向下滚动 那怎么办呢 Set windo
  • 防止服务器中出现多个实例相同的用户名

    我开发了一个托管在一台服务器上的应用程序 许多用户通过远程桌面连接访问它 但有时我在任务管理器中看到同一用户打开了 2 个实例 我需要防止同一用户无法打开多个实例 但请注意 该程序可以由不同的用户多次打开 请原谅我的英语 谢谢 PS 我使用
  • 在 Java Lambda 中,为什么对捕获的变量调用 getClass()

    如果你看一下字节码 Consumer
  • 使用VBA查找Windows中安装的MySQL ODBC驱动程序的版本

    使用 Visual Basic 进行应用程序 如何查明用户计算机上的 Windows 中安装了哪个版本的 MySQL ODBC 驱动程序 我有一个 Microsoft Access 应用程序 它使用 MySQL ODBC 驱动程序进行连接
  • 如何在mysql json表中使用where子句进行查询

    我使用的是mysql 5 7 x 我可以创建一个 mysql json 表 CREATE TABLE t1 jdoc JSON 我可以插入行 INSERT INTO t1 VALUES key1 value1 key2 value2 INS
  • 为什么Soap支持异步调用而Rest不支持?

    我在网上浏览了 Soap 与 Rest 发现大多数人都说 Soap 支持异步调用 而 Rest 不支持 但没有得到任何具体的例子 有人可以帮我吗 这是我提到的资源之一 http web archive org web 20120421084
  • 在 C++11 中实现 boost::Optional

    我正在尝试使用 c 11 功能实现 boost Optional 之类的数据结构 这是我到目前为止所拥有的 template
  • Android 可以进行点对点自组织网络吗?

    是否可以将 Android 设置为 ad hoc 对等 wifi 模式 例如 我想让一部电话广播一条消息 并让网络中的所有对等方接收广播 而无需服务器 我想使用 wifi 因为蓝牙范围更有限 这是有关您请求的功能的错误报告 它的状态是 已审
  • Angular 6 材质嵌套树不适用于动态数据

    我在用mat tree with mat nested tree node在角度 6 中 我想要的是当用户切换展开图标时动态加载数据 使用动态数据示例Flat Tree给出材料示例我尝试使用相同的概念Nested Tree 这是我到目前为止
  • 如何定义自己的asciidoc宏

    如何在 asciidoc asciidoctor 中定义宏 我将在文档的许多部分使用重复模式 因此我想进行参数化替换以避免多次输入相同的内容 特别是 我有以下 asciidoc 片段 set cellbgcolor grey grid no
  • 在网络浏览器中,窗口对象是本机 ECMAScript 对象吗?

    ECMAScript 规范定义了一个 在控制进入任何执行上下文之前创建的唯一全局对象 该全局对象是 ECMAScript 的标准内置对象 因此是本机对象 该规范还指出 除了本规范中定义的属性之外 全局 对象可能具有其他主机定义的属性 这可能
  • PHP - DOMDocument - 需要用新标签更改/替换现有 HTML 标签

    我正在努力改变一切 p 文档中的标签 p div 这是我想出来的 但它似乎不起作用 dom new DOMDocument dom gt loadHTML htmlfile data foreach dom gt getElementsBy
  • 在 super.init 中引用 self

    我有以下代码 编辑 更新了代码 以便每个人都可以编译并查看 import UIKit struct Action let text String let handler gt Void class AlertView UIView init