【问题标题】:Swift Computed properties cannot be used in init?Swift Computed 属性不能在 init 中使用?
【发布时间】:2014-09-16 10:19:28
【问题描述】:

我正在尝试将 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 存储属性替换为计算属性和 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,但它似乎也不是一个优雅的解决方案。

非常感谢您对这些人的帮助。

【问题讨论】:

    标签: ios swift multipeer-connectivity


    【解决方案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!
    }()
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-10-19
      • 2019-02-23
      • 1970-01-01
      • 1970-01-01
      • 2015-07-19
      • 1970-01-01
      • 2011-06-29
      • 1970-01-01
      相关资源
      最近更新 更多