Swift Computed properties cannot be used in init?

旧巷老猫 提交于 2019-12-02 02:41:55

问题


I am trying to use MultipeerConnectivity framework with Swift. I have following properties:

var peerId: MCPeerID?;
let advertiser: MCNearbyServiceAdvertiser;
let browser: MCNearbyServiceBrowser;
var session: MCSession? 
 ....

In my init method, I initialize all my stored properties like this:

  init() {
    let defaults = NSUserDefaults.standardUserDefaults();
    let dataToShow = defaults.dataForKey("kPeerID");
        peerId = NSKeyedUnarchiver.unarchiveObjectWithData(dataToShow) as? MCPeerID;
    if !peerId {
        peerId = MCPeerID(displayName: UIDevice.currentDevice().name);
        let data: NSData = NSKeyedArchiver.archivedDataWithRootObject(peerId);
        defaults.setObject(data, forKey: "kPeerID");
        defaults.synchronize();
    }

    advertiser = MCNearbyServiceAdvertiser(peer: peerId, discoveryInfo:nil, serviceType: "stc-classroom");
    browser = MCNearbyServiceBrowser(peer: peerId, serviceType: "stc-classroom");
    session = MCSession(peer: self.peerId);
    super.init();

    session!.delegate = self;
    advertiser.delegate = self;
    browser.delegate = self;
}

Now as you can see there is quite a bit lines of code to assign value to peerId (Apple recommended way), so I thought it would be nice to put that logic in a computed property so I replaced peerId stored property with a computed property and init method like this:

 var peerId: MCPeerID {
    let defaults = NSUserDefaults.standardUserDefaults();
    let dataToShow = defaults.dataForKey("kPeerID");
    var peer = NSKeyedUnarchiver.unarchiveObjectWithData(dataToShow) as? MCPeerID;
    if peer == nil {
        peer = MCPeerID(displayName: UIDevice.currentDevice().name);
        let data: NSData = NSKeyedArchiver.archivedDataWithRootObject(peer);
        defaults.setObject(data, forKey: "kPeerID");
        defaults.synchronize();
    }
    return peer!;
}

Now my init method is much cleaner and shorter like this:

init() {
    advertiser = MCNearbyServiceAdvertiser(peer: peerId, discoveryInfo:nil, serviceType: "stc-classroom");
    browser = MCNearbyServiceBrowser(peer: peerId, serviceType: "stc-classroom");
    session = MCSession(peer: self.peerId);        
    super.init();

    session!.delegate = self;
    advertiser.delegate = self;
    browser.delegate = self;
}

But now compiler complains as I am trying to access self while accessing peerId in browser/advertiser/session initialization. I understand in Swift all the properties must be initialized before we can use them and self is called implicitly and hence the error. But apparently that means I can't call computed properties in the init method, so I want to know if there is any better way of implementing what I am trying to do or not? I understand that I can create stored properties for every computed property and treat it as an iVar but it doesn't seem like an elegant solution either.

I would really appreciate your help regarding this guys.


回答1:


The Swift book doesn't address initialization & computed properties directly, but it has relevant information in the section about inheritance and initialization:

Two-Phase Initialization
Class initialization in Swift is a two-phase process. In the first phase, each stored property is assigned an initial value by the class that introduced it. Once the initial state for every stored property has been determined, the second phase begins, and each class is given the opportunity to customize its stored properties further before the new instance is considered ready for use.

Basically, you need to assign an initial value to all of your non-Optional stored properties (looks like advertiser and browser) before you can call any methods or access any computed properties. You might instead want to initialize peerId with a closure, using this method:

var peerId: MCPeerID = {
    let defaults = NSUserDefaults.standardUserDefaults()
    let dataToShow = defaults.dataForKey("kPeerID")
    var peer = NSKeyedUnarchiver.unarchiveObjectWithData(dataToShow) as? MCPeerID
    if peer == nil {
        peer = MCPeerID(displayName: UIDevice.currentDevice().name)
        let data: NSData = NSKeyedArchiver.archivedDataWithRootObject(peer)
        defaults.setObject(data, forKey: "kPeerID")
        defaults.synchronize()
    }
    return peer!
}()


来源:https://stackoverflow.com/questions/24940855/swift-computed-properties-cannot-be-used-in-init

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