这课主要是以一个计算器一个用为例子,教你怎么使用XCode,如何使用MVC设计模式创建应用。
(1)新建一个single view application模版的应用
打开xcode并点击“创建一个新xcode项目”,进入项目创建界面,这个界面让我们为应用选择一个模板。接着选择“single view application”模板,单击next按钮,进入项目详细信息界面。
其中Company Identifier用来标志你的应用,要是唯一的,不要有冲突。class prefix通常与应用的名字一样。这个use storyboard是ios5新特性,它允许把所有的view同时放到屏幕上,所以能看到它们之间的互动。storyboard能让你在屏幕上看到MVC群的结构图,看到MVC之间的关系。
接着单击next按钮,进入选择保存项目目录界面,选择好后单击create按钮,就创建好了项目。
MainStoryboard.storyboard是我们MVC的view,所有MVC的所有view都在这里。在我们的例子里,storyboard会包含所有controller的view。系统不会自动创建model,因为系统不知道它是什么。
接下来构建计算器,需要一些控件如按钮、文本框、显示区域。这可以通过单击右上角utilities按钮实现,它会弹出一个区域:上部分叫inspector,用来显示所选内容的更多信息;下半部分可以认为是一个向导,绘制view的向导,我们需要这个向导,因为我们需要对象库。
还记得之前的那个MVC图吗?controller有个绿色箭头能够向view发话。
controller肯定需要和view对话,告诉它显示内容、计算结果、输入内容,所以要在controller中创建一个outlet到veiw里。实现这点不用打代码,只需按住键盘control键,从显示上拖出一条线到代码上即可。label已经有个strong指针了,因为父窗口view已经有了strong指针指向它,所以label只需weak指针。IBOutlet这个类型没有具体内容,只是xcode用来跟踪哪个property是outlet的。controller已经准备好向label发话了,synthesize已经生成setter和getter,那什么时候调用呢?setter用来设置指针,当storyboard被读取画面出现在屏幕上时,ios就会调用setter去创建连接到outlet,当想要和label对话时就去调用getter。回到对象库拖出round rect button到显示界面上,现在要考虑controller和veiw的另一个连接,target action。所以controller要有一个target来接收键盘按钮发送的action(用户按下按钮),操作只需按住control将按钮拖出到h文件,IBAction实际上就是void,用ibaction是要让xcode知道这是个action。这个target action就是当按钮被按,它就发消息给controller,消息附带参数,这个参数就是发送者自己,这里就是按钮。复制粘贴按钮,也会复制它的target actin,所以按钮都会发送一样的target action。
以下是CalculatorViewController.h文件的代码:
#import <UIKit/UIKit.h>@interface CalculatorViewController : UIViewController {UILabel *display; }@property (strong, nonatomic) IBOutlet UILabel *display; - (IBAction)digitPressed:(id)sender; - (IBAction)operationPressed:(id)sender; - (IBAction)enterPressed;@end
CalculatorViewController.m文件的代码:
#import "CalculatorViewController.h"#import "CalculatorBrain.h"@interface CalculatorViewController ()@property (nonatomic) BOOL userIsIntheMiddleOfEnterNumber; @property (nonatomic, strong) CalculatorBrain *brain;@end@implementation CalculatorViewController@synthesize display = _display; @synthesize userIsIntheMiddleOfEnterNumber = _userIsIntheMiddleOfEnterNumber; @synthesize brain = _brain;-(CalculatorBrain *)brain{if (!_brain) {_brain = [[CalculatorBrain alloc] init];}return _brain; }- (IBAction)digitPressed:(UIButton *)sender {NSString *digit = [sender currentTitle];if (self.userIsIntheMiddleOfEnterNumber) {self.display.text = [self.display.text stringByAppendingString:digit];} else {self.display.text = digit;self.userIsIntheMiddleOfEnterNumber = YES;} }- (IBAction)operationPressed:(UIButton *)sender {if (self.userIsIntheMiddleOfEnterNumber) {[self enterPressed];}double result = [self.brain performOperation:[sender currentTitle]];NSString *resultString = [NSString stringWithFormat:@"%g",result];self.display.text = resultString; }- (IBAction)enterPressed {[self.brain pushOperand:[self.display.text doubleValue]];self.userIsIntheMiddleOfEnterNumber = NO; } @end
现在需要建个model,我们已经有了controller和view还要有model。单击菜单里File—NEW—NEW File创建文件,选择objective-c class,单击next,取名为CalculatorBrain保存位置与其它文件一样。
需要一个栈来保持操作数、入栈运算、出栈运算等。怎么去实现一个栈?一个很简单的办法是使用数组。我们需要private接口,因为这个栈不是公共的,入栈出栈操作全在model里进行。当property创建的时候值是0或nil,那么向nil发送消息就什么也不会发生,因此需要一个构造函数来设置它,只需要在getter方法里判断实体变量是否为空,如果为空就为它分配一个数组,同时也只分配一次,这叫延迟实例化。synthesize不会自动分配内存空间,synthesize只有一个变量指针,需要自己来分配空间。
以下是CalculatorBrain.h文件的代码:
#import <Foundation/Foundation.h>@interface CalculatorBrain : NSObject-(void)pushOperand:(double)operand; -(double)performOperation:(NSString *)operation;@end
CalculatorBrain.m文件的代码如下:
#import "CalculatorBrain.h"@interface CalculatorBrain()@property (nonatomic, strong) NSMutableArray *operandStack;@end@implementation CalculatorBrain@synthesize operandStack = _operandStack;-(NSMutableArray *)operandStack{if (_operandStack == nil) {_operandStack = [[NSMutableArray alloc] init];}return _operandStack; }-(void)pushOperand:(double)operand{NSNumber *operandObject = [NSNumber numberWithDouble:operand];[self.operandStack addObject:operandObject]; }-(double)popOperand{NSNumber *operandObject = [self.operandStack lastObject];if (operandObject != nil) {[self.operandStack removeLastObject];}return [operandObject doubleValue]; }-(double)performOperation:(NSString *)operation{double result = 0;if ([operation isEqualToString:@"+"]) {result = [self popOperand] + [self popOperand];}else if([operation isEqualToString:@"*"]){result = [self popOperand] * [self popOperand];}return result; }@end