讀古今文學網 > iOS編程基礎:Swift、Xcode和Cocoa入門指南 > 13.1 實例化可見性 >

13.1 實例化可見性

每一個實例都有自己的來源,並且根據需要創建出來:某個對象會發送一條消息,命令創建出一個實例。因此,命令對像在這個時刻就會擁有一個指向該實例的引用。當Manny創建Jack時,Manny就會擁有對Jack的引用。

這個簡單的事實可作為建立未來通信機制的出發點。如果Manny創建了Jack並且知道未來他需要一個對Jack的引用,那麼Manny就可以將創建Jack所返回的引用保存起來。如果Manny知道Jack在未來需要一個對Manny的引用,那麼Manny就可以在創建Jack後立刻向其提供引用,Jack會將該引用保存起來。

委託就是這樣一種情況。Manny可能會在創建完Jack後立刻將自身作為Jack的委託,如下面這個來自於第11章的示例代碼所示:


let cpc = ColorPickerController(colorName:colorName, andColor:c)
cpc.delegate = self
  

事實上,如果這很重要,那麼你應該為Jack聲明一個初始化器,這樣Manny就可以在創建Jack後向其傳遞一個對自身的引用,從而防止任何失誤的發生。看看UIBarButtonItem所採取的方式,它有3個不同的初始化器,比如,init(title:style:

target:action:),它們都需要一個target參數,表示UIBarButtonItem發送消息的目標。

當Manny創建Jack時,Jack需要的可能不是對Manny自身的引用,而是需要Manny知道或擁有的某個引用。你可以向Jack提供一個方法,這樣Manny就可以將該信息提供給Jack了;另外,如果沒有這個信息Jack將不復存在,那麼將該方法作為Jack的初始化器也是合情合理的。

回憶一下第11章的這個示例。它來自於一個表視圖控制器。用戶輕拍了表中的一行。我們又創建了一個表視圖控制器TracksViewController實例,並將其所需要的數據傳遞給它,然後展現出這個表視圖。我故意讓TracksViewController擁有一個指定初始化器init(mediaItemCollection:),這樣TracksViewController在創建出來到獲取所需數據之間就必須使用它:


override func tableView(tableView: UITableView,
    didSelectRowAtIndexPath indexPath: NSIndexPath) {
        delay(0.1) { // let spinner start spinning
            let t = TracksViewController(
                mediaItemCollection: self.albums[indexPath.row])
            self.navigationController!.pushViewController(
                t, animated: true)
         }
}
  

在該示例中,self並沒有保持對新創建的TracksViewController實例的引用,TracksViewController也不需要對self的引用。不過,self創建了TracksViewController實例,並且在短暫的時刻內擁有對其的引用。因此,self利用這個時刻向TracksView-Controller實例傳遞了它所需的數據,這是個絕佳的時刻。知道這個時刻,並且充分利用它,這是數據通信的關鍵所在。

Nib加載也是一樣的。Nib加載是一種從nib中實例化對象的方式。我們需要精心準備以確保存在著對這些對象的引用,這樣它們就不會消失不見了(見12.9節)。Nib加載時刻也是nib所有者或加載nib的代碼與這些對像產生聯繫的時刻;它會充分利用這個時刻來確保引用的安全性。

初學者常感到困惑的是,如果兩個對像從不同的nib中加載(從不同的.xib文件中或故事板中的不同場景中),那麼它們是如何獲得彼此的引用的。令人沮喪的是,你不能在nib A中的對象與nib B中的對象間繪製連接;更有甚者,你可能看到同一個故事板中的兩個對象就在那兒,但卻無法連接它們。不過,如前所述(見7.3.11節),這種連接是毫無意義的,這也是不能將其連接起來的原因所在。它們是不同的nib,會在不同的時間加載。不過,當nib A加載時,某個對象(Manny)會成為所有者;當nib B加載時,會有另外的對象(Jack)成為所有者。也許它們(Manny與Jack)會看到彼此,在這種情況下,指定好所有必要的插座變量後,問題就會得以解決。也許還有第3個對象(Moe)能夠看到Manny與Jack,並為其提供通信路徑。

比如,當故事板中的Segue被觸發時,該Segue的目標視圖控制器就會被實例化,並且這個Segue會持有一個對其的引用。同時,這個Segue的源視圖控制器已經存在了,它也會持有一個對其的引用。這樣,該Segue就可以向源視圖控制器發送prepareForSegue:sender:消息,其中包含了對自身(Segue)的引用。這個Segue就是Moe;它會將Manny(源視圖控制器)與Jack(目標視圖控制器)連接起來。這樣,源視圖控制器(Manny)就可以獲得對新實例化的目標視圖控制器(對Jack的引用)的引用,這是通過讓Segue獲取來做到的;現在,源視圖控制器就可以讓自身成為目標視圖控制器的委託,並向其傳遞任何必要的信息,如此種種。