Swift的计算属性不能在init中使用?

我正在尝试与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赋值(苹果推荐的方式),所以我认为把这个逻辑放到一个计算属性中是很好的,所以我用一个计算属性replace了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时访问自己。 我明白,在Swift中,所有的属性必须被初始化,然后我们才能使用它们,并且隐式地调用self,从而产生错误。 但显然这意味着我不能在init方法中调用计算属性,所以我想知道是否有更好的方法来实现我正在尝试做什么或不是? 我明白,我可以为每个计算属性创build存储的属性,并将其视为一个iVar,但它似乎不是一个优雅的解决scheme。

我真的很感激你对这个家伙的帮助。

Swift书不直接解决初始化和计算属性问题,但它在关于inheritance和初始化的部分有相关的信息:

两阶段初始化
Swift中的类初始化是一个两阶段的过程。 在第一阶段,每个存储的属性由引入它的类来分配一个初始值。 一旦确定了每个存储属性的初始状态,第二阶段开始,并且每个类都有机会在新实例被认为准备好使用之前进一步定制其存储的属性。

基本上,您需要为所有非可选的存储属性(看起来像advertiserbrowser )分配初始值,然后才能调用任何方法或访问任何计算的属性。 您可以改为使用以下方法使用闭包来初始化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! }()