2016-09-18 70 views
1

在斯威夫特3去除dispatch_once功能訪問的「自我」和migration guide建議使用初始化關閉:在初始化關閉

讓myGlobal = {...全球包含在呼叫初始化一個封閉...}( )

_ = myGlobal //使用myGlobal將只在第一次使用時調用初始化代碼。

我想從訪問初始化閉包內的「自我」的實例變量,像這樣:

class SomeClass { 
    var other = SomeOtherClass() 

    let initialize:() = { 
     // self.other - this doesn't work, complains about unresolved identifier 'self' 
     // how to access self.other here? 
    }() 

    func doSomething() { 
     // initialize will only be called once 
     initialize 
    } 
} 

爲什麼是「自我」不是在封閉訪問,怎樣才能使之成爲?

+1

使用dispatch_once與實例屬性,以確保「每個實例一次」初始化是*永遠是錯的,*參見例如這樣的回答http://stackoverflow.com/a/19845164/1187415從蘋果電腦的工程師。 –

+0

那麼Swift 3中的正確方法是確保實例初始化代碼只運行一次,並且能夠設置實例變量?在這種情況下,我不能使用init()的變體,因爲類(NSViewController)只需運行初始化代碼一次,但是在'NSViewController'生命週期(即'viewDidAppear')的特定點之後。 @vadian提供的答案在你看來是否正確(它似乎正常工作)? – danielv

+0

也比較http://stackoverflow.com/questions/39048008/call-a-method-once-only-for-the-lifetime-of-the-object-in-swift。 –

回答

3

此引用的例子遷移指南是誤導,因爲它涉及到一個全局變量。

關閉實例let當初始化類時立即調用(一次)常量。這就是爲什麼它不能使用同一級別聲明的其他變量的原因。

你可以做的是初始化initialize(變量名不是最好的;-))懶惰。關閉也被稱爲只有一次,但 - 如指導描述 - 只有第一次(當)它使用

class SomeClass { 
    let other = SomeOtherClass() 

    lazy var initialize :() = { 
    let test = self.other 
    test.doSomething() 
    }() 

    func doSomething() { 
    // initialize will only be called once 
    _ = initialize 
    } 
} 
+1

您認爲Apple的遷移指南中有什麼錯誤?它告訴你可以使用*「懶惰初始化全局變量或靜態屬性」*代替dispatch_once。在問題中的*實例屬性*既不是一個懶惰初始化的全局屬性,也不是一個靜態屬性。 - 爲此目的使用dispatch_once總是錯誤的,因此「遷移」不適用。另請參閱我對這個問題的評論。 –

+0

@MartinR這個特殊的語法是錯誤的。 '_ = myGlobal'這一行表明'let myGlobal'閉包是懶惰地初始化的。實際上這條線對*變量*根本不需要。 – vadian

+1

遷移指南是關於一個*全局變量*'myGlobal'來爲每個應用程序運行時執行一次代碼*,並且它不能在這裏應用。就我所知,根據您的聲明,遷移指南中沒有錯誤。 –

1

創建'SomeClass'類的實例時,它將首先創建該實例上的所有變量和常量。在此期間,自己可能沒有完全初始化,因爲它可能在設置的一半。因此,直到初始化步驟完成之後,自我纔可用。

在這個例子中,他們談論的是一個沒有自我概念的全局變量,或者是一個沒有自我概念的靜態常量。

如果它需要一個實例方法/變量,您可以:

一)使它成爲一個懶惰的VAR像

lazy var initialise :()->Void = { 
    return { 
     // can access self here 
    }  
}() 

將要創建的第一次調用它,而不是在初始化。當然,你會以這種方式失去常量,因爲你只執行一次,所以你必須存儲浪費的閉包。

二)把代碼的init方法裏面:

init() { 
    // if your class doesn't have a super class, you can access self.other here. 
    // If it does have a super class (like NSObject) you must first call super.init() here to complete the initialisation. 
    // This can only be done after all other variables have been set. 
}