就iOS而言 MVC无处不在 是基础 是核心
可以说它是设计模式 但更多的说是框架
这两天认真研究了一下MVC设计模式,在iOS开发中这个算是重点中的重点了,如果对MVC模式不理解或者说不会用,那么你iOS肯定学不好,或者写不出好的东西,当然本人目前也在学习中,不过既然能看到这篇文档,说明你已经开始着手学习并且想深入研究它了,个人也是研究很久才搞懂,就写下来希望对各位有用,也能方便自己以后开发中查看,好了废话不多说,下面就来详细介绍一下MVC,并且用实例验证一下在项目开发中怎么去使用它。
相信你对 MVC 设计模式 并不陌生,只是不能完全理解其中的含义或者不能很好的使用它。
从字面意思来理解, Modal , View , Controller ,其用意在于将数据与视图分离开来------解藕。
在iOS cocoa touch 编程中, MVC机制被发挥得淋漓尽致。 MVC 示意图如下。 只有充分理解了MVC,才能在编写出优雅的iOS app。为充分理解 MVC, 相关的概念(比如: Delegate、 Protocol、 Notification 等)也要了然于胸。
MVC 约定, Model 不允许与View 打交道。 Model 是管理数据的, 当Model中的数据发生变化时,与之对应的视图应更新。 这就需要一种机制来支持。为此 iOS 框架提供了两种支持机制: Notification 和KVO (Key-Value Observing)。
KVO 可简单理解为,为你所关注的 Key 对象注册一个监听器。 当有数据发生变化时,就会发出广播给所有的监听器。
MVC 也约定, View 不允许直接引用Modal, 它只能被Controller 所控制。 Controller 控制 View 显示什么数据。我们知道,View 所要显示的数据是来源于 Modal, View 上产生的事件 ( 比如 Touch事件)需要通知 Controller。 既然MVC 不允许直接打交道,就需要提供一种机制。
不错, iOS 确实提供了一种机制, 名曰: Delegate。 Delegate 这个词, 有人将它译为“委托”,也有人将它译为“代理”。名称上的差异没有什么,重要的是如何理解 Delegate。 Delegate设计模式的引入,就是为了解决UIView与Controller松耦合互动问题。
为便于理解, 这里截取一张来iOS MVC 示意图:
我们在详细介绍下这张图的内涵:
1. 图中,绿色的箭头表示直接引用。 对View 的直接引用体现在 IBOutlet 上。 当引用一个View 时,比如Button。 需要在ViewController
中声明一个 IBOutlet UIButton * btn;
2. 然后,我们看View 是怎么向 Controller 通信的。对于这个, iOS 有三种常见的模式:
设置View对应的Action Target。如设置UIButton的Touch up inside的Action Target。
设置View的Delegate,如UIAlertViewDelegate, UIActionSheetDelegate,UITextFieldDelegate等。
设置View的data source, 如UITableViewDataSource。
通过以上三种模式,View既能向Controller通信,又无需知道具体的Controller是谁,这样,View 就与Controller解耦了。
除此之外, iOS 还提供了 Action-Target 模式来让Controller 监听View 触发的事件。 View 又是如何获取数据呢? iOS提供了 Data source 的概念,其实也就是Protocol 的应用。
综上所述, 正是在iOS MVC框架的驱使下, 才需要深入理解 Delegate、Protocol等概念。
下面来看看代码中是怎么实现的,
说到MVC我们一开始都是先从Model开始,然后再编写对应的View最后在控制器中做相应的控制
一:Model
1:首先我们先创建一个模型类,用于实现模型数据的读取
头文件中创建两个模型属性,和两个模型方法,
1 #pragma mark 模型属性
2
3 //用于存储对应的数据
4
5 @property (nonatomic, copy) NSString *name;
6
7 @property (nonatomic, copy) NSString *icon;
8
9
10 #pragma mark 模型方法
11
12 //用于初始化模型数据
13
14 -(instancetype)initWithDict:(NSDictionary *)dict;
15
16 +(instancetype)shopWithDict:(NSDictionary *)dict;
实现文件中实现对应的模型方法,
1 #pragma mark 模型方法de实现
2
3 -(instancetype)initWithDict:(NSDictionary *)dict{
4 if (self == [super init]) {
5 //创建模型并且通过字典的键获取里面的值放到模型属性中,方便后面用于数据处理直接食用
6 shopsModel *shop = [[shopsModel alloc] init];
7 shop.name = dict[@"name"];
8 shop.icon = dict[@"icon"];
9 }
10 return self;
11 }
12
13 +(instancetype)shopWithDict:(NSDictionary *)dict
14 {
15 return [[self alloc] initWithDict:dict];
16 }
二:View
/***********************纯代码***********************************/
创建一个视图类,用于显示对应的视图(控件,数据)
头文件中通过模型定义一个属性,并且定义三个快速创建视图View的方法,这种方法是使用较多的,而且让人一看上去就知道怎么用
1 //引入模型类
2 @class shopsModel;
3
4 @interface shopsView : UIView
5
6 @property (nonatomic, assign) shopsModel *shop;
7
8 //实例方法,使用模型快速创建视图View
9 -(instancetype)initWIthShop:(shopsModel *)shop;
10
11 //类方法,使用模型快速创建视图View
12 +(instancetype)shopWithShop:(shopsModel *)shop;
13
14 //用于创建View的一个类方法
15 +(instancetype)shopView;
实现文件中先导入模型类:
1 #import "shopsModel.h"
然后实现对应的创建View的方法,
1 -(instancetype)initWIthShop:(shopsModel *)shop
2 {
3 if (self == [super init]) {
4 self.shop = shop;
5 }
6 return self;
7 }
8
9 +(instancetype)shopWithShop:(shopsModel *)shop
10 {
11 return [[self alloc] initWIthShop:shop];
12 }
13
14 +(instancetype)shopView
15 {
16 return [[self alloc] init];
17 }
记得平时我们自定义View的时候,都是直接在init方法中做的,但是,这里有一个细节需要注意的,就是init方法内部会自动调用initWithFrame方法,我们要自定义View一般要做的就是设置View的布局和View的创建,而initWithFrame正好是控件布局之前创建控件的时候调用的,所以我们建议在这里设置他的Frame
这里我们先要在私有拓展中定义两个属性用于记录我们所创建的View的属性
@property (nonatomic, weak) UIImageView *imageV;
@property (nonatomic, weak) UILabel *label;
实现空间创建的View方法
1 //初始化View的方法
2 -(instancetype)initWithFrame:(CGRect)frame
3 {
4
5 if (self == [super initWithFrame:frame]) {
6 //创建UIImageView和UILabel把它加到自定义View上面,并且使用我们定义的属性纪录他,方便后面使用
7
8 UIImageView *image = [[UIImageView alloc] init];
9 [self addSubview:image];
10 self.imageV = image;
11
12 UILabel *label = [[UILabel alloc] init];
13 [self addSubview:label];
14 self.label = label;
15 }
16 return self;
17 }
在View中布局空间的时候就会调用下面的方法
1 //布局子控件方法
2 -(void)layoutSubviews
3 {
4 [super layoutSubviews];
5
6 //获取宽高
7 CGFloat W = self.frame.size.width;
8 CGFloat H = self.frame.size.height;
9
10 //设置自定义View中对应控件的Frame
11 self.imageV.frame = CGRectMake(0, 0, W, W);
12 self.label.frame = CGRectMake(0, W, W, H - W);
13 }
我们还有一个事情要做,就是重写通过模型创建的那个属性,将模型里面的属性设置到控件中对应的属性,
1 //重写Set方法,设置对应的数据
2 -(void)setSpView:(shopsModel *)shop
3 {
4 _shop = shop;
5
6 //使用模型中的数据设置控件对应的属性
7 self.imageV.image = [UIImage imageNamed:shop.icon];
8 self.label.text = shop.name;
9
10 }
/***********************Xib***********************************/
关于Xib这里就不多做解释了
说一下怎么使用Xib创建一个我们自定义的View并且,在控制器里面显示
首先新建一个文件选中interface Builder中的空文件设置一个名字,就可以创建一个Xib文件
————然后创建一个自定义View的类。
点击Xib会看到里面什么也没有,因为我需要自定View所以拖一个View到Xib内部,并且拖我们对应要实现的控件到View里面作为他的子控件,这里需要注意的我们需要设置Xib文件对应的类为我们创建的那个类的名字:
然后我们要做的就是将我们放在View里面的属性设置对输出口(这里就是拖线)这里我们一般是拖到实现文件中的私有拓展中
1 //控件输出口
2
3 @property (weak, nonatomic) IBOutlet UIImageView *icon;
4
5 @property (weak, nonatomic) IBOutlet UILabel *name;
再后面的操作之前我们还需要在头文件引入这个类,并且通过模型创建一个属性
1 //模型商品属性 2 @property (nonatomic, strong) shopsModel *shop;
定义一个通过模型快速创建View的方法
1 //快速创建并且加载Xib文件的方法 2 +(instancetype)shopViewWithShop:(shopsModel *)shop;
然后就是在实现文件中实现这个方法,我们是将Xib的加载封装在里面更好的实现解耦和不被外界知道
这里加载Xib文件的方式有两种
1 /**
2 * 便利创建自定义View的方法
3 */
4 +(instancetype)shopViewWithShop:(shopsModel *)shop
5 {
6
7 /**
8 * 加载Xib文件
9 */
10 iCocosView *shops = [[[NSBundle mainBundle] loadNibNamed:@"shops.plist" owner:nil options:nil] lastObject];
11 /**
12 * 第二种方法
13 */
14 // UINib *nib = [UINib nibWithNibName:@"shops.plist" bundle:[NSBundle mainBundle]];
15 // NSArray *arr = [nib instantiateWithOwner:nil options:nil].lastObject;
16
17 shops.shop = shop;
18 return shops;
19 }
这里同样需要实现重写那个通过模型创建的属性的Setter方法
1 //重写Setter方法,设置View中对应的控件的属性为模型中的数据
2 -(void)setShop:(shopsModel *)shop
3 {
4 _shop = shop;
5
6 //设置模型属性
7 self.icon.image = [UIImage imageNamed:shop.icon];
8 self.name.text = shop.name;
9 }
三:Controller
完成上面之后,控制器里面实现久简单多了
定义一个可变数组用于存放我们的模型数据
1 @property (nonatomic, strong) NSMutableArray *shops;
使用懒加载的方式加载那个plist数据,并且转成模型放到一个数组中,方便后面的使用
1 //懒加载
2 -(NSMutableArray *)shops
3 {
4 if (_shops == nil) {
5 //加载plist数据并且把他放到一个数组中
6 NSArray *shopsArray = [NSArray arrayWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"shops.plist" ofType:nil]];
7 //初始化存放数据的可变模型数组
8 _shops = [NSMutableArray array];
9
10 //遍历那个存放好了plist数组的数组,把他放到一个字典中
11 for (NSDictionary *arr in shopsArray) {
12
13 //使用快速创建模型的方法创建一个模型对象,并且将他加到可变的模型数组中,方便后面使用
14 shopsModel *shop = [shopsModel shopWithDict:arr];
15 [_shops addObject:shop];
16 }
17 }
18 return _shops;
19
20 }
最后我们就只需要在控制器里面控制并且使用上面的模型和View了,
先来看看纯代码是怎么实现的
1 //使用快速创建方法去存放模型数据的数组中取出数据,通过View内部的实现显示到View上面
2 shopsView *shView = [shopsView shopWithShop:self.shops[count]];
3 //设置View的frame
4 shView.frame = CGRectMake(shopX, shopY, shopW, shopH);
5 //将自定义View加到界面中显示
6 [self.shopView addSubview:shView];
如果你使用的是Xib,方法和思路还是一样的
1 //去存放模型数据的数组中取出数据
2 iCocosView *shop = self.shops[index];
3 //通过取出来的数据快速创建一个View放到view内部实现并且使用
4 iCocosView *shopView = [iCocosView shopViewWithShop:shop];
5 //设置View的Frame
6 shopView.frame = CGRectMake(shopX, shopY, shopW, shopH);
7 //将自定义的View添加到界面显示
8 [self.shopsView addSubview:shopView];
/***********************************************Swift实现*******************************************************/
注:如果你没有一点Swift基础(基本语法都不知道,虽然和OC很相似,但看了也是没有用的),建议保留此文,后面学习的Swift过程中遇到的时候再拿来看看就完全不一样了。
最近swift被炒的很火,由于苹果今年做了一个很大的决定,就是Swift2.0将开源,9月份将会放出源码,就意味着我们可以知道这里面是怎么实现的,并且可以在Linux平台上写,我想好处远远不止这些。
笔者对swift也有些一些研究,平时在OC上面学习到一个好东西的时候都会使用实现一遍,所以这个就更不能例外了。
一:Model
第一步我们同样从模型下手,这里喝OC有些不同的是Swift只是在一个文件里面实现的
1 import UIKit
2
3 class Shop: NSObject {
4
5 //定义变量字符串属性
6 var name:String!
7 var icon:String!
8
9 //初始化模型方法
10 init(dict:[String:String]) {
11 super.init()
12
13 //设置模型对应的属性
14 self.name = dict["name"]
15 self.icon = dict["icon"]
16
17 //使用封装好的方法设置模型属性
18 setValuesForKeysWithDictionary(dict)
19 }
20
21 }
二:View
/**************************************纯代码************************************************/
自定义View中实现的方法也是差不多的,只是方法的形式和关键字不同而已
1 import UIKit
2
3 class ShopView: UIView {
4
5 /// 懒加载控件
6 lazy var iconView:UIImageView = UIImageView()
7 lazy var nameView:UILabel = UILabel()
8
9
10 /**
11 初始化Frame
12 */
13 override init(frame: CGRect) {
14 super.init(frame: frame)
15
16 //添加子控件到界面
17 self.addSubview(iconView)
18 self.addSubview(nameView)
19 //设置Label的文字剧中
20 nameView.textAlignment = NSTextAlignment.Center
21 }
22
23 /**
24 从文件中加载数据(Xib/StoryBoard)
25 */
26 required init(coder aDecoder: NSCoder) {
27 fatalError("init(coder:) has not been implemented")
28 }
29
30 /**
31 布局子控件方法
32 */
33 override func layoutSubviews() {
34 //获取宽高
35 var W:CGFloat = self.frame.size.width
36 var H:CGFloat = self.frame.size.height
37
38 //设置UIImageView和UIlable的frame
39 self.iconView.frame = CGRectMake(0, 0, W, W)
40 self.nameView.frame = CGRectMake(0, W, W, H - W)
41 }
42 }
/**************************************Xib************************************************/
使用Xib方式同样是先创建Xib,创建对应的类文件,设置Xib对应为我们创建的类,添加子控件,设置输出口,然后就实现对应的方法
1 import UIKit
2
3 class XMGShopView: UIView {
4
5 /** 图片 */
6 @IBOutlet weak var iconView: UIImageView!
7 /** 名字 */
8 @IBOutlet weak var nameLabel: UILabel!
9
10 var shop: Shop? {
11 didSet {
12 // 重写set方法
13 iconView.image = UIImage(named: shop!.icon)
14 nameLabel.text = shop!.name
15 }
16 }
17 //加载Xib实现方法
18 class func shopView() -> XMGShopView{
19 return NSBundle.mainBundle().loadNibNamed("XMGShopView", owner: nil, options: nil).last as! XMGShopView
20 }
21
22
23 }
注:这里最值得注意的地方是didSet这个方法,其实在swift中海油一个方法叫willSet,他们是相对应的,使用来监听属性变化的,就相当于OC里面的KVO不过在这里叫做属性观察者,分别是在设置属性后和之前调用,这里由于需要只实现了设置之后观察属性的变化
三:Conreoller
关于控制器里面实现的代码和OC里面就有许多不同的地方了,特别是懒加载(lazy)这里,笔者也是搞了好久才搞明白
懒加载
1 //使用lazy实现懒加载,这里使用的是一个叫做闭包返回值的东西来实现的
2 lazy var shops:NSMutableArray = {
3 //从MainBundle中获取plist文件的路径
4 let path:String = NSBundle.mainBundle().pathForResource("shops.plist", ofType: nil)!
5 //加载plist文件放到一个可变数组里面,
6 let tempArr:NSMutableArray = NSMutableArray(contentsOfFile: path)!
7 //定义一个可变的数组,数组的大小就是上面那个存放plist数据的数组的大小
8 let shopsArrM:NSMutableArray = NSMutableArray(capacity: tempArr.count)
9 //遍历存放plist数据的那个数组,放到一个字典中去
10 for dict in tempArr
11 {
12 //使用模型中实现的方法创建一个模型对象
13 let shop: Shop = Shop(dict: dict as! [String : String])
14 //将模型对象放到plist数组中
15 shopsArrM.addObject(shop)
16 }
17 //返回那个存放模型数据的数组
18 return shopsArrM
19 }()
下面就死创建并且显示View的实现
/**************************************纯代码************************************************/
1 //创建一个自定义的View
2 let shopView: ShopView = ShopView()
3 //设置他的frame
4 shopView.frame = CGRect(x: shopX, y: shopY, width: shopW, height: shopH)
5 //取出模型数组中对应的数组设置到试图中(这里使用了?表示类型转换)
6 shopView.shop = self.shops[index] as? Shop
7 //添加并显示
8 self.shopsView.addSubview(shopView)
/**************************************Xib************************************************/
1 //创建一个自定义的View
2 let shopView: iCocosView = iCocosView.shopView()
3 //设置他的frame
4 shopView.frame = CGRect(x: shopX, y: shopY, width: shopW, height: shopH)
5 //取出模型数组中对应的数组设置到试图中(这里使用了?表示类型转换)
6 shopView.shop = self.shops[index] as? Shop
7 //添加并显示
8 self.shopsView.addSubview(shopView)
使用纯代码和Xib的方式没有什么不同,最主要是自定义View内部的实现。
mvc机制
说明:
(1)在开发过程中,作为控制器处理的量级应该很轻,不该操心的不操心。协调好模型和视图就ok了,要学会当一个好老板。
(2)三个部分各司其职,数据模型只负责数据的处理,视图部分只负责把拿到的数据进行显示,两个部分都是被动的,等待着大管家控制器的调遣。
(3)在OC中,如果视图和数据模型之间有通道,那控制器是否处于失控状态呢?
网上有人是这里理解MVC的:
MVC是Model-VIew-Controller,就是模型-视图-控制器,这些都是什么东西呢?MVC把软件系统分为三个部分:Model,View。controller。在cocoa中,你的程序中的每一个object(对象)都将明显地仅属于这三部分中的一个,而完全不属于另外两个。
Model = 你的程序是什么(而不是你的程序是如何显示的)
让我们举个例子,我们上中学的时候,我们的步步高电子词典中有个游戏叫“雷霆战机”,也就是“打飞机”的游戏,Model就是:你的小飞机的攻击力是多少?你的小飞机上装的是什么武器,炮弹,导弹,还是激光炮?你的小飞机还有多少血?等等。再概括点说,就是你的程序将要实现的功能,或者是它所能干的事情。
Controller = 如何使你的模型呈现给用户(程序逻辑)
Controller是程序内部的逻辑,大多情况下你将看不到它,它将Model和View捆绑在一起,它将处理用户的输入,例如,你按开炮的键子,Controller就会通过内部的逻辑来处理你的要求,并在屏幕上做出相应的显示,你将看到屏幕上的小飞机发出炮弹击中敌机。这也是Controller控制View的显示的例子。所以你可以把Controller看成是连接M和V的桥梁。
View = 在屏幕上你所看到的(是你的Controller的“奴才”)
-
外文名
- MVC框架 全 名
- Model View Controller
-
产生时间
- 1982年 架构内容
- 视图,模型,控制器 类 别
- 软件构件模式
目录
简介编辑
MVC 编程模式编辑
- Model(模型)表示应用程序核心(比如数据库记录列表)。
- View(视图)显示数据(数据库记录)。
- Controller(控制器)处理输入(写入数据库记录)。
通常模型对象负责在数据库中存取数据。
通常视图是依据模型数据创建的。
通常控制器负责从视图读取数据,控制用户输入,并向模型发送数据。
框架内容编辑
视图
模型
控制器
区别编辑
常见框架编辑
Struts
Spring
ZF
.NET
特点编辑
优点
缺点
外界评价编辑
MVC控件编辑
LinkExtensions,SelectExtensions,TextAreaExtensions,ValidationExtensions,RenderPartialExtensions等7个静态类,他们全部是是采用拓展方法来实现的。
一、要求
要求完成下面一个小的应用程序。
二、一步步对代码进行优化
注意:在开发过程中,优化的过程是一步一步进行的。(如果一个人要吃五个包子才能吃饱,那么他是否直接吃第五个,前面四个不用吃就饱了?)
1.完成基本要求的代码(使用了字典转模型和xib连线)
(1)文件结构
(2)主要代码
字典转模型部分:
YYappInfo.h头文件
1 // 2 // YYappInfo.h 3 // 12-视图改进(1) 4 // 5 // Created by apple on 14-5-25. 6 // Copyright (c) 2014年 itcase. All rights reserved. 7 // 8 9 #import <Foundation/Foundation.h> 10 11 @interface YYappInfo : NSObject 12 @property(nonatomic,copy)NSString *name; 13 @property(nonatomic,copy)NSString *icon; 14 @property(nonatomic,strong,readonly)UIImage *img; 15 16 -(instancetype)initWithDict:(NSDictionary *)dict; 17 /**工厂方法*/ 18 +(instancetype)appInfoWithDict:(NSDictionary *)dict; 19 @end
YYappInfo.m文件
1 // 2 // YYappInfo.m 3 // 12-视图改进(1) 4 // 5 // Created by apple on 14-5-25. 6 // Copyright (c) 2014年 itcase. All rights reserved. 7 // 8 9 #import "YYappInfo.h" 10 @interface YYappInfo() 11 { 12 UIImage *_img; 13 } 14 @end 15 @implementation YYappInfo 16 -(instancetype)initWithDict:(NSDictionary *)dict 17 { 18 if (self=[super init]) { 19 self.name=dict[@"name"]; 20 self.icon=dict[@"icon"]; 21 } 22 return self; 23 } 24 25 +(instancetype)appInfoWithDict:(NSDictionary *)dict 26 { 27 return [[self alloc]initWithDict:dict]; 28 } 29 30 -(UIImage *)img 31 { 32 _img=[UIImage imageNamed:self.icon]; 33 return _img; 34 } 35 @end
xib部分(YYappInfoView.h文件):
注:(xib视图和YYappInfoView进行了关联,三个属性均进行了连线)
1 // 2 // YYappInfoView.h 3 // 12-视图改进(1) 4 // 5 // Created by apple on 14-5-25. 6 // Copyright (c) 2014年 itcase. All rights reserved. 7 // 8 9 #import <UIKit/UIKit.h> 10 11 @interface YYappInfoView : UIView 12 @property (strong, nonatomic) IBOutlet UIImageView *appInfoViewimg; 13 14 @property (strong ,nonatomic) IBOutlet UILabel *appInfoViewlab; 15 @property (strong, nonatomic) IBOutlet UIButton *appInfoViewbtn; 16 17 @end
主要功能实现部分:
YYViewController.m文件
1 // 2 // YYViewController.m 3 // 12-视图改进(1) 4 // 5 // Created by apple on 14-5-25. 6 // Copyright (c) 2014年 itcase. All rights reserved. 7 // 8 9 #import "YYViewController.h" 10 #import "YYappInfo.h" 11 #import "YYappInfoView.h" 12 13 @interface YYViewController () 14 @property(nonatomic,strong)NSArray *apps; 15 @end 16 17 //开发思路 18 //1.加载plist文件(字典转模型提供接口) 19 //2.使用xib文件完成单个的view 20 //3.计算坐标,使用for循环把view展现到界面上 21 //4.优化代码 22 @implementation YYViewController 23 24 //get方法,懒加载 25 -(NSArray *)apps 26 { 27 if (!_apps) { 28 NSString *path = [[NSBundle mainBundle]pathForResource:@"app.plist" ofType:nil]; 29 NSArray * arrayM = [NSArray arrayWithContentsOfFile:path]; 30 31 NSMutableArray *appinfoarray=[NSMutableArray array]; 32 for (NSDictionary *dict in arrayM) { 33 [appinfoarray addObject:[YYappInfo appInfoWithDict:dict]]; 34 } 35 _apps = appinfoarray; 36 } 37 return _apps; 38 } 39 40 - (void)viewDidLoad 41 { 42 [super viewDidLoad]; 43 NSLog(@"%d",self.apps.count); 44 45 int totalloc = 3; 46 CGFloat appviewW = 80; 47 CGFloat appviewH = 90; 48 CGFloat margin = (self.view.frame.size.width-totalloc*appviewW)/(totalloc+1); 49 50 int count=self.apps.count; 51 for (int i = 0; i < count; i++) { 52 int row = i/totalloc; 53 int loc = i%totalloc; 54 55 CGFloat appviewX = margin + (margin + appviewW) * loc; 56 CGFloat appviewY = margin + (margin + appviewH) * row; 57 58 YYappInfo *appinfo=self.apps[i]; 59 60 //拿出xib中的数据 61 NSArray *arryM=[[NSBundle mainBundle]loadNibNamed:@"appInfoxib" owner:nil options:nil]; 62 YYappInfoView *appinfoview=[arryM firstObject]; 63 //设置位置 64 appinfoview.frame=CGRectMake(appviewX, appviewY, appviewW, appviewH); 65 //设置值 66 appinfoview.appInfoViewimg.image=appinfo.img; 67 appinfoview.appInfoViewlab.text=appinfo.name; 68 //添加到视图 69 appinfoview.appInfoViewbtn.tag=i; 70 [appinfoview.appInfoViewbtn addTarget:self action:@selector(Click:) forControlEvents:UIControlEventTouchUpInside]; 71 [self.view addSubview:appinfoview]; 72 } 73 } 74 -(void)Click:(UIButton *)btn 75 { 76 btn.enabled=NO; 77 YYappInfo *appinfo=self.apps[btn.tag]; 78 UILabel *lab=[[UILabel alloc]initWithFrame:CGRectMake(60, 450, 200, 20)]; 79 [lab setBackgroundColor:[UIColor lightGrayColor]]; 80 [lab setTextAlignment:NSTextAlignmentCenter]; 81 [lab setText:[NSString stringWithFormat:@"%@成功下载",appinfo.name]]; 82 [self.view addSubview:lab]; 83 84 lab.alpha=1.0; 85 [UIView animateWithDuration:2.0 animations:^{ 86 lab.alpha=0; 87 }completion:^(BOOL finished) { 88 [lab removeFromSuperview]; 89 }]; 90 } 91 @end
2.对1进行优化(把数据呈现部分封装到视图)
说明:在1的基础上寻找还会有那些可以优化的部分
1)改进思路:
(1)1中主文件的66~67行对控件属性的设置能否拿到视图中进行?
(2)1中61~62行是从xib文件中读取信息的操作,且和主控制器没有什么太大的关联,能否把它也封装到视图中进行?
(3)当上述两个步骤完成后,主文件69行以后的按钮操作和按钮单击事件就显得很突兀,放在主控制器中已经不再合适,是否可以把它放到视图中进行处理
2)按照上述思路优化后的代码如下:
优化视图,在视图部分之对外提供一个接口,把数据的处理封装在内部
YYappInfoView.h文件代码:
1 // 2 // YYappInfoView.h 3 // 12-视图改进(1) 4 // 5 // Created by apple on 14-5-25. 6 // Copyright (c) 2014年 itcase. All rights reserved. 7 // 8 9 #import <UIKit/UIKit.h> 10 @class YYappInfo; 11 @interface YYappInfoView : UIView 12 13 //读取 14 //+(instancetype)appInfoView; 15 //只对外开放一个数据接口 16 +(instancetype)appInfoViewWithappInfo:(YYappInfo *)appinfo; 17 @end
YYappInfoView.m文件代码
说明:该文件中的属性和click等均已做了连线的操作。
1 // 2 // YYappInfoView.m 3 // 12-视图改进(1) 4 // 5 // Created by apple on 14-5-25. 6 // Copyright (c) 2014年 itcase. All rights reserved. 7 // 8 9 #import "YYappInfoView.h" 10 #import "YYappInfo.h" 11 //私有扩展,把属性拿进来 12 @interface YYappInfoView () 13 @property (strong, nonatomic) IBOutlet UIImageView *appInfoViewimg; 14 @property (strong ,nonatomic) IBOutlet UILabel *appInfoViewlab; 15 @property (strong, nonatomic) IBOutlet UIButton *appInfoViewbtn; 16 @property(strong,nonatomic)YYappInfo *appinfo; 17 18 @end 19 @implementation YYappInfoView 20 21 +(instancetype)appInfoView 22 { 23 NSArray *arryM=[[NSBundle mainBundle]loadNibNamed:@"appInfoxib" owner:nil options:nil]; 24 YYappInfoView *appinfoview=[arryM firstObject]; 25 return appinfoview; 26 } 27 28 +(instancetype)appInfoViewWithappInfo:(YYappInfo *)appinfo 29 { 30 YYappInfoView *appInfoView=[self appInfoView]; 31 appInfoView.appinfo=appinfo; 32 return appInfoView; 33 } 34 35 -(void)setAppinfo:(YYappInfo *)appinfoc 36 { 37 //这里一定要记录变化 38 _appinfo=appinfoc; 39 self.appInfoViewimg.image=appinfoc.img; self.appInfoViewlab.text=appinfoc.name;
41 }
42 - (IBAction)Click { 43 44 self.appInfoViewbtn.enabled=NO; 45 //YYappInfo *appinfo=self.apps[]; 46 47 YYappInfo *appinfo=self.appinfo; 48 UILabel *lab=[[UILabel alloc]initWithFrame:CGRectMake(60, 450, 200, 20)]; 49 [lab setBackgroundColor:[UIColor lightGrayColor]]; 50 [lab setTextAlignment:NSTextAlignmentCenter]; 51 [lab setText:[NSString stringWithFormat:@"%@成功下载",appinfo.name]]; 52 //把lab添加到父视图(即view中) 53 [self.superview addSubview:lab]; 54 55 lab.alpha=1.0; 56 [UIView animateWithDuration:2.0 animations:^{ 57 lab.alpha=0; 58 }completion:^(BOOL finished) { 59 [lab removeFromSuperview]; 60 }]; 61 } 62 63 64 @end
优化后的主控制器部分
YYViewController.m文件代码
1 // 2 // YYViewController.m 3 // 12-视图改进(1) 4 // 5 // Created by apple on 14-5-25. 6 // Copyright (c) 2014年 itcase. All rights reserved. 7 // 8 9 #import "YYViewController.h" 10 #import "YYappInfo.h" 11 #import "YYappInfoView.h" 12 13 @interface YYViewController () 14 @property(nonatomic,strong)NSArray *apps; 15 @end 16 @implementation YYViewController 17 18 -(NSArray *)apps 19 { 20 if (!_apps) { 21 NSString *path = [[NSBundle mainBundle]pathForResource:@"app.plist" ofType:nil]; 22 NSArray * arrayM = [NSArray arrayWithContentsOfFile:path]; 23 24 NSMutableArray *appinfoarray=[NSMutableArray array]; 25 for (NSDictionary *dict in arrayM) { 26 [appinfoarray addObject:[YYappInfo appInfoWithDict:dict]]; 27 } 28 _apps = appinfoarray; 29 } 30 return _apps; 31 } 32 33 - (void)viewDidLoad 34 { 35 [super viewDidLoad]; 36 NSLog(@"%d",self.apps.count); 37 38 int totalloc = 3; 39 CGFloat appviewW = 80; 40 CGFloat appviewH = 90; 41 CGFloat margin = (self.view.frame.size.width-totalloc*appviewW)/(totalloc+1); 42 43 int count=self.apps.count; 44 for (int i = 0; i < count; i++) { 45 int row = i/totalloc; 46 int loc = i%totalloc; 47 48 CGFloat appviewX = margin + (margin + appviewW) * loc; 49 CGFloat appviewY = margin + (margin + appviewH) * row; 50 51 /*思路: 52 要达到的效果 appinfoview.appinfo=appinfo; 53 优化后即变成 appinfoview.appinfo=self.apps[i]; 54 要进行上面代码的操作,需要在视图中新增加一个appinfo类的属性,这样数据——》视图的转换即可以不需要在主控制器中完成,让程序结构一目了然 55 */ 56 YYappInfo *appinfo=self.apps[i]; 57 YYappInfoView *appinfoview=[YYappInfoView appInfoViewWithappInfo:appinfo]; 58 //设置位置 59 appinfoview.frame=CGRectMake(appviewX, appviewY, appviewW, appviewH); 60 //添加 61 [self.view addSubview:appinfoview]; 62 } 63 } 64 @end
3.对2进一步优化(把数据处理部分拿到模型中去进行)
(1)思路:把字典转模型部分的数据处理操作,拿到模型中去处理,这样外界不需要再关心数据处理的内部细节。
(2)优化后的代码如下
YYappInfo.h文件中向外开放一个接口,返回一个处理好的数组。
1 // 2 // YYappInfo.h 3 // 12-视图改进(1) 4 // 5 // Created by apple on 14-5-25. 6 // Copyright (c) 2014年 itcase. All rights reserved. 7 // 8 9 #import <Foundation/Foundation.h> 10 11 @interface YYappInfo : NSObject 12 @property(nonatomic,copy)NSString *name; 13 @property(nonatomic,copy)NSString *icon; 14 @property(nonatomic,strong)UIImage *img; 15 16 -(instancetype)initWithDict:(NSDictionary *)dict; 17 /**工厂方法*/ 18 +(instancetype)appInfoWithDict:(NSDictionary *)dict; 19 +(NSArray *)appinfoarray; 20 @end
YYappInfo.m文件中的数据处理
1 // 2 // YYappInfo.m 3 // 12-视图改进(1) 4 // 5 // Created by apple on 14-5-25. 6 // Copyright (c) 2014年 itcase. All rights reserved. 7 // 8 9 #import "YYappInfo.h" 10 @interface YYappInfo() 11 @end 12 @implementation YYappInfo 13 -(instancetype)initWithDict:(NSDictionary *)dict 14 { 15 if (self=[super init]) { 16 self.name=dict[@"name"]; 17 self.icon=dict[@"icon"]; 18 } 19 return self; 20 } 21 22 +(instancetype)appInfoWithDict:(NSDictionary *)dict 23 { 24 return [[self alloc]initWithDict:dict]; 25 } 26 27 -(UIImage *)img 28 { 29 _img=[UIImage imageNamed:self.icon]; 30 return _img; 31 } 32 33 //把数据处理部分拿到模型中来处理 34 +(NSArray *)appinfoarray 35 { 36 NSString *path = [[NSBundle mainBundle]pathForResource:@"app.plist" ofType:nil]; 37 NSArray * arrayM = [NSArray arrayWithContentsOfFile:path]; 38 39 NSMutableArray *appinfoarray=[NSMutableArray array]; 40 for (NSDictionary *dict in arrayM) { 41 [appinfoarray addObject:[YYappInfo appInfoWithDict:dict]]; 42 } 43 return appinfoarray; 44 } 45 @end
主控制器中不再需要关心数据处理的内部细节
YYViewController.m文件现在只是负责模型和视图之间的协调工作了,怎么样?差不多了吧。
1 // 2 // YYViewController.m 3 // 12-视图改进(1) 4 // 5 // Created by apple on 14-5-25. 6 // Copyright (c) 2014年 itcase. All rights reserved. 7 // 8 9 #import "YYViewController.h" 10 #import "YYappInfo.h" 11 #import "YYappInfoView.h" 12 13 @interface YYViewController () 14 @property(nonatomic,strong)NSArray *apps; 15 @end 16 @implementation YYViewController 17 18 -(NSArray *)apps 19 { 20 if (!_apps) { 21 _apps=[YYappInfo appinfoarray]; 22 } 23 return _apps; 24 } 25 26 - (void)viewDidLoad 27 { 28 [super viewDidLoad]; 29 30 int totalloc = 3; 31 CGFloat appviewW = 80; 32 CGFloat appviewH = 90; 33 CGFloat margin = (self.view.frame.size.width-totalloc*appviewW)/(totalloc+1); 34 35 int count=self.apps.count; 36 for (int i = 0; i < count; i++) { 37 38 int row = i/totalloc; 39 int loc = i%totalloc; 40 41 CGFloat appviewX = margin + (margin + appviewW) * loc; 42 CGFloat appviewY = margin + (margin + appviewH) * row; 43 44 YYappInfo *appinfo=self.apps[i]; 45 YYappInfoView *appinfoview=[YYappInfoView appInfoViewWithappInfo:appinfo]; 46 appinfoview.frame=CGRectMake(appviewX, appviewY, appviewW, appviewH); 47 [self.view addSubview:appinfoview]; 48 } 49 } 50 @end
实现效果:
4.补充说明
View的封装思路
(1) 如果一个view内部的子控件比较多,一般会考虑自定义一个view,把它内部子控件的创建屏蔽起来,不让外界关心
(2) 外界可以传入对应的模型数据给view,view拿到模型数据后给内部的子控件设置对应的数据
三、mvc机制简单说明
说明:
(1)在开发过程中,作为控制器处理的量级应该很轻,不该操心的不操心。协调好模型和视图就ok了,要学会当一个好老板。
(2)三个部分各司其职,数据模型只负责数据的处理,视图部分只负责把拿到的数据进行显示,两个部分都是被动的,等待着大管家控制器的调遣。
在组织大型项目的代码文件时,我们常用MVC的思想。MVC的概念讲起来非常简单,就和对象(object)一样。但是理解和应用起来却非常困难。今天我们就试着探讨一下MVC设计理念。
M是指业务模型,V是指用户界面,C则是控制器,使用MVC的目的是将M和V的实现代码分离,从而使同一个程序可以使用不同的表现形式。
比如一批统计数据可以分别用柱状图、饼图来表示。
C存在的目的则是确保M和V的同步,一旦M改变,V应该同步更新。
再实际开发中,M虽然本意是业务模型,但通常被理解为数据库操作层。
V即界面层,这个没有异议。
C则被理解为业务层。
对应在ios中,V就是指.xib文件。C是指.m文件。但是,通常情况并不如我们想像的这么理想。因为客户的需求是千变万化的。很多时候,我们需要根据客户的需求对界面进行自定义。所以,很多时候界面代码和会混淆在.m文件中和控制层代码掺杂在一起。
在我个人的设想中,MVC这三层分别要完成哪些工作呢?
本层要实现的功能:
(1)
本层输入件:sql增加或插入数据库表对应的实体类的对象的语句
本层输出件:增加、或插入数据库
(2)
本层输入件:sql查询语句
本层输出件:返回存储实体类对象的数组
(3)
本层输入件:sql删除语句
本层输出件:删除数据库中的指定信息
2、V层 视图
不用多讲了,在ios中,这个层主要由.nib文件完成。如果客户由自定义需求,则在.m文件中实现。
本层实现的功能就是控件的布局。
3、C层 控制
这个层的意义就在于确保M和V的同步。我个人理解,这层不仅叫控制层,更应该叫业务层。
本层要实现的功能:
(1)
本层输入件:界面控件中数据和事件
本层输出件:
第一:调用M层的接口,更新M层(数据库)中的数据
第二:调用V层的接口,更新V层(界面)中的数据
在现实的开发过程中,代码真的就这么清晰地分成以上三种吗?
现实中,工程中还有以下几种类型的代码:
(1)接口文件[数据操作]
(2)解析通过接口获取的数据[数据操作]
(3)开源框架(实现各种界面效果、解析各种数据)[数据操作+V显示]
(4)工具类(比如为图片增加圆角、实现checkbox、实现各种页面效果、数据加密解密)[数据操作+V显示]
(5)本项目提炼的公用类(如验证、升级检测、数据更新等)[数据操作M]
业务层BusinessLayer:
可以调用:数据层
可以被调用:控制层
组织当前软件独特的业务体系,只处理数据,和数据层和控制层有关系,和界面层没有任何关系。
常见业务:
(1)数据同步(用到数据层数据操作和界面层的数据)
(2)软件升级
(3)登录验证
(4)账号有效性验证
控制层ControllerLayer:只负责数据层和界面层的数据同步(通过业务层来实现)
数据层DataLayer:只和数据打交道,和业务毫无关系
界面层ViewLevel:只和界面打交道,和控制层打交道,和其他层毫无关系
用MVC思想重构一个项目的核心就是剥离出这个项目的业务逻辑。
什么是项目的业务逻辑?所谓业务逻辑关注点主要集中在业务规则的制定、业务流程的实现等与业务需求有关的系统设计。简而言之,所谓业务逻辑就是指业务规则。凡事有规则的东西,就是业务逻辑,没有规则的东西就不是业务逻辑。
利用MVC思想组织的文件结构一例:
IOS下的MVC
一、概念 Model = 你的应用程序是什么,是用户界面无关的部分 Controller = 你的应用程序如何将Model显示给用户(UI逻辑),是中心是桥梁,连通Model和View View = Controller的奴才(minion)、小跟班。view一切听从Controller的指挥,并及时将重要事件报告给Controller
二、通信 mvc设计模式,IPhone MVC设计模式要点
1、Model和View永远不能相互通信,只能通过Controller传递。
2、Controller可以直接与Model对话(读写调用Model),Model通过Notification和KVO机制与Controller间接通信。
3、Controller可以直接与View对话(通过outlet,直接操作View,outlet直接对应到View中的控件),View通过 action向Controller报告事件的发生(如用户Touch我了)。Controller是View的直接数据源(数据很可能是 Controller从Model中取得的)。Controller是View的代理(delegate),以同步View与Controller,delegate是一组协议,表示程序将要或者已经处于某种状态时,来调整View,以对用户有个交代。例如系统内存不足了,你是 不是相应的降低view的质量以节省内存。
- @property (nonatomic, copy, readonly) NSString *title, *artist, *genre, *coverUrl, *year;
- - (id)initWithTitle:(NSString*)title artist:(NSString*)artist coverUrl:(NSString*)coverUrl year:(NSString*)year;
- - (id)initWithTitle:(NSString*)title artist:(NSString*)artist coverUrl:(NSString*)coverUrl
- year:(NSString*)year {
- self = [super init];
- if (self)
- {
- _title = title;
- _artist = artist;
- _coverUrl = coverUrl;
- _year = year;
- _genre = @"Pop";
- }
- return self;
- }
- @implementationAlbumView
- {
- UIImageView *coverImage;
- UIActivityIndicatorView *indicator;
- }
- - (id)initWithFrame:(CGRect)frame albumCover:(NSString*)albumCover
- {
- self = [super initWithFrame:frame];
- if (self)
- {
- self.backgroundColor = [UIColor blackColor];
- // the coverImage has a 5 pixels margin from its frame
- coverImage = [[UIImageView alloc] initWithFrame:CGRectMake(5, 5, frame.size.width-10,
- frame.size.height-10)];
- [self addSubview:coverImage];
- indicator = [[UIActivityIndicatorView alloc] init];
- indicator.center = self.center;
- indicator.activityIndicatorViewStyle = UIActivityIndicatorViewStyleWhiteLarge;
- [indicator startAnimating];
- [self addSubview:indicator];
- }
- return self;
- }
- @end
- + (LibraryAPI*)sharedInstance
- {
- // 1
- static LibraryAPI *_sharedInstance = nil;
- // 2
- static dispatch_once_t oncePredicate;
- // 3
- dispatch_once(&oncePredicate, ^{
- _sharedInstance = [[LibraryAPI alloc] init];
- });
- return _sharedInstance;
- }
- - (NSArray*)getAlbums;
- - (void)addAlbum:(Album*)album atIndex:(int)index;
- - (void)deleteAlbumAtIndex:(int)index;
- - (id)init
- {
- self = [super init];
- if (self) {
- // a dummy list of albums
- albums = [NSMutableArrayarrayWithArray:
- @[[[Album alloc] initWithTitle:@"Best of Bowie" artist:@"David Bowie" coverUrl:@"http://www.coversproject.com/static/thumbs/album/album_david%20bowie_best%20of%20bowie.png" year:@"1992"],
- [[Album alloc] initWithTitle:@"It's My Life" artist:@"No Doubt" coverUrl:@"http://www.coversproject.com/static/thumbs/album/album_no%20doubt_its%20my%20life%20%20bathwater.png" year:@"2003"],
- [[Album alloc] initWithTitle:@"Nothing Like The Sun" artist:@"Sting" coverUrl:@"http://www.coversproject.com/static/thumbs/album/album_sting_nothing%20like%20the%20sun.png" year:@"1999"],
- [[Album alloc] initWithTitle:@"Staring at the Sun" artist:@"U2" coverUrl:@"http://www.coversproject.com/static/thumbs/album/album_u2_staring%20at%20the%20sun.png" year:@"2000"],
- [[Album alloc] initWithTitle:@"American Pie" artist:@"Madonna" coverUrl:@"http://www.coversproject.com/static/thumbs/album/album_madonna_american%20pie.png" year:@"2000"]]];
- }
- return self;
- }
- - (NSArray*)getAlbums
- {
- return albums;
- }
- - (void)addAlbum:(Album*)album atIndex:(int)index
- {
- if (albums.count >= index)
- [albums insertObject:album atIndex:index];
- else
- [albums addObject:album];
- }
- - (void)deleteAlbumAtIndex:(int)index
- {
- [albums removeObjectAtIndex:index];
- }
注:突然冒出个delegate,让人不好理解,其实他不对应xcode为我们创建的XXAppDelegate文件,此文件不属于MVC中的任何一部分,虽然与MVC有联系。
三、实作 建立一个BtnClick工程系统,会为我们生成以下文件:
BtnClickAppDelegate.h
BtnClickAppDelegate.m
以上两个文件定义了实现UIApplicationDelegate协议的类 BtnClicAppDelegate,UIApplicationDelegate协议是系统预定义的协议,负责监视应用程序的高层行为,处理几个关键 系统消息,是应用程序生命周期为我们预留的Hook,每个iphone应用程序必不可少的。
iphone应用程序的生命周期: mvc设计模式,IPhone MVC设计模式要点
BtnClickViewController.h BtnClickViewController.m 实现了MVC中的Controller.可以定义一些IBOutlet元素和IBAction方法与View通信。
@interface
BtnClickViewController : UIViewController{
IBOutlet
UILabel* statusText;
}
@property
(retain,
nonatomic
) UILabel *statusText;
- (
IBAction
)buttonPressed:(
id
)sender;
@end
|
View对于那个文件?
答案是Resource下的MainWindow.xib和BtnClickViewController.xib。
MainWindow.xib文件在在应用程序加载是会被自动加载,这其实是在plist文件中配置的。然后MainWindow.xib会加载子视图 BtnClickViewController.xib。为什么会命名为ViewController,而不是分开命名?可能是因为View和Controller关系太紧密了,view就是Controller的跟班。
实际编程时一定要分清MVC各部分的职责。
iOS开发之理解iOS中的MVC设计模式
模型-视图-控制器(Model-View-Controller,MVC)是Xerox PARC在20世纪80年代为编程语言Smalltalk-80发明的一种软件设计模式,至今已广泛应用于用户交互应用程序中。在iOS开发中MVC的机制被使用的淋漓尽致,充分理解iOS的MVC模式,有助于我们程序的组织合理性。
模型对象
模型对象封装了应用程序的数据,并定义操控和处理该数据的逻辑和运算。例如,模型对象可能是表示游戏中的角色或地址簿中的联系人。用户在视图层中所进行的创建或修改数据的操作,通过控制器对象传达出去,最终会创建或更新模型对象。模型对象更改时(例如通过网络连接接收到新数据),它通知控制器对象,控制器对象更新相应的视图对象。
视图对象
视图对象是应用程序中用户可以看见的对象。视图对象知道如何将自己绘制出来,并可能对用户的操作作出响应。视图对象的主要目的,就是显示来自应用程序模型对象的数据,并使该数据可被编辑。尽管如此,在 MVC 应用程序中,视图对象通常与模型对象分离。
在iOS应用程序开发中,所有的控件、窗口等都继承自 UIView,对应MVC中的V。UIView及其子类主要负责UI的实现,而UIView所产生的事件都可以采用委托的方式,交给UIViewController实现。
控制器对象
在应用程序的一个或多个视图对象和一个或多个模型对象之间,控制器对象充当媒介。控制器对象因此是同步管道程序,通过它,视图对象了解模型对象的更改,反之亦然。控制器对象还可以为应用程序执行设置和协调任务,并管理其他对象的生命周期。
控制器对象解释在视图对象中进行的用户操作,并将新的或更改过的数据传达给模型对象。模型对象更改时,一个控制器对象会将新的模型数据传达给视图对象,以便视图对象可以显示它。
对于不同的UIView,有相应的UIViewController,对应MVC中的C。例如在iOS上常用的UITableView,它所对应的Controller就是UITableViewController。
- Model和View永远不能相互通信,只能通过Controller传递。
- Controller可以直接与Model对话(读写调用Model),Model通过Notification和KVO机制与Controller间接通信。
- Controller可以直接与View对话,通过outlet,直接操作View,outlet直接对应到View中的控件,View通过action向Controller报告事件的发生(如用户Touch我了)。Controller是View的直接数据源(数据很可能是Controller从Model中取得并经过加工了)。Controller是View的代理(delegate),以同步View与Controller。
如果数据模型和数据库上下文是建立在解决方案的.web项目下、
1.打开“工具---NuGet程序包管理器---程序包管理器控制台”
2.输入:enable-migrations,程序会自动寻找在web中的数据库上下文,成功后会生成一个Migrations的文件夹。
3.输入:add-migrations,此时控制台会要你输入此次更新的名称,比如你可以输入User,(你这次添加了一个User模型)
4.输入:update-database,这样就实现了数据库的迁移。
如果数据库上下文不是建立在web项目下,比如我把数据库上下文建立在了一个类库Triz.DAL里。则可以使用以下方法来进行迁移。
1.输入enable-migrations -projectname Triz.DAL
2.输入add-migration -projectname Triz.DAL,输入此条语句后同样会要你填写这次更新的名字,是为了便于记录。
3.输入update-database -projectname Triz.DAL
过程与上面的类似,只不过指定了新的ProjectName
IOS的生态系统
iOS自下至上可以分为四层:Core OS,Core Services,Media,Cocoa Touch。
Core OS
是用FreeBSD和Mach所改写的Darwin, 是开源、符合POSIX标准的一个Unix核心。这一层提供了整个iPhone OS的一些基础功能,比如:硬件驱动, 内存管理,程序管理,线程管理(POSIX),文件系统,网络(BSD Socket),以及标准输入输出等等,所有这些功能都会通过C语言的API来提供。另外,值得一题的是,这一层最具有UNIX色彩,如果你需要把 UNIX上所开发的程序移植到iPhone上,多半都会使用到Core OS的API。核心OS层的驱动也提供了硬件和系统框架之间的接口。然而,由于安全的考虑,只有有限的系统框架类能访问内核和驱动。iPhone OS提供了许多访问操作系统低层功能的接口集,iPhone 应用通过LibSystem库来访问这些功能,这些接口集如下所示:
- 线程(POSIX线程);
- 网络(BSD sockets);
- 文件系统访问;
- 标准I/O;
- Bonjour和DNS服务;
- 现场信息(Locale Information);
- 内存分配;
- 数学计算。
Core Services
在Core OS基础上提供了更为丰富的功能, 它包含了Foundation.Framework和Core Foundation.Framework, 之所以叫Foundation ,就是因为它提供了一系列处理字串,排列,组合,日历,时间等等的基本功能。Foundation是属于Objective-C的API,Core Fundation是属于C的API。另外Core servieces还提供了其他的功能,比如:Security, Core Location, SQLite, 和Address Book. 其中Security是用来处理认证,密码管理,按安全性管理的; Core Location是用来处理GPS定位的;SQLLite是轻量级的数据库,而AddressBook则用来处理电话薄资料的。下面是具体介绍:
(1)电话本框架(AddressBook.framework)
提供了保存在手机设备中的电话本编程接口。开发者能使用该框架访问和修改存储在用户联系人数据库里的记录。
例如,一个聊天程序可以使用该框架获得可能的联系人列表,启动聊天的进程(Process),并在视图上显示这些联系人信息等。
(2)核心基础框架(CoreFoundation.framework)
是基于C语言的接口集,提供iPhone应用的基本数据管理和服务功能。该框架 支持如下功能:
- Collection数据类型(Arrays、 Sets等);
- Bundles;
- 字符串管理;
- 日期和时间管理;
- 原始数据块管理;
- 首选项管理;
- URL和Stream操作;
- 线程和运行循环(Run Loops);
- 端口和Socket通信。
核心基础框架与基础框架是紧密相关的,它们为相同的基本功能提供了Objective-C接口。如果开发者混合使用Foundation Objects 和Core Foundation类型,就能充分利用存在两个框架中的"toll-free bridging"。
toll-free bridging意味着开发者能使用这两个框架中的任何一个的核心基础和基础类型,例如Collection和字符串类型等。每个框架中的类和数据类型的描述注明该对象是否支持toll-free bridged。如果是,它与哪个对象桥接(toll-free bridged)。
(3)CFNetwork框架(CFNetwork.framework)
是一组高性能的C语言接口集,提供网络协议的面向对象的抽象。开发者可以使用 CFNetwork框架操作协议栈,并且可以访问低层的结构如BSD Sockets等。同时,开发者也能简化与FTP和HTTP服务器的通信,或解析DNS等任务。使用CFNetwork框架实现的任务如下所示:
- BSD Sockets;
- 利用SSL或TLS创建加密连接;
- 解析DNS Hosts;
- 解析HTTP协议,鉴别HTTP和HTTPS服务器;
- 在FTP服务器工作;
- 发布、解析和浏览Bonjour服务。
(4)核心位置框架(Core Location Framework)
主要获得手机设备当前的经纬度,核心位置框架利用附近的GPS、蜂窝基站或Wi- Fi信号信息测量用户的当前位置。iPhone地图应用使用这个功能在地图上显示用户的当前位置。开发者能融合这个技术到自己的应用中,给用户提供一些位置信息服务。
例如可以提供一个服务:基于用户的当前位置,查找附近的餐馆、商店或设备等。
(5)安全框架(Security Framework)
iPhone OS除了内置的安全特性外,还提供了外部安全框架,从而确保应用数据的安全性。该框架提供了管理证书、公钥/私钥对和信任策略等的接口。它支持产生加密安全的伪随机数,也支持保存在密钥链的证书和密钥。对于用户敏感的数据,它是安全的知识库(Secure Repository)。CommonCrypto接口也支持对称加密、HMAC和数据摘要。在iPhone OS里没有OpenSSL库,但是数据摘要提供的功能在本质上与OpenSSL库提供的功能是一致的。
(6)SQLite
开发者可以创建本地数据库文件,并管理这些文件中的表格和记录。数据库SQLite为通用的目的而设计,但仍可以优化为快速访问数据库记录。访问数据库SQLite的头文件位于<iPhoneSDK>/usr/include/sqlite3.h,其中<iPhoneSDK>是SDK安装的目标路径。
(7)支持XML
基础框架提供NSXMLParser类,解析XML文档元素。libXML2库提供操作XML内容的功能,这个开放源代码的库可以快速解析和编辑 XML数据,并且转换XML内容到HTML。访问libXML2库的头文件位于目录<iPhoneSDK>/usr/include /libxml2/,其中<iPhoneSDK>是SDK安装的目标目录。
Media层
提供了图片,音乐,影片等多媒体功能。图像分为2D图像和3D图像, 前者由Quartz2D来支持,后者则是用OpenglES.与音乐对应的模组是Core Audio和OpenAL, Media Player 实现了影片的播放,而最后还提供了Core Animation来对强大动画的支持。具体介绍如下:
(1)图像技术(Graphics Technologies)
高质量图像是所有iPhone应用的一个重要的组成部分。任何时候,开发者可以采用UIKit 框架中已有的视图和功能以及预定义的图像来开发iPhone应用。然而,当UIKit 框架中的视图和功能不能满足需求时,开发者可以应用下面描述的技术和方法来制作视图。
① Quartz核心图像框架(CoreGraphics.framework)
包含了Quartz 2D画图API,Quartz与在Mac OS中采用的矢量图画引擎是一样先进的。Quartz支持基于路径(Path-based)画图、抗混淆(Anti-aliased)重载、梯度 (Gradients)、图像(Images)、颜色(Colors)、坐标空间转换(Coordinate-space Transformations)、pdf文档创建、显示和解析。虽然API是基于C语言的,它采用基于对象的抽象表征基础画图对象,使得图像内容易于保存和复用。
② 核心动画(Core Animation)
Quartz核心框架(QuartzCore.framework)包含CoreAnimation接口,Core Animation是一种高级动画和合成技术,它用优化的重载路径(Rendering Path)实现复杂的动画和虚拟效果。它用一种高层的Objective-C接口配置动画和效果,然后重载在硬件上获得较好的性能。Core Animation集成到iPhone OS 的许多部分,包括UIKit类如UIView,提供许多标准系统行为的动画。开发者也能利用这个框架中的Objective-C接口创建客户化的动画。
③ OpenGL ES
OpenGL ES框架(OpenGLES.framework)符合OpenGL ES v1.1规范,它提供了一种绘画2D和3D内容的工具。OpenGL ES 框架是基于C语言的框架,与硬件设备紧密相关,为全屏游戏类应用提供高帧率(high frame rates)。开发者总是要使用OpenGL框架的EAGL接口,EAGL接口是OpenGL ES框架的一部分,它提供了应用的OpenGL ES画图代码和本地窗口对象的接口。
(2)音频技术(Audio Technologies)
iPhone OS的音频技术为用户提供了丰富的音频体验。它包括音频回放,高质量的录音和触发设备的振动功能等。iPhone OS的音频技术支持如下音频格式:AAC、Apple Lossless(ALAC)、A-law、IMA/ADPCM(IMA4)、Linear PCM、μ-law和Core Audio等。
① 核心音频(Core Audio Family)
核心音频框架家族(Core Audio family of frameworks)提供了音频的本地支持,如表16-1所示。Core Audio是一个基于C语言的接口,并支持立体声(Stereo Audio)。开发能采用iPhone OS 的Core Audio框架在iPhone 应用中产生、录制、混合和播放音频。开发者也能通过核心音频访问手机设备的振动功能。核心音频框架:
框架(Framework) | 服务(Service) |
CoreAudio.framework | 定义核心音频的音频数据类型 |
AudioUnit.framework | 提供音频和流媒体文件的 回放和录制,并且管理音 频文件和播放提示声音 |
AudioToolbox.framework | 提供使用内置音频单元服务, 音频处理模块 |
② OpenAL
iPhone OS 也支持开放音频库(Open Audio Library, OpenAL)。OpenAL是一个跨平台的标准,它能传递位置音频(Positional Audio)。开发者能应用OpenAL在需要位置音频输出的游戏或其他应用中实现高性能、高质量的音频。由于OpenAL是一个跨平台的标准,采用OpenAL的代码模块可以平滑地移植到其他平台。
(3)视频技术(Video Technologies)
iPhone OS通过媒体播放框架(MediaPlayer.framework)支持全屏视频回放。媒体播放框架支持的视频文件格式包括.mov, .mp4,.m4v和.3gp,并应用如下压缩标准:
① H.264 Baseline Profile Level 3.0 video,在30 f/s 的情况下分辨率达到640×480像素。注意:不支持B frames;
② MPEG4规范的视频部分;
③ 众多的音频格式,包含在音频技术的列表里,如AAC、Apple Lossless (ALAC)、A-law、IMA/ADPCM(IMA4)、线性PCM、μ-law和Core Audio等。
Cocoa Touch
是Objective-C的API, 其中最核心的部分是UIKit.Framework,应用程序界面上的各种组件,全是由它来提供呈现的,除此之外它还负责处理屏幕上的多点触摸事件,文字的输出,图片,网页的显示,相机或文件的存取,以及加速感应的部分等。具体介绍如下:
(1)UIKit框架(UIKit.framework)
包含Objective-C程序接口,提供实现图形,事件驱动的iPhone应用的关键架构。 iPhone OS中的每一个应用采用这个框架实现如下核心功能:
- 应用管理;
- 支持图形和窗口;
- 支持触摸事件处理;
- 用户接口管理;
- 提供用来表征标准系统视图和控件的对象;
- 支持文本和Web内容;
- 通过URL scheme与其他应用的集成。
为提供基础性代码建立应用,UIKit也支持一些与设备相关的特殊功能,如下所示:
- 加速计数据;
- 内建Camera;
- 用户图片库;
- 设备名称和模式信息。
(2)基础框架(Foundation Framework)
支持如下功能:
- Collection数据类型(包括Arrays、Sets);
- Bundles;
- 字符串管理;
- 日期和时间管理;
- 原始数据块管理;
- 首选项管理;
- 线程和循环;
- URL和Stream处理;
- Bonjour;
- 通信端口管理;
- 国际化。
(3)电话本UI框架(Address Book UI Framework)
是一个Objective-C标准程序接口,主要用来创建新联系人,编辑和选择 电话本中存在的联系人。它简化了在iPhone应用中显示联系人信息,并确保所有应用使用相同的程序接口,保证应用在不同平台的一致性。
总结:
尽可能使用高层框架,当我们要开发iPhone程序的时候,首先要现从上层入手,优先使用Objective-C封装后的库。
也就是通过 UIKit.framework搭配Foundation.framework来进行开发,而当面对一些比较复杂的功能时,像是多媒体的处理或是绘图,再往下层去找寻相关的framwork开完成。
MVC 布局
其实在 PHP,包括 java(Struts+Hibernate/Mybatis+Spring)等都有涉及,很常见的一种模式。回忆整理下:
目的:
将人机交互从核心功能中分离出来,模型model对用户来说是不可见的,用户只需要观察视图view,用户与模型的交互通过控制器controller提供的安全方法来实现 。
MVC(Model-View-Controller)将一个交互式应用程序分成3个组件
模型:包含核心功能和数据 (核心业务逻辑)
视图:向用户显示信息
控制器:处理用户输入
变更-传播机制保证了模型和用户界面之间的一致性
一个模型可对应多个视图,如果用户通过一个视图的控制器改变了模型中的数据,那么依赖于该数据的其他视图也应该反映出这样的变化。一旦模型的数据发生了变化,模型需要通知所有相关的视图做出相应的变化,一起维护数据的一致性 。
模型 model
封装了内核功能和数据,模型对于用户来说是不可见的(M与V独立),模型独立于特定输出表示或者输入方式(M与C独立) ,用户只能通过控制器操作模型(C是M与V之间的桥梁)
视图 view向用户显示信息,不同的视图使用不同的方法呈现信息,
-
每个视图组件都有一个更新函数,这个函数被模型变更通知激活,
-
被激活(此时模型已经改变)后, 将使得视图重新和模型一致。
-
在初始化阶段,视图向模型登记请求变更通知(表),
-
从模型获得数据
-
通过状态查询函数实现。
例如:定时刷新
控制器 controller
每个视图有一个相关的控制器组件(一一对应),控制器组件接受事件,并翻译成输入,事件如何发送到控制器由用户界面平台决定,事件被翻译成为对模型或者视图的请求,如果控制器的行为依赖于模型的状态,那么控制器也需要向模型登记请求变更通知。
例如:用户点击按钮,按钮的事件响应函数将采取相应的措施处理用户要求,用户仅仅通过控制器与系统交互