讀古今文學網 > iOS編程基礎:Swift、Xcode和Cocoa入門指南 > 1.14 隱私 >

1.14 隱私

我之前曾說過,命名空間本身並非訪問內部名字的不可逾越的屏障。不過如果你願意,它還是可以作為屏障的。比如,並非存儲在實例中的所有數據都需要修改,甚至要對其他實例可見。並非每一個實例方法都可以被其他實例調用。任何優秀的基於對象的編程語言都需要通過一種方式確保其對像成員的隱私性——如果不希望其他對像看到這些成員,那麼可以通過這種方式做到這一點。

比如:


class Dog {
    var name = ""
    var whatADogSays = "woof"
    func bark {
        print(self.whatADogSays)
    }
    func speak {
        print(self.whatADogSays)
    }
}  

對於上述代碼來說,其他對象可以修改屬性whatADogSays。由於該屬性由bark與speak使用,因此最後可能出現的結果就是,我們讓一隻Dog吼叫,但它卻發出「貓叫聲」。這顯然不是我們想要的:


let dog1 = Dog
dog1.whatADogSays = "meow"
dog1.bark // meow  

你可能會說:真夠笨的了,為何要使用var聲明whatADogSays呢?使用let聲明不就行了,讓它成為常量。現在就沒人能夠修改它了:


class Dog {
    var name = ""
    let whatADogSays = "woof"
    func bark {
        print(self.whatADogSays)
    }
    func speak {
        print(self.whatADogSays)
    }
}  

這個答案還不錯,但並不是最好的答案。它有兩個問題。假設我希望Dog實例本身能夠修改self.whatADogSays,那麼whatADogSays就必須得是var了;否則,即便實例本身也無法修改它。此外,假設我不希望其他對像知道這只Dog吼的是什麼,除非調用bark或是speak才可以。即便使用let聲明,其他對像依然還是可以讀取到whatADogSays的值。我可不想這樣。

為了解決這個問題,Swift提供了關鍵字private。稍後將會介紹這個關鍵字的全部含義,不過現在只要知道它可以解決問題就行了:


class Dog {
    var name = ""
    private var whatADogSays = "woof"
    func bark {
        print(self.whatADogSays)
    }
    func speak {
        print(self.whatADogSays)
    }
}  

現在,name是個公有屬性,但whatADogSays卻是個私有屬性:其他對象是看不到它的。一個Dog實例可以使用self.whatADogSays,但引用Dog實例的不同對像(如dog1)就無法使用dog1.whatADogSays。

這裡要說明的重要的一點是,對像成員默認是公有的,如果需要訪問隱私信息,那就需要請求。類聲明定義了一個命名空間;該命名空間要求其他對像通過額外的點符號來引用命名空間內部的事物,不過其他對像依然可以引用命名空間內部的事物;命名空間本身並不會對可見性形成屏障,而private關鍵字則形成了這道屏障。