swift Computed属性不能在init中使用?

时间:2014-07-24 18:01:01

标签: ios swift multipeer-connectivity

我正在尝试使用Swift的MultipeerConnectivity框架。我有以下属性:

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

在我的init方法中,我初始化所有存储的属性,如下所示:

  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;
}

现在您可以看到有相当多的代码行为peerId赋值(Apple推荐方式),所以我认为将该逻辑放在计算属性中会很好,所以我用一个peerId存储属性替换了计算属性和init方法如下:

 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!;
}

现在我的init方法更清晰,更短,如下所示:

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;
}

但是现在编译器抱怨我在浏览器/广告商/会话初始化中访问peerId时尝试访问self。我理解在Swift中,所有属性必须在我们使用它们之前初始化,并且self被隐式调用,因此错误。但显然这意味着我不能在init方法中调用计算属性,所以我想知道是否有更好的方法来实现我想要做的或不做什么?我知道我可以为每个计算属性创建存储属性并将其视为iVar,但它似乎也不是一个优雅的解决方案。

我真的很感谢你对这些人的帮助。

1 个答案:

答案 0 :(得分:1)

Swift书并没有解决初始化问题。直接计算属性,但它在有关继承和初始化的部分中有相关信息:

  

两阶段初始化
     Swift中的类初始化是一个两阶段的过程。在第一阶段,每个存储的属性是   由引入它的类分配初始值。一旦   每个存储的属性的初始状态已经确定,   第二阶段开始,每个班级都有机会   在新实例之前进一步自定义其存储的属性   被认为可以使用了。

基本上,您需要为所有非可选存储属性(看起来像advertiserbrowser)分配初始值,然后才能调用任何方法或访问任何计算属性。您可能希望使用闭包using this method

初始化peerId
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!
}()