有些对象是全局可见的,也就是说,它们对所有对象都是可见的。对象类型本身就是个很好的例子。正如我在第4章所指出的那样,我们可以在使用Swift结构体的同时通过静态成员来提供全局可用的命名空间约束(见4.3.2节)。
有时,类会通过类方法来提供单例。这些单例反过来又提供了指向其他对象的属性,这使得其他对象也变成全局可见的了。比如,任何对象都可以通过调用UIApplication.sharedApplication()看到单例的UIApplication实例。这样,任何对象也都可以看到应用的主窗口,因为它是单例UIApplication实例的keyWindow属性;任何对象也都可以看到应用委托,因为它是其delegate属性。这个链条还会继续:任何对象都可以看到应用的根视图控制器,因为它是主窗口的rootViewController;正如13.2节所述,我们可以从这里导航视图控制器与视图层次体系。
你也可以通过将自己的对象附加到全局可见对象上使其全局可见。比如,你可以自由创建的应用委托的公共属性就是全局可见的,这是因为应用委托是全局可见的(因为共享应用是全局可见的)。
另一个全局可见对象是调用NSUserDefaults.standardUserDefaults()所返回的共享默认对象。该对象是个网关,用于存储和获取用户默认值,它像是一个字典(一个值的集合,根据键来获取)。当应用终止时,用户默认值会自动保存;当应用再次启动时,它们又会自动恢复。因此,这是应用在两次启动之间维护信息的一种方式。不过,由于是全局可见的,因此它们还是应用中通信的一种媒介。
比如,在我开发的一个应用中有一个名为HazyStripy的设置。它决定了某个可见的界面对象(游戏中的一张纸牌)是模糊的还是条纹的。用户可以修改这个设置,因此会有一个首选项界面让用户修改。当用户打开这个首选项界面时,我会在用户默认值中检查HazyStripy设置,配置这个界面以在分割控件中反映出来(叫作self.hazyStripy)。
func setHazyStripy { let hs = NSUserDefaults.standardUserDefaults .objectForKey(Default.HazyStripy) as! Int self.hazyStripy.selectedSegmentIndex = hs}
相反,如果用户操作了首选项界面,轻拍hazyStripy分割控件来修改其设置,那么我会通过修改用户默认值中实际的HazyStripy设置来作出响应:
@IBAction func hazyStripyChange(sender:AnyObject) { let hs = self.hazyStripy.selectedSegmentIndex NSUserDefaults.standardUserDefaults.setObject( hs, forKey: Default.HazyStripy)}
这里还有一个地方很有意思。首选项界面并非唯一一个使用用户默认值中HazyStripy设置的地方;实际绘制模糊或条纹卡片的绘制代码也会用到它,这样才能知道卡片该如何绘制自身!当用户关闭首选项界面,纸牌游戏重新出现时,纸牌会被重新绘制,它会查询NSUserDefaults中的HazyStripy设置。
override func drawRect(rect: CGRect) { let hazy : Bool = NSUserDefaults.standardUserDefaults .integerForKey(Default.HazyStripy) == HazyStripy.Hazy.rawValue CardPainter.sharedPainter.drawCard(self.card, hazy:hazy)}
这样,纸牌对象与管理首选项界面的视图控制器对象就没必要看到彼此了,因为它们都能看到这个共同的对象,即HazyStripy用户默认值。NSUserDefaults本质上会成为一个全局的媒介,用于实现应用中不同部分之间信息的通信。