用子类搞定不同的设备
因为要判断我们的程序正运行在哪个设备上,所以,我们的代码有些混乱了,IF来ELSE去的,记住,将来你花在维护代码上的时间要比花在写代码上的时间多,如果你的项目比较大,且IF语句分布得到处都是,那么可以悲催地告诉你,你将在跟踪iPad或iPhone的功能上面花更多的时间,更大的精力。
在下面的建议中,我们不是针对iPad,而是要建立一种用传统的包装技巧来提取类、封装方法的思路和习惯,这样不但会减少那些个啰哩啰嗦的条件判断,还能使代码结构更加清晰。
例如,一个更加明智的方法就是把你的类分成三个不同的类别,把那些两个设备共用的代码放在共享类别中,把iPhone相关的代码放在iPhone类别中,把iPad相关的代码放在iPad类别中,在本节结束的时候,我们的源代码结构将变成下图这样:
首先考虑RootViewController,这其中,我们只修改了表视图代理的tableView:didSelectRowAtIndexPath:方法的实现,以让它是适应于不同的设备,现在,我们就从RootViewController类中干掉它,然后创建两个子类实现它。
创建一个RootViewController的子类,起名为RootViewController_Pad,头文件里面几乎没啥东西:
实现起来也很简单,在这里面我们将针对iPad实现代理方法,如果喜欢偷懒,就从RootViewController.m中把iPad对应的代码复制、粘贴过来:
接着,我们用类似的方法针对iPhone创建RootViewController_Phone子类,不用说,该子类的爸爸也是RootViewController类。
自然,其中代理方法实现的是iPhone功能,我们继续发扬复制、粘贴的精神,从RootViewContoller.m的tableView:didSelectRowAtIndexPath:方法中摘出iPhone对应的代码:
通过子类化RootViewController,我们没费多大劲就把iPad、iPhone的功能分离开来,从RootViewController.m中删除tableView:didSelectRowAtIndexPath:方法。如此,超类中包含了所有表视图的数据源方法,而针对具体设备的功能方法,都被放在了子类中,从而实现了数据与功能的分离。
不过,事儿还没有干完,程序还不知道这些子类的存在,我们还要把应用代理切成iPad份和iPhone份,并让他们分别调用相应的子类。
2.5 把应用代理分开
为了调用上面的子类,我们还要做一些改动,那就是针对不同的平台创建不同的应用代理,在超类DailyShootAppDegelate中保留这些设备共用的代码,其头文件如下:
在实现文件中,干掉那些判断目标设备的代码,稍后,我们将添加子类的初始视图,DailyShootAppDegelate.m的内容如下:
创建一个DailyShootDegelate_Phone类,其头文件内容如下:
对于iPhone,我们要添加导航控制器的视图,一添加进来它就会在最上面显示,然后,还要调用超类的application:didFinishLaunchingWithOptions方法:
类似的,再创建DailyShootAppDegelate_Pad类,其头文件内容如下:
在这个子类中,需要添加一个分割视图控制器(UISplitViewController)属性,在实现中,我们将把分割视图控制器的视图作为顶部视图添加进来,并在dealloc方法中释放资源:
到现在,工作基本完成,不过先别着急,我们还需要对nib文件做少许修改。在IB中打开MainWindow.nib,用实体查看器把DailyShootAppDegelate对象的类型改为DailyShootAppDegelate_Phone,把RootViewController对象的类型改为RootViewController_Phone。
类似的,在IB中打开MainWindow_iPad.nib,用实体查看器把DailyShootAppDegelate对象的类型改为DailyShootAppDegelage_Pad,把RootViewController对象的类型改为RootViewController_Pad。
保存所有成果,生成并运行,所有的东西将如以往那般运行。
为了替换两个简单的if语句我们就做了这么多事情,是不是感觉很磨叽?但是,凡事要朝好的方向想,你的代码是不是变得清晰灵活了?其实,你也许感觉做这些修改也没有费多少时间,但是,这么做确实很重要。
2.6 在详细视图中添加一个工具条
下一步,让我们在iPad中被AssignmentViewController管理的详细视图的顶部添加一个工具条,竖着使用iPad时,为了隐藏和显示导航视图,我们的确需要一个工具栏放置“导航”按钮;即使在横屏下,留着它也挺好,因为,有时候隐藏掉导航视图会使界面更清晰。iPhone版本的界面已经有个导航条,所以不用理会它。
我们要创建一个iPad版的AssignmentViewController,选择“iPad组”,创建新文件,该文件是UIViewController的子类,记着选中“针对iPad”、“创建XIB”两个复选框,且将新类命名为AssignmentViewController_Pad。
给AssignmentViewController_Pad类添加名为toolbar的公共属性,其类型为UIToolbar,把超类从通用的UIViewController改为AssignmentViewController。
打开AssignmentViewController_Pad nib,在视图的顶部放一个UIToolbar,剩下的部分用UIWebView填充,把工具条上的默认按钮干掉,待会我们创建自己的按钮。在UIWebView对象的属性查看器中,把“Scales Pages”的值设置为“Fit”,从“Files’Owner”中把两个外部接口与这些元素相连,保存。
现在,在AssignmentViewController_Pad类的实现文件中就没有多少事情要做了:
下面,我们要对MainWindow_iPad.nib做一些调整,用实体查看器把AssignmentViewController对象的类型改为AssignmentViewController_Pad,接着,还要用属性查看器把NIB名称改为AssignmentViewController_Pad,别忘了保存。
好了,运行运行,看看工具条是不是出来了,下面我们将在分割视图(横屏)和悬浮窗体(竖屏)中使用工具条。