我正在尝试将MultipeerConnectivity框架与Swift结合使用。我具有以下属性:

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存储的属性,并且初始化方法是这样的:
 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;
}

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

非常感谢您在这方面的帮助。

最佳答案

Swift书没有直接涉及初始化和计算属性,但在继承和初始化部分中有相关信息:

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

基本上,您需要为所有非可选存储属性(看起来像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!
}()

关于ios - Swift计算属性不能在init中使用?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/24940855/

10-12 00:15
查看更多