self.init() 导致便利 init() 无限运行

Posted

技术标签:

【中文标题】self.init() 导致便利 init() 无限运行【英文标题】:self.init() causes convenience init() to run infinitelyself.init() 导致便利 init() 无限运行 【发布时间】:2020-08-18 17:25:12 【问题描述】:

我有一个我正在尝试启动的课程,但是,正如标题所示,convenience init 方法可以无限运行。这是为什么呢?

class Peripheral: CBPeripheralManager, CBPeripheralManagerDelegate

    var peripheralManager : CBPeripheralManager!
    convenience init(delegate: CBPeripheralManagerDelegate?, queue: DispatchQueue?)
    
        print("howdy")
        self.init()
        peripheralManager = CBPeripheralManager(delegate: self, queue: nil, options: [CBPeripheralManagerOptionShowPowerAlertKey: true])
        peripheralManager.add(myCBService)
    
    func peripheralManagerDidUpdateState(_ peripheral: CBPeripheralManager)
    
    


let myPeripheral = Peripheral.init()

我运行我的程序大约十秒钟,“你好”打印了 42,266 次。我把打印语句放在 self.init() 的下面,“你好”根本没有打印出来。我做错了什么?

【问题讨论】:

【参考方案1】:

您发现 Objective-C 和 Swift 实现之间存在一些冲突。

CBPeripheralManager 有 3 个 init 方法,它们基本上是这样工作的:

convenience init() 
    self.init(delegate: nil, queue: nil)


convenience init(delegate: CBPeripheralManagerDelegate?, queue: DispatchQueue?) 
    self.init(delegate: delegate, queue: queue, options: nil)  


// designated
init(delegate: CBPeripheralManagerDelegate?, queue: DispatchQueue?, options: [String : Any]?)
   // the actual implementation

一旦你声明了一个新的convenience 初始化器,这两个便利初始化器将被删除,只有你定义的一个存在。通常,您根本无法拨打Peripheral.init()。然而,问题在于 Objective-C 类总是有一个没有参数的init 方法。

这意味着init() 委托给您的新便利初始化程序,而您的初始化程序再次委托给init(),最终进入无限循环。

解决办法,不要拨打init()。调用指定的初始化器:

class Peripheral: CBPeripheralManager, CBPeripheralManagerDelegate 
    var peripheralManager : CBPeripheralManager!

    convenience init(delegate: CBPeripheralManagerDelegate?, queue: DispatchQueue?) 
        print("howdy")
        self.init(delegate: delegate, queue: queue, options: nil)
        peripheralManager = CBPeripheralManager(delegate: self, queue: nil, options: [CBPeripheralManagerOptionShowPowerAlertKey: true])
        peripheralManager.add(myCBService)
    

但是,似乎还有一个更深层次的问题。为什么要从CBPeripheralManager 内部创建一个新的CBPeripheralManager

你想要的不就是下面的吗?:

class Peripheral: NSObject, CBPeripheralManagerDelegate 
    var peripheralManager: CBPeripheralManager!
    override init() 
        print("howdy")

        super.init()

        peripheralManager = CBPeripheralManager(delegate: self, queue: nil, options: [CBPeripheralManagerOptionShowPowerAlertKey: true])
        peripheralManager.add(myCBService)
    

    func peripheralManagerDidUpdateState(_ peripheral: CBPeripheralManager) 
    

【讨论】:

感谢@Sulthan 的帮助。您的彻底回答为我消除了很多困惑,但是我按照说明进行操作,它告诉我在 super.init() 调用之前我不能引用 self 。我该如何解决这个问题,以及为什么引用 self 需要调用 super.init()? @Nathan 哦,对不起,我错过了self 参考。那么使用var 可能是一个更好的主意。或lazy var。有问题的部分是你不能使用self,直到整个对象被构造(在初始化之后)。而且你必须在调用super.init之前初始化局部变量。有一些变通方法,但其中一些并不适用于所有情况。

以上是关于self.init() 导致便利 init() 无限运行的主要内容,如果未能解决你的问题,请参考以下文章

为啥在我的结构中调用 self.init 之前使用了错误“self”?

如何在 swift 初始化程序中确定 Self 类

CoreData 和 Codable 类编译器错误:在从初始化程序返回之前,未在所有路径上调用“self.init”

Swift: self.init (coder : aDecoder) 正在使用 EXC_BAD_ACCESS 使应用程序崩溃

json.swift 错误是 Self.init 在委托初始化程序中的所有路径上都没有调用

在viewDidLoad之前编写init方法将模型传递给视图控制器[重复]