iOS编程中常用的设计模式 Objective C中的文件归档 iOS用户界面 iOS编程中常用的设计模式 内容概述 MVC Target-Action 代理 17.1 MVC 模型-视图-控制器(Model-View-Controller,MVC)是Xerox PARC在20世纪80年代为编程语言Smalltalk-80发明的一种软件设计模式,至今已广泛应用于用户交互应用程序中。每个MVC应用程序都包含Model、View和Controller三部分。 Model部分内容是程序的业务逻辑或数据逻辑是程序的"大脑",View顾名思义就是视图,即用户界面是和用户交互的部分,而Controller是控制器,是将模型内容格式化为视图需要格式。 下图展示了MVC设计模式几个部分的关系。从下图中,我们可以看出控制器在MVC中起到非常重要的作用,它负责视图与模型相互间的交互。当视图上有了某些操作,会通过控制器反应至模型中。如果模型中的数据有所改变或者更新,则会通过控制器,对视图进行相关界面改变。视图与模型是永远都不直接进行通信的。 在iOS程序开发中,所有的控件、窗口等都继承自 UIView,对应MVC中的V。UIView及其子类主要负责UI的实现,而UIView所产生的事件都可以采用委托的方式,交给UIViewController实现。对于不同的UIView,有相应的UIViewController,对应MVC中的C。例如在iOS上常用的UITableView,它所对应的Controller就是UITableViewController。至于MVC中的M,就需要用户根据自己的需求来实现了。 iOS的SDK中已经为我们提供了许多视图组件:例如:UIView,UIViewController。这也方便开发者进行开发。同时,也对数据模型中可能使用到的一些组件进行了封装:数据库、CoreData等,这有利于开发者迅速的建立一个基于MVC设计模式的程序。下面我们通过一个计算器的案例来演示MVC设计模式在iOS中的应用。实现步骤如下: 创建一个项目,在项目中添加一个Model类,该类是程序大大脑,负责程序的计算。 @interface CalculatorModel : NSObject // 计算结果 @property(nonatomic)double result; // 计算方法 -(double)calculate:(double)num andOperator:(NSString*)ope; @end #import "CalculatorModel.h" @implementation CalculatorModel // 实现计算方法 -(double)calculate:(double)num andOperator:(NSString *)ope{ // 根据操作法进行计算 if ([ope isEqualToString:@"+"]) { self.result+=num; } if ([ope isEqualToString:@"-"]) { self.result-=num; } if ([ope isEqualToString:@"*"]) { self.result*=num; } if ([ope isEqualToString:@"/"]) { self.result/=num; } // 返回计算结果 return self.result; } @end 在界面上添加数字按钮和操作符按钮,以及显示计算结果标签,如下图所示,该部分就是MVC中的View部分。 实现Controller部分,在Controller的.h中,引用Model部分,添加显示结果的标签属性和操作符属性,添加数字按钮被按下、操作符被按下、结果按钮被按下、清除按钮被按下方法。 #import <UIKit/UIKit.h> #import "CalculatorModel.h" @interface AmakerViewController : UIViewController // 引用Model部分 @property(nonatomic,strong)CalculatorModel *model; // 结果标签 @property(nonatomic,strong)IBOutlet UILabel *resultLabel; // 操作符 @property(nonatomic,strong)NSString *currentOperator; // 数字按钮被按下 -(IBAction)digitPress:(id)sender; // 操作符被按下 -(IBAction)operatorPress:(id)sender; // 结果按钮被按下 -(IBAction)resultPress:(id)sender; // 清除按钮被按下 -(IBAction)cleanPress:(id)sender; @end 在Controller的实现类中实现上述计算方法。 // 数字按钮被按下的实现 -(IBAction)digitPress:(id)sender{ UIButton *btn = (UIButton*)sender; // 获得当前被按下按钮数字 double num = [btn.titleLabel.text doubleValue]; // 如果第一次按下数字 if (self.currentOperator==nil) { self.model.result = num; } // 计算结果 [self.model calculate:num andOperator:self.currentOperator]; } // 操作符被按下的实现 -(IBAction)operatorPress:(id)sender{ UIButton *btn = (UIButton*)sender; // 获得当前被按下的操作符 self.currentOperator = btn.titleLabel.text; } // 结果按钮被按下 -(IBAction)resultPress:(id)sender{ self.resultLabel.text = [NSString stringWithFormat:@"%f",self.model.result]; } // 清除按钮被按下 -(IBAction)cleanPress:(id)sender{ // 归零 self.resultLabel.text = @"0.0"; self.model.result = 0.0; self.currentOperator = nil; } 运行程序结果如下所示。 17.2 Target-Action Target-Action设计模式贯穿iOS开发始终,但是对于初学者,这种模式还是被搞得一头雾水。其实Target-Action模式很简单,就是当某个事件发生时,调用那个对象中的那个方法,例如,当按钮被单击时,调用Controller里面的change方法。这里描述的"那个对象"就是Target,"那个方法"就是Action。也就是Controller是Target,change方法是Action。一般Target都是Controller,而Action有固定的格式:-(IBAction)click:(id)sender。 下面我们就通过案例的方式来演示Target-Action模式的用法。本案例在界面上添加一个按钮,当按钮被单击时调用Controller中定义的一个方法,该方法弹出一个对话框。实现步骤如下: 创建一个项目,在viewDidLoad方法中,通过代码的方式创建一个按钮。 - (void)viewDidLoad { [super viewDidLoad]; // 实例化按钮 UIButton *btn = [UIButton buttonWithType:UIButtonTypeRoundedRect]; // 设置按钮大小 btn.frame = CGRectMake(20, 20, 200, 50); // 设置按钮标题 [btn setTitle:@"点击我..." forState: UIControlStateNormal]; // 将按钮添加到View [self.view addSubview:btn]; } 在控制器的.h文件中添加一个事件方法,并在.m文件中实现它。 // 按钮点击事件 -(IBAction)click:(id)sender; -(IBAction)click:(id)sender{ // 显示对话框 UIAlertView *alert = [[UIAlertView alloc]initWithTitle:nil message:@"测试Target-Action设计模式" delegate:self cancelButtonTitle:@"OK" otherButtonTitles:nil, nil]; [alert show]; } 使用Target-Action设计模式,使用的当按钮被按下时,调用Controller的click方法。在iOS SDK中有一个UIControl类,该类中定义了一个- (void)addTarget:(id)target action:(SEL)action forControlEvents:(UIControlEvents)controlEvents方法,大部分视图类都继承了UIControl类,所有可以使用该方法实现Target-Action设计模式。在iOS中这种设计模式被称作一个对象给另外一个对象发送消息。 // 使用Target-Action设计模式,在两个对象直接发送消息 // 1.self是指当前对象即AmakerViewController // 2. action即click方法 // 3. 何时调用UIControlEventTouchUpInside,即单击 [btn addTarget:self action:@selector(click:) forControlEvents:UIControlEventTouchUpInside]; 程序运行结果如下所示。 17.2 代理 使用代理设计模式的目的是,减少程序中使用更多的继承关系。在iOS开发中除了上述的MVC和Target-Action设计模式外,代理是第三个最常用的设计模式。在iOS中代理是通过协议来实现的。 在第8章我们讲述协议中讲述了一个案例,这里我们再来回顾一下,深入认识一下代理的用法。 下面通过一个现实生活中的例子,来理解代理。在IBM笔记本风靡的年代,全世界有大量的IBM代理商为IBM代理销售笔记本电脑。这个例子可以很好的理解代理设计模式。该案例的实现步骤如下: 创建一个IBM代理类,IBMDelegate,并添加一个销售方法sale。 @protocol IBMDelegate <NSObject> // 销售电脑 -(void)sale; @end 创建一个IBM类,该类实现IBMDelegate协议,并添加该协议属性。 // 实现代理协议 @interface IBM : NSObject<IBMDelegate> // 生产电脑方法 -(void)produce; // 代理属性 @property(nonatomic,strong)id<IBMDelegate> delegate; @end 实现IBM类,在初始化方法中指定代理,并实现produce和sale。 @implementation IBM // 初始化方法 - (id)init { self = [super init]; if (self) { // 指定代理 self.delegate = self; } return self; } // 生产电脑方法 -(void)produce{ NSLog(@"生产电脑..."); } // 销售电脑 -(void)sale{ NSLog(@"销售电脑..."); } 在main方法中测试。 #import <Foundation/Foundation.h> #import "IBM.h" int main(int argc, const char * argv[]) { @autoreleasepool { // 实例化 IBM *ibm = [[IBM alloc]init]; // 生产方法 [ibm produce]; // ibm的代理的sale方法 [ibm.delegate sale]; } return 0; } 上述代理模式就实现了IBM生产电脑,IBM代理来销售电脑的代码分离。降低了程序的耦合性。 Objective C中的文件归档 iOS用户界面