首页 » iOS编程基础:Swift、Xcode和Cocoa入门指南 » iOS编程基础:Swift、Xcode和Cocoa入门指南全文在线阅读

《iOS编程基础:Swift、Xcode和Cocoa入门指南》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获取来做到的;现在,源视图控制器就可以让自身成为目标视图控制器的委托,并向其传递任何必要的信息,如此种种。