How to initialize CBCentralManager in Swift when a self reference is necessary

ε祈祈猫儿з 提交于 2019-12-22 09:00:10

问题


What are good ways to initialize an instance of CBCentralManager, which requires a delegate and is often pointing to the owning class?

I could declare the property as an implicitly unwrapped optional but doing so as a general practice seems rather not Swift-like and not very safe.

Alternatively, I can declare the property as an optional. But since CBCentralManager's initializers are not declared as failable, it doesn't seem to make sense to declare the instance as such.

Implicitly Unwrapped Optional:

class MyUnwrappedOptional: NSObject, CBCentralManagerDelegate {
    var centralManager: CBCentralManager! 

    func init() {
        super.init()

        centralManager = CBCentralManager(delegate: self, queue: nil, options:nil)

        // Subsequent usages of centralManager in other methods of this class don't require additional unwrapping.
        centralManager.scanForPeripheralsWithServices(services, options: nil)       
    }
}

Using An Optional:

class MyOptionalClass: NSObject, CBCentralManagerDelegate {
    var centralManager: CBCentralManager?

    func init() {
        super.init()

        centralManager = CBCentralManager(delegate: self, queue: nil, options:nil)

        // Subsequent usages of centralManager in other methods of this class require optional checks:
        if let central = centralManager {
            central.scanForPeripheralsWithServices(services, options: nil)      
        }

        // :: or ::
        central!.scanForPeripheralsWithServices(services, options: nil)
    }
}

Is either of these more preferred or is there another way to achieve this?


回答1:


There is no way to use self in an init method prior to initializing every non-lazy property that has no default value and is not optional (which have a default value of nil).

If you always initialize centralManager in init, and you have no code that will potentially make it nil, I would say that the CBCentralManager! declaration is a good choice. That is one of the main purposes of the implicitly unwrapped optional type.

Here is the excerpt from the documentation about implicitly unwrapped optionals:

Sometimes it is clear from a program’s structure that an optional will always have a value, after that value is first set. In these cases, it is useful to remove the need to check and unwrap the optional’s value every time it is accessed, because it can be safely assumed to have a value all of the time.

These kinds of optionals are defined as implicitly unwrapped optionals. You write an implicitly unwrapped optional by placing an exclamation mark (String!) rather than a question mark (String?) after the type that you want to make optional.

If the program logic does potentially allow for it to be nil at some point when it might be used. Then a normal optional type is the appropriate choice.

One other possible option would be for you to declare your centralManager property as a lazy property. If you do this it won't be created until you access it, but you will be able to reference self and make it non-optional. When you need it to be created will govern if you use this option or not.

lazy var centralManager: CBCentralManager = { [unowned self] () -> CBCentralManager in
    CBCentralManager.init(delegate: self, queue: nil, options: [:])
}()


来源:https://stackoverflow.com/questions/33189011/how-to-initialize-cbcentralmanager-in-swift-when-a-self-reference-is-necessary

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!