self.init使便捷的init{}无限运行

问题描述

我有一个要尝试初始化的类,但是,正如标题所示,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()

我运行程序大约十秒钟,“ howdy”打印了42266次。我将打印语句置于self.init()以下,而“ howdy”根本没有打印。我在做什么错了?

解决方法

您发现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,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,options: [CBPeripheralManagerOptionShowPowerAlertKey: true])
        peripheralManager.add(myCBService)
    }

    func peripheralManagerDidUpdateState(_ peripheral: CBPeripheralManager) {
    }
}