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中起到非常重要的作用,它负责视图与模型相互间的交互。当视图上有了某些操作,会通过控制器反应至模型中。如果模型中的数据有所改变或者更新,则会通过控制器,对视图进行相关界面改变。视图与模型是永远都不直接进行通信的。

图17.1 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中的应用。实现步骤如下:

  1. 创建一个项目,在项目中添加一个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
  1. 在界面上添加数字按钮和操作符按钮,以及显示计算结果标签,如下图所示,该部分就是MVC中的View部分。

图 17.2 计算器View部分

  1. 实现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
  1. 在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;

}
  1. 运行程序结果如下所示。

图17.3 计算器运行结果

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中定义的一个方法,该方法弹出一个对话框。实现步骤如下:

  1. 创建一个项目,在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];

}
  1. 在控制器的.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];

}
  1. 使用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];
  1. 程序运行结果如下所示。

图17.4  Target-Action设计模式

17.2 代理

使用代理设计模式的目的是,减少程序中使用更多的继承关系。在iOS开发中除了上述的MVC和Target-Action设计模式外,代理是第三个最常用的设计模式。在iOS中代理是通过协议来实现的。

在第8章我们讲述协议中讲述了一个案例,这里我们再来回顾一下,深入认识一下代理的用法。

下面通过一个现实生活中的例子,来理解代理。在IBM笔记本风靡的年代,全世界有大量的IBM代理商为IBM代理销售笔记本电脑。这个例子可以很好的理解代理设计模式。该案例的实现步骤如下:

  1. 创建一个IBM代理类,IBMDelegate,并添加一个销售方法sale。
@protocol IBMDelegate <NSObject>

// 销售电脑

-(void)sale;

@end
  1. 创建一个IBM类,该类实现IBMDelegate协议,并添加该协议属性。
// 实现代理协议

@interface IBM : NSObject<IBMDelegate>

// 生产电脑方法

-(void)produce;

// 代理属性

@property(nonatomic,strong)id<IBMDelegate> delegate;

@end
  1. 实现IBM类,在初始化方法中指定代理,并实现produce和sale。
@implementation IBM

// 初始化方法

- (id)init

{

    self = [super init];

    if (self) {

        // 指定代理

        self.delegate = self;

    }

    return self;

}

// 生产电脑方法

-(void)produce{

    NSLog(@"生产电脑...");

}

// 销售电脑

-(void)sale{

    NSLog(@"销售电脑...");

}
  1. 在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代理来销售电脑的代码分离。降低了程序的耦合性。