MVC框架

iOS 专栏收录该内容
252 篇文章 1 订阅

就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的“奴才”)


接着前面的小飞机,View就是:你的小飞机是什么样子的,有一个还是两个翅膀,有几挺枪炮;还有,你的飞机在屏幕上的位置等等。总之,你在屏幕上看到的组件都可以归类为View。



MVC全名是Model View Controller,是模型(model)-视图(view)-控制器(controller)的缩写,一种软件设计典范,用一种业务逻辑、数据、界面显示分离的方法组织代码,将业务逻辑聚集到一个部件里面,在改进和个性化定制界面及用户交互的同时,不需要重新编写业务逻辑。MVC被独特的发展起来用于映射传统的输入、处理和输出功能在一个逻辑的图形化用户界面的结构中。
外文名
MVC框架
全    名
Model View Controller
产生时间
1982年
架构内容
视图,模型,控制器
类    别
软件构件模式

简介编辑

MVC开始是存在于桌面程序中的,M是指业务模型,V是指 用户界面,C则是控制器,使用MVC的目的是将M和V的实现代码分离,从而使同一个程序可以使用不同的表现形式。比如一批统计数据可以分别用 柱状图饼图来表示。C存在的目的则是确保M和V的同步,一旦M改变,V应该同步更新。 [1-2]  
模型-视图-控制器( MVC)是 Xerox PARC在二十世纪八十年代为编程语言Smalltalk-80发明的一种 软件设计模式,已被广泛使用。后来被推荐为 Oracle旗下 Sun公司 Java EE平台的设计模式,并且受到越来越多的使用 ColdFusionPHP的开发者的欢迎。模型-视图-控制器模式是一个有用的 工具箱,它有很多好处,但也有一些缺点。 [3]  
(概述内容来源: [4]   )

MVC 编程模式编辑

MVC 是一种使用 MVC(Model View Controller 模型-视图-控制器)设计创建 Web 应用程序的模式: [1]  
  • Model(模型)表示应用程序核心(比如数据库记录列表)。
  • View(视图)显示数据(数据库记录)。
  • Controller(控制器)处理输入(写入数据库记录)。
MVC 模式同时提供了对 HTML、CSS 和 JavaScript 的完全控制。
Model(模型)是应用程序中用于处理应用程序数据逻辑的部分。
  通常模型对象负责在数据库中存取数据。
View(视图)是应用程序中处理数据显示的部分。
  通常视图是依据模型数据创建的。
Controller(控制器)是应用程序中处理用户交互的部分。
  通常控制器负责从视图读取数据,控制用户输入,并向模型发送数据。
MVC 分层有助于管理复杂的应用程序,因为您可以在一个时间内专门关注一个方面。例如,您可以在不依赖业务逻辑的情况下专注于视图设计。同时也让应用程序的测试更加容易。
MVC 分层同时也简化了分组开发。不同的开发人员可同时开发视图、控制器逻辑和业务逻辑。

框架内容编辑

MVC是一个框架模式,它强制性的使应用程序的输入、处理和 输出分开。使用MVC应用程序被分成三个核心部件:模型、 视图、控制器。它们各自处理自己的任务。最典型的MVC就是JSP +  servlet +  javabean的模式。 [5]  

视图

视图是用户看到并与之交互的界面。对老式的Web应用程序来说,视图就是由 HTML元素组成的界面,在新式的Web应用程序中, HTML依旧在视图中扮演着重要的角色,但一些新的技术已层出不穷,它们包括 Adobe Flash和像 XHTMLXML/ XSL, WML等一些标识语言和 Web services.
MVC好处是它能为应用程序处理很多不同的 视图。在视图中其实没有真正的处理发生,不管这些数据是联机存储的还是一个雇员列表,作为视图来讲,它只是作为一种输出数据并允许用户操纵的方式。 [6]  

模型

模型表示企业数据和业务规则。在MVC的三个部件中,模型拥有最多的处理任务。例如它可能用像 EJBs和ColdFusion Components这样的构件对象来处理数据库,被模型返回的数据是中立的,就是说模型与数据格式无关,这样一个模型能为多个视图提供数据,由于应用于模型的代码只需写一次就可以被多个视图重用,所以减少了代码的重复性。 [6]  

控制器

控制器接受用户的输入并调用模型和视图去完成用户的需求,所以当单击Web页面中的超链接和发送 HTML表单时,控制器本身不输出任何东西和做任何处理。它只是接收请求并决定调用哪个模型构件去处理请求,然后再确定用哪个视图来显示返回的数据。 [6]  

区别编辑

框架和设计模式的区别
有很多程序员往往把框架模式和设计模式混淆,认为MVC是一种设计模式。实际上它们完全是不同的概念。 [7]  
框架、设计模式这两个概念总容易被混淆,其实它们之间还是有区别的。框架通常是代码重用,而设计模式是设计重用,架构则介于两者之间,部分代码重用,部分设计重用,有时分析也可重用。在软件生产中有三种级别的重用:内部重用,即在同一应用中能公共使用的抽象块;代码重用,即将通用模块组合成库或工具集,以便在多个应用和领域都能使用;应用框架的重用,即为专用领域提供通用的或现成的基础结构,以获得最高级别的重用性。
框架与设计模式虽然相似,但却有着根本的不同。设计模式是对在某种环境中反复出现的问题以及解决该问题的方案的描述,它比框架更抽象;框架可以用代码表示,也能直接执行或复用,而对模式而言只有实例才能用代码表示;设计模式是比框架更小的元素,一个框架中往往含有一个或多个设计模式,框架总是针对某一特定应用领域,但同一模式却可适用于各种应用。可以说,框架是软件,而设计模式是软件的知识。
框架模式有哪些?
MVC、MTV、 MVP、CBD、 ORM等等;
框架有哪些?
C++语言的QT、MFC、gtk,Java语言的 SSH 、 SSIphp语言的 smarty(MVC模式), python语言的django(MTV模式)等等
设计模式有哪些?
工厂模式、适配器模式、策略模式等等
简而言之:框架是大智慧,用来对软件设计进行分工;设计模式是小技巧,对具体问题提出解决方案,以提高代码复用率,降低耦合度。

常见框架编辑

Struts

StrutsApache软件基金下Jakarta项目的一部分。Struts框架的主要架构设计和开发者是Craig R.McClanahan。Struts 是Java Web MVC框架中不争的王者。经过长达九年的发展,Struts已经逐渐成长为一个稳定、成熟的框架,并且占有了MVC框架中最大的市场份额。但是Struts某些技术特性上已经落后于新兴的MVC框架。面对 Spring MVC、Webwork2这些设计更精密,扩展性更强的框架,Struts受到了前所未有的挑战。但站在产品开发的角度而言,Struts仍然是最稳妥的选择。
Struts有一组相互协作的类(组件)、 Servlet以及jsp tag lib组成。基于struts构架的web应用程序基本上符合JSP Model2的设计标准,可以说是MVC设计模式的一种变化类型。根据上面对framework的描述,很容易理解为什么说Struts是一个web framework,而不仅仅是一些标记库的组合。但 Struts 也包含了丰富的标记库和独立于该框架工作的实用程序类。Struts有其自己的控制器( Controller),同时整合了其他的一些技术去实现模型层( Model)和视图层(View)。在模型层,Struts可以很容易的与数据访问技术相结合,包括 EJBJDBC和Object Relation Bridge。在视图层,Struts能够与JSP, Velocity Templates,XSL等等这些表示层组件相结合。 [8]  

Spring

Spring实际上是Expert One-on-One J2EE Design and Development 一书中所阐述的设计思想的具体实现。在One-on-One 一书中, Rod Johnson倡导 J2EE实用主义的 设计思想,并随书提供了一个初步的开发框架实现(interface21 开发包)。而Spring 正是这一思想的更全面和具体的体现。Rod Johnson 在interface21 开发包的基础之上,进行了进一步的改造和扩充,使其发展为一个更加开放、清晰、全面、高效的开发框架。
Spring是一个开源框架,由Rod Johnson创建并且在他的著作《J2EE设计开发编程指南》里进行了描述。它是为了解决企业应用开发的复杂性而创建的。Spring使使用基本的JavaBeans来完成以前只可能由EJB完成的事情变得可能了。然而,Spring的用途不仅限于服务器端的开发。从简单性、可测试性和松耦合的角度而言,任何Java应用都可以从Spring中受益。
简单来说,Spring是一个轻量的控制反转和面向切面的容
框架。当然,这个描述有点过于简单。但它的确概括出了Spring是做什么的。 [8]  

ZF

Zend Framework(简写ZF)是由 Zend 公司支持开发的完全基于 PHP5 的开源PHP开发框架,可用于开发 Web 程序和服务,ZF采用 MVC(Model–View-Controller) 架构模式来分离应用程序中不同的部分方便程序的开发和维护。
(MVC框架的详细使用及其相关具体操作可以阅读参考资料: [8]   或者扩展阅读第二,三,四条。)

.NET

.NET MVC [9]    是微软官方提供的以MVC模式为基础的.NET Web应用程序(Web Application)框架,它由Castle的 MonoRail而来(Castle的MonoRail是由java而来),目前最新版本是.N 4.5。 [10]  

特点编辑

优点

耦合性
视图层和业务层分离,这样就允许更改视图层代码而不用重新编译模型和控制器代码,同样,一个应用的业务流程或者业务规则的改变只需要改动MVC的模型层即可。因为模型与控制器和视图相分离,所以很容易改变应用程序的数据层和业务规则。
模型是自包含的,并且与控制器和视图相分离,所以很容易改变应用程序的数据层和业务规则。如果把数据库从MySQL移植到 Oracle,或者改变基于RDBMS数据源到 LDAP,只需改变模型即可。一旦正确的实现了模型,不管数据来自数据库或是LDAP服务器,视图将会正确的显示它们。由于运用MVC的应用程序的三个部件是相互独立,改变其中一个不会影响其它两个,所以依据这种设计思想能构造良好的 松耦合的构件。 [11]  
重用性高
随着技术的不断进步,需要用越来越多的方式来访问应用程序。 MVC模式允许使用各种不同样式的视图来访问同一个服务器端的代码,因为多个视图能共享一个模型,它包括任何WEB(HTTP)浏览器或者无线浏览器(wap),比如,用户可以通过电脑也可通过手机来订购某样产品,虽然订购的方式不一样,但处理订购产品的方式是一样的。由于模型返回的数据没有进行格式化,所以同样的构件能被不同的界面使用。例如,很多数据可能用HTML来表示,但是也有可能用WAP来表示,而这些表示所需要的命令是改变视图层的实现方式,而控制层和模型层无需做任何改变。由于已经将数据和业务规则从表示层分开,所以可以最大化的重用代码了。模型也有状态管理和数据持久性处理的功能,例如,基于会话的购物车和电子商务过程也能被Flash网站或者无线联网的应用程序所重用。 [11]  
生命周期 成本低
MVC使开发和维护用户 接口的技术含量降低。
部署快
使用MVC模式使开发时间得到相当大的缩减,它使程序员(Java开发人员)集中精力于业务逻辑,界面程序员(HTML和JSP开发人员)集中精力于表现形式上。
可维护性高
分离视图层和业务逻辑层也使得WEB应用更易于维护和修改。
有利软件工程化管理
由于不同的层各司其职,每一层不同的应用具有某些相同的特征,有利于通过工程化、工具化管理程序代码。控制器也提供了一个好处,就是可以使用控制器来联接不同的模型和视图去完成用户的需求,这样控制器可以为构造应用程序提供强有力的手段。给定一些可重用的模型和视图,控制器可以根据用户的需求选择模型进行处理,然后选择视图将处理结果显示给用户。 [12-13]  

缺点

没有明确的定义
完全理解MVC并不是很容易。使用MVC需要精心的计划,由于它的内部原理比较复杂,所以需要花费一些时间去思考。同时由于模型和视图要严格的分离,这样也给调试应用程序带来了一定的困难。每个构件在使用之前都需要经过彻底的测试。
不适合小型,中等规模的应用程序
花费大量时间将MVC应用到规模并不是很大的应用程序通常会得不偿失。
增加系统结构和实现的复杂性
对于简单的界面,严格遵循MVC,使模型、视图与控制器分离,会增加结构的复杂性,并可能产生过多的更新操作,降低运行效率。
视图与控制器间的过于紧密的连接
视图与控制器是相互分离,但却是联系紧密的部件,视图没有控制器的存在,其应用是很有限的,反之亦然,这样就妨碍了他们的独立重用。
视图对模型数据的低效率访问
依据模型操作接口的不同,视图可能需要多次调用才能获得足够的显示数据。对未变化数据的不必要的频繁访问,也将损害操作性能。
一般高级的界面工具或构造器不支持模式
改造这些工具以适应MVC需要和建立分离的部件的代价是很高的,会造成MVC使用的困难。 [12-13]  

外界评价编辑

根据天极网资料显示:基于Web的MVC framework在J2EE的世界内已是空前繁荣, TTS网站上几乎每隔一两个星期就会有新的MVC框架发布,比较好的MVC,老牌的有Struts、Webwork。新兴的MVC 框架有Spring MVC、Tapestry、JSF等。这些大多是著名团队的作品,另外还有一些边缘团队的作品,也相当出色,如Dinamica、 VRaptor等,这些框架都提供了较好的层次分隔能力,在实现良好的MVC 分隔的基础上,通过提供一些现成的辅助类库,同时也促进了生产效率的提高。 [8]  
如何选择一个好的框架应用在项目中,将会对项目的效率和可重用是至关重要的。 [8]  

MVC控件编辑

ASP  .NET MVC框架中没有了自己的控件,页面显示完全就回到了写 html代码的年代。还好在 asp .net mvc框架中也有自带的HtmlHelper和UrlHelper两个帮助类。另外在MvcContrib扩展项目中也有扩展一些帮助类,这样我们就不光只能使用完整的html来编写了需要显示的页面了,就可以使用这些帮助类来完成,但最后运行时都还是要生成html代码的。
HtmlHelper类
HtmlHelper类位于System.Web.MVC.Html命名空间下。主要包括FormExtensions,InputExtensions,
  LinkExtensions,SelectExtensions,TextAreaExtensions,ValidationExtensions,RenderPartialExtensions等7个静态类,他们全部是是采用拓展方法来实现的。
InputExtensions类:主要有5种类型的扩展方法,分别用于CheckBox控件、Hidden控件、Pass控件、RadionButton控件和TextBox控件
LinkExtensions类:该类主要用于生成相关链接,主要扩展了ActionLink和RouteLink方法。
ActionLink:扩展方法主要实现一个连接,共有十个重载方法。
UrlHelper帮助类
看类名也都知道这个类是用来成URL在 ASP .NET MVC应用程序中。
UrlHelper提供了四个非常常用的四个方法。
1.Action方法通过提供Controller,Action和各种参数生成一个URL,
2.Content方法是将一个虚拟的,相对的路径转换到应用程序的绝对路径,
3.Encode方法是对URL地址进行加密,与Server.Encode方法一样。
4.RouteUrl方法是提供在当前应用程序中规定的路由规则中匹配出URL。
另外还有两个属性,分别是RequestContext和RouteCollection两个属性,分别指的是包含HTTP上下文和RouteData两个属性,另外,RouteCollection是整个当前应用程序中规定的路由规则。
自定义控件
微软提供的HtmlHelper已经是足够大部分开发人员使用了,但是有一些功能要用微软提供的HtmlHelper可能还不满足要求。接下来就谈谈如何自定义的过程。
首先自定义的方法就是对HtmlHelper对象的扩展。
扩展方法实现的三要素:1、静态类 2、静态方法 3、this关键字
1、先定义一个类,例如:MyHtmlHelper:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace MvcApplicationFirstDome.Models {
//静态类
public static class MyHtmlHelper
{
//静态方法
}
}
2、假设要扩展的方式是GetSpan,作用就是当你传入参数时,内部封装了之后返回结果,代码如下。注意在MyHtmlHelper类中要引用using System.Web.Mvc命名空间。
//静态方法
public static string GetSpan(this HtmlHelper htmlHelper,string text)
{
return "<span style='color:Red'>"+text+"</span>";
}
经过上面两步之后HtmlHelper的扩展方法GetSpan基本可以使用了,接下来就讲解如何在页面调用了。
在调用的时候要注意下一命名空间:如果扩展方法的命名空间和页面的命名空间不同的就必须引用扩展方法的 命名空间,否则在页面是没有办法调用自定义的方法的。
引用完命名空间之后,就可以在相应的页面调用自定义的扩展方法了。
对于某些项目来说,自定义控件过于复杂和浪费时间。这个时候也可以从技术社区或是源代码站下载适合自己需求的Mvc控件。如一些控件套包,表格控件等。



一、要求

要求完成下面一个小的应用程序。

 

二、一步步对代码进行优化

注意:在开发过程中,优化的过程是一步一步进行的。(如果一个人要吃五个包子才能吃饱,那么他是否直接吃第五个,前面四个不用吃就饱了?)

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)三个部分各司其职,数据模型只负责数据的处理,视图部分只负责把拿到的数据进行显示,两个部分都是被动的,等待着大管家控制器的调遣。

(3)在OC中,如果视图和数据模型之间有通道,那控制器是否处于失控状态呢?



       接触iOS手机开发有一段时间了。总体来说,苹果公司设计的开发环境还是非常人性化的。很容易上手,也方便深入。

       在组织大型项目的代码文件时,我们常用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、M层 模型(更多的是数据库模型)
(1)创建数据库、创建相应的表
(2)完成针对数据库各个表的增、删、改、查的操作类
(3)映射数据库各个表的实体类(这个实体类的作用就是沟通数据库层(M)和控制层(C)的桥梁,同时这个实体类也将担负其后台数据(xml、json等)与本地数据的沟通和存储)

  本层要实现的功能:

  (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的质量以节省内存。


 
iOS  设计模式 - 你可能已经听说过这个词,但是你真正理解它意味着什么吗?虽然大多数的开发者可能都会认为设计模式是非常重要的,然而关于设计模式这一主题的文章却不多,并且有时候我们开发者在写代码的时候也不会太关注它。  
在软件设计领域,设计模式是对通用问题的可复用的解决方案。设计模式是一系列帮你写出更可理解和复用代码的模板,设计模式帮你创建松耦合的代码以便你不需要费多大力就可以改变或者替换代码中的组件。  
如果你刚接触设计模式,我们有好消息告诉你!首先,多亏了 Cocoa 的构建方式,你已经使用了许多的设计模式以及被鼓励的最佳实践。
其次本指南将带你使用绝大多数(并不是所有) Cocoa 中频繁使用的 IOS  设计模式。  
本指南被分为了许多部分,每个部分涉及一个设计模式。在每个部分中,你将会了解到如下内容:
•       设计模式是什么?
•       你为什么要用设计模式?
•       如何使用设计模式,以及在使用的时候,哪里是合适的,哪里是需要注意的坑。
在本指南中,你将创建一个音乐库应用,这个应用将显示你的专辑以及它们相关联的信息。
在开发本应用的过程中,你将熟悉被大量使用的 Cocoa  设计模式:
•       创建型:单利(单态)和   抽象工厂
•       结构型:模型 - 视图 - 控制器,装饰器,适配器,外观(门面 ) 和组合模式
•       行为型:观察者,备忘录,责任链和命令模式
不要被误导认为这是一篇关于设计模式理论的文章,在本音乐应用中,你将使用这些设计模式中的大多数,最终你的音乐应用将长的像下图所示的那样:


 
我们开始吧!
下载   starter project , 导出 zip 文件的内容,然后用 xcode 打开 BlueLibrary.xcodeproj.
工程里面没有太多的文件,仅仅包含缺省的 ViewController 以及空实现的 HTTP Client.
注意:当你创建一个新的 Xcode 工程的时候,你的代码其实已经涉及到了设计模式,你知道吗?模型 - 视图 - 控制器,委托,协议,单例 - 你不费吹灰之力就可以免费使用它们啦。
在你深入到第一个设计模式之前,你首先必须创建两个类,用这两个类去保存和显示音乐库专辑的信息。
Xcode 中,导航到 "File\New\File..." (或者按 Command+N 快捷键),选择 IOS>Cocoa Touch, 然后 Objective-C class ,点击下一步。设置类名称为 Album ,父类选择 NSObject ,点击下一步,然后创建。  
打开 Album.h 文件,在 @interface @end 之间,增加如下的属性和方法原型:
Objective -c代码   收藏代码
  1. @property (nonatomic, copy, readonly) NSString *title, *artist, *genre, *coverUrl, *year;    
  2. - (id)initWithTitle:(NSString*)title artist:(NSString*)artist coverUrl:(NSString*)coverUrl year:(NSString*)year;  
 

注意到新增代码中所有的属性都是只读的,因为在 Album 对象创建以后,不需要修改它们的值。
新增的方法是对象初始化器( object initializer), 当你创建一个新的专辑( album )对象的时候,你需要传递专辑( album) , 艺术家,专 辑封面URL ,以及年份。
现在打开 Album.m 文件,在 @implementation    @end  之间   增加如下代码:
Objective-c代码   收藏代码
  1. - (id)initWithTitle:(NSString*)title artist:(NSString*)artist coverUrl:(NSString*)coverUrl  
  2.   year:(NSString*)year {  
  3.     self = [super init];  
  4.     if (self)  
  5.     {  
  6.         _title = title;  
  7.         _artist = artist;  
  8.         _coverUrl = coverUrl;  
  9.         _year = year;  
  10.         _genre = @"Pop";  
  11.     }  
  12.     return self;  
  13. }  
 
这里没什么复杂花哨的东西,仅仅是一个创建 Album 实例的初始化方法而已。
Xcode 中,再一次导航到 "File\New\File..." 选择 Cocoa Touch ,然后 Objective-C class, 点击下一步。设置类名为 AlbumView, 但是这一 次设置父类为UIView 。点击下一步然后点击创建。
      注意 :如果你发现键盘快捷键更容易使用, Command+N 将创建一个新文件, Command+Option+N 将创建一个新组, Command+B 将构建你的工程, Command + R  将运行它。
现在打开 AlbumView.h ,在 @interface    @end 之间   增加如下的方法原型:
Objective-c代码   收藏代码
  1. - (id)initWithFrame:(CGRect)frame   albumCover:(NSString*)albumCover;  
现在打开 AlbumView.m ,用如下代码替换 @implementation  之后所有的代码:
Objective-c代码   收藏代码
  1. @implementationAlbumView  
  2. {  
  3.     UIImageView *coverImage;  
  4.     UIActivityIndicatorView *indicator;  
  5. }  
  6.    
  7. - (id)initWithFrame:(CGRect)frame albumCover:(NSString*)albumCover  
  8. {  
  9.     self = [super initWithFrame:frame];  
  10.     if (self)  
  11.     {  
  12.    
  13.         self.backgroundColor = [UIColor blackColor];  
  14.         // the coverImage has a 5 pixels margin from its frame  
  15.         coverImage = [[UIImageView alloc] initWithFrame:CGRectMake(55, frame.size.width-10,  
  16.    
  17.         frame.size.height-10)];  
  18.         [self addSubview:coverImage];  
  19.    
  20.         indicator = [[UIActivityIndicatorView alloc] init];  
  21.         indicator.center = self.center;  
  22.         indicator.activityIndicatorViewStyle = UIActivityIndicatorViewStyleWhiteLarge;  
  23.         [indicator startAnimating];  
  24.         [self addSubview:indicator];  
  25.     }  
  26.     return self;  
  27. }  
  28.    
  29. @end  
 

    上面的代码里,你首先需要注意的是 coverImage 实例变量。它表示这个专辑的封面图。第二个变量是一个通过旋转来指示封面图正在下载的指示器。
在初始化器的实现中你设置背景颜色为黑色,创建了有 5 像素边框的图片视图,同时还创建了指示器。 
注意: 你可能想知道为什么私有变量在实现文件中定义,而不是在接口文件中?这是因为 AlbumView 以外的类不需要知道这些变量的存在,这些变量仅仅只在类内部函数使用。如果你在开发给其它开发者使用的框架,这个约定就显得十分重要了。
构建( Command + B )你的工程确保每件事情都井井有条,都 ok 吗?然后准备迎接我们的第一个设计模式! 
模型-视图-控制器(MVC)模式 - 设计模式之王
 
 


 
 
模型 - 视图 - 控制器( MVC)  Cocoa 的构建块之一,毫无疑问它是使用最频繁的设计模式。它根据通用的角色去划分类,这样就使得类的
职责可以根据角色清晰的划分开来。
  涉及到的三个角色如下:
              Model:
模型保存应用程序的数据,定义了怎么去操作它。例如在本应用中模型就是Album 类。
          View:  
视图是模型的可视化表示以及用户交互的控件;基本上来说,所有的UIView 对象以及它的子类都属于视图。在本应用中AlbumView 代表了视图。
        Controller:
 控制器是一个协调所有工作的中介者(Mediator )。它访问模型中的数据并在视图中展示它们,同时它们还监听事件和根据需要操作数据。你可以猜猜哪个类是控制器吗?它正是:ViewController
一个 MVC 模式的好的实现也就意味着每一个对象都会被划分到上面所说的组中。
      我们可以很好的用下图来描述通过控制器实现的视图到模型的交互过程:


 
   
模型会把任何数据的变更通知控制器,然后控制器更新视图数据。视图对象通知控制器用户的操作,控制器要么根据需要来更新模型,要么检索任何被请求的数据。
      你可能在想为什么不能仅仅使用控制器,在一个类中实现视图和模型,这样貌似更加容易
      所有的这些都归结于代码关注点分离以及复用。在理想的状态下,视图应该和模型完全的分离。如果视图不依赖某个实际的模型,那么视图就可以被复用来展示不同模型的数据。
      举个例子来说,如果将来你打算加入电影或者书籍到你的资料库中,你仍然可以使用同样的 AlbumView 去显示电影和书籍数据。更进一步来说,如果你想创建一个新的与专辑有关联的工程,你可以很简单的复用 Album 类,因为它不依赖任何视图。这就是 MVC 的强大之处。
如何使用MVC模式
首先,你需要确保在你工程中的每个类是控制器,模型和视图中的一种,不要在一个类中组合两种角色的功能。到目前为止,你创建了一个 Album 类和 AlbumView 类,这样做挺好的。
其次,为了确保你能符合这种工作方法,你应该创建三个工程组( Project Group )来保存你的代码,每个工程组只存放一种类型的代码。
导航到 " 文件 \ 新建 \ 组( File\New\Group " (或者按下 Command + Option + N ),命名组为 Model ,重复同样的过程来创建 View Controller 组。
现在拖动 Album.h Album.m 去模型组,拖动 AlbumView.h AlbumView.m 去视图组,最后拖动 ViewController.h ViewController.m 到控制器组。
此时工程结构应该看起来和下图类似:
 


 
 
没有了之前所有文件都散落在各处,现在你的工程已经开起来好多了。显然你也可以有其它的组和类,但是本应用的核心包含在这三个类别中( Model,View,Controller )。
现在所有的组件都已经安排好了,你需要从某处获取专辑数据。你将创建一个贯穿于代码的管理数据的 API- 这也就代表将有机会去讨论下一个设计模式  -  单例(单态)模式。  
单例(单态)模式
单例设计模式确保对于一个给定的类只有一个实例存在,这个实例有一个全局唯一的访问点。它通常采用懒加载的方式在第一次用到实例的时候再去创建它。
注意 :苹果大量使用了此模式。例如: [NSUserDefaults standardUserDefaults] , [UIApplication sharedApplication] ,  [UIScreen mainScreen] ,  [NSFileManager defaultManager] ,所有的这些方法都返回一个单例对象。
你很可能会想为什么这么关心是否一个类有多个实例?毕竟代码和内存都是廉价的,对吗?  
有一些情况下,只有一个实例显得非常合理。举例来说,你不需要有多个 Logger 的实例,除非你想去写多个日志文件。或者一个全局的配置处理类:实现线程安全的方式访问共享实例是容易的,比如一个配置文件,有好多个类同时修改这个文件。
如何使用单例模式
首先来看看下面的图:


 
 
上面的图描述了一个有单一属性(它就是单一实例)和 sharedInstance,init 两个方法的类。
客户端第一次发送 sharedInstance 消息的时候, instance 属性尚未被初始化,所以此时你需要创建一个新的实例,然后返回它的引用。
当你下一次调用 sharedInstance 的时候, instance 不需要任何初始化可以立即返回。这个逻辑保证总是只有一个实例。
你接下来将用这个模式来创建一个管理所有专辑数据的类。
你将注意到工程中有一个 API 的组,在这个组里你可以放入给你应用提供服务的所有类。在此组中,用 IOS\Cocoa Touch\Objective-C class  模板创建一个新类,命名它为 LibraryAPI, 设置父类为 NSObject.
打开 LibraryAPI.h ,用如下代码替换它的内容:
Objective-c代码   收藏代码
  1. @interfaceLibraryAPI : NSObject  
  2.    
  3. + (LibraryAPI*)sharedInstance;  
  4.    
  5. @end  
 
现在打开 LibraryAPI.m ,在 @implementation  那一行后面插入下面的方法:
Objective-c代码   收藏代码
  1. + (LibraryAPI*)sharedInstance  
  2. {  
  3.     // 1  
  4.     static LibraryAPI *_sharedInstance = nil;  
  5.    
  6.     // 2  
  7.     static dispatch_once_t oncePredicate;  
  8.    
  9.     // 3  
  10.     dispatch_once(&oncePredicate, ^{  
  11.         _sharedInstance = [[LibraryAPI alloc] init];  
  12.     });  
  13.     return _sharedInstance;  
  14. }  
 
在这个简短的方法中,有一些需要需要注意的点:
1. 声明一个静态变量去保存类的实例,确保它在类中的全局可用性。
2. 声明一个静态变量 dispatch_once_t , 它确保初始化器代码只执行一次
3. 使用 Grand Central Dispatch(GCD) 执行初始化 LibraryAPI 变量的 block.    正是单例模式的关键:一旦类已经被初始化,初始化器永远不会再被调用。
下一次你调用 sharedInstance 的时候, dispatch_once 块中的代码将不会执行(因为它已经被执行了一次),你将得到原先已经初始化好的实例。  
注意 :  为了学习更多关于 GCD 方面的信息以及如何使用,请查看本站指南 Multithreading and Grand Central Dispatch     How to Use Blocks
你现在有一个单例的对象作为管理专辑数据的入口。咋们更进一步来创建一个处理资料库数据持久化的类。
API 组中,使用 iOS\Cocoa Touch\Objective-C class  模板   创建一个新类,命名它为 PersistencyManager, 设置父类为 NSObject.
打开 PersistencyManager.h  在文件头部增加下面的导入语句:
#import "Album.h"  
接下来,在 PersistenceManager.h 文件的 @interface 之后,增加下面的代码:
Objective-c代码   收藏代码
  1. - (NSArray*)getAlbums;  
  2. - (void)addAlbum:(Album*)album atIndex:(int)index;  
  3. - (void)deleteAlbumAtIndex:(int)index;  
 

上面是你需要处理专辑数据的方法的原型。  
打开 PersistencyManager.m 文件,在 @implementation 行之前,增加下面的代码:
Objective-c代码   收藏代码
  1. @interfacePersistencyManager () {  
  2.     // an array of all albums  
  3.     NSMutableArray *albums;  
  4. }  
 
上面增加了一个类扩张( class extension ),这是另外一个增加私有方法和变量以至于外部类不会看到它们的方式。这里,你申明了一个数组 NSMutableArry  来保存专辑数据。这个数组是可变的方便你增加和删除专辑。
现在在 PersistencyManager.m 文件中 @implementation 行之后增加如下代码:
Objective-c代码   收藏代码
  1. - (id)init  
  2. {  
  3.     self = [super init];  
  4.     if (self) {  
  5.         // a dummy list of albums  
  6.         albums = [NSMutableArrayarrayWithArray:  
  7.                  @[[[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"],  
  8.                  [[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"],  
  9.                  [[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"],  
  10.                  [[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"],  
  11.                  [[Album alloc] initWithTitle:@"American Pie" artist:@"Madonna" coverUrl:@"http://www.coversproject.com/static/thumbs/album/album_madonna_american%20pie.png" year:@"2000"]]];  
  12.     }  
  13.     return self;  
  14. }  
 
init 中,你用五条样例专辑填充数组。如果你不喜欢上面的专辑,你可以自由用你喜欢的专辑替换它们。  
现在在 PersistencyManager.m 文件中增加下面的三个方法:
Objective-c代码   收藏代码
  1. - (NSArray*)getAlbums  
  2. {  
  3.     return albums;  
  4. }  
  5.    
  6. - (void)addAlbum:(Album*)album atIndex:(int)index  
  7. {  
  8.     if (albums.count >= index)  
  9.         [albums insertObject:album atIndex:index];  
  10.     else  
  11.         [albums addObject:album];  
  12. }  
  13.    
  14. - (void)deleteAlbumAtIndex:(int)index  
  15. {  
  16.     [albums removeObjectAtIndex:index];  
  17. }  
 
这些方法让你可以增加和删除专辑。
构建你的工程确保每个资源都可以被正确的编译。
这时候,你可能想知道 PersistencyManager 类来自哪里?因为它不是一个单例类。下一部分,我们将探究 LibraryAPI  PersistencyManager 之间的关系,那时候你将看到门面或者外观( Facade )模式。

注:突然冒出个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各部分的职责。


自始至终没间Model的面,其实M是可选的,特别是对于简单的应用。任何与界面无关的,我们添加的自定义类来定义我们的应用程序的对象,都属于Model的范畴。

iOS开发之理解iOS中的MVC设计模式

柳志超博客 » Program » IOS » iOS开发之理解iOS中的MVC设计模式

posted in  IOS on  2013/01/03 by  liuzc

模型-视图-控制器(Model-View-Controller,MVC)是Xerox PARC在20世纪80年代为编程语言Smalltalk-80发明的一种软件设计模式,至今已广泛应用于用户交互应用程序中。在iOS开发中MVC的机制被使用的淋漓尽致,充分理解iOSMVC模式,有助于我们程序的组织合理性。

model_view_controller
模型对象
模型对象封装了应用程序的数据,并定义操控和处理该数据的逻辑和运算。例如,模型对象可能是表示游戏中的角色或地址簿中的联系人。用户在视图层中所进行的创建或修改数据的操作,通过控制器对象传达出去,最终会创建或更新模型对象。模型对象更改时(例如通过网络连接接收到新数据),它通知控制器对象,控制器对象更新相应的视图对象。
视图对象
视图对象是应用程序中用户可以看见的对象。视图对象知道如何将自己绘制出来,并可能对用户的操作作出响应。视图对象的主要目的,就是显示来自应用程序模型对象的数据,并使该数据可被编辑。尽管如此,在 MVC 应用程序中,视图对象通常与模型对象分离。

在iOS应用程序开发中,所有的控件、窗口等都继承自 UIView,对应MVC中的V。UIView及其子类主要负责UI的实现,而UIView所产生的事件都可以采用委托的方式,交给UIViewController实现。
控制器对象
在应用程序的一个或多个视图对象和一个或多个模型对象之间,控制器对象充当媒介。控制器对象因此是同步管道程序,通过它,视图对象了解模型对象的更改,反之亦然。控制器对象还可以为应用程序执行设置和协调任务,并管理其他对象的生命周期。

控制器对象解释在视图对象中进行的用户操作,并将新的或更改过的数据传达给模型对象。模型对象更改时,一个控制器对象会将新的模型数据传达给视图对象,以便视图对象可以显示它。

对于不同的UIView,有相应的UIViewController,对应MVC中的C。例如在iOS上常用的UITableView,它所对应的Controller就是UITableViewController。

  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。

 




浅析iosMVC开发模式

引言

自从2007年乔布斯发布以第一代iphone至今,移动领域的终端设备已经发展到了一个新的高度,功能手机逐渐失去了主流用户的喜爱,来势汹汹的智能手机、平板电脑等移动终端已经成为了很多人每天不能缺少的生活必需品。与此同时,伴随着智能移动设备的发展,“Application”这个词也在逐渐被人们所熟知,app store的应用数量已经达到了58.5万之多,越来越多的应用开发者开始为移动设备开发应用。

什么是MVC

越来越多的开发者们专注于ios的开发,他们开发的相当一大部分应用软件都给人以美的享受,究竟是什么使得ios上的应用可以如此漂亮?因为他们使用了将代码和界面分开的开发结构框架MVC

MVC即是Model-VIew-Controller三个英文单词的缩写,中文翻译为模型视图控制器。MVC并非只有ios应用软件独有的应用开发模式,它被广泛应用在许多软件(尤其是中大型软件)的开发上。MVC把软件系统分为三个部分:ModelViewControllerModel相当于应用的底层,应用在功能上的实现完全依赖于Model,打个比方,如果是一台电脑的话,Model就是你机箱里的所有东西:cpu,内存,硬盘,显卡等的一个集合,你不必看到它们,但它们必不可少;Controller就是控制器,它控制ModelView的交互,它将MV捆绑在一起,将你的操作传达给Model,再控制View将其表现出来。View相当于电脑的图形界面,将Model的运行结果可视化地呈现给用户,你在屏幕上看到的一切都可以归类于View

cocoa中,你的程序中的每一个object(对象)都将明显地仅属于这三部分中的一个,而完全不属于另外两个。因此,用MVC开发的应用软件更易于进行维护和修改,不用因为底层的Model出了问题而去影响表层的ViewMVC虽然把三部分独立了出来,但三部分之间仍然存在联系,但就如下图所示,ModelView之间是完全独立的,两者各自运行,以Controller为桥梁进行交互,并不发生直接关联。接下来我们用下面这张图来简单讲解一下MVC之间是如何进行交互的。

MVC交流方式

如上文所讲,MV之间是双黄线,在交通法规方面我们都知道,双黄线是完全禁止超车的,MV也是,两者不存在任何直接交互。存在直接交互的只有MC之间与CV之间。首先我们来看MC的交互,如图所示,有一条绿色的箭头从C发起指向了M,代表了CM之间的交互应该首先从Controller发起,C首先向M提出自己的需求,再由M作出响应。C具有导入M头文件的API,因此C可以知晓M的一切内容,如同图中的那一条白色的虚线。再来看看相对复杂的CV之间的交互,这次我们仍然从绿色的箭头开始了解,箭头仍然由C发起,可见CV之间的交互依旧由Controller发起,但箭头起始端写了outlet一个词,意思是“输出口”,outlet可以看作是从C指向V的指针,它在C中被定义。outlet给我们提供了很大的方便,它使我们在C的内部就可以轻松准确地向V施令。C可以拥有很多的outlet,可以不止一个,这也使它可以更高效的和V进行交流。

MVC之间的交流模式(出自斯坦福大学CS193课程的课件)

接下来我们再来了解一下VC之间是如何进行交流的。V能通过三种方法与C进行交流,分别对应了链接CV的三条黄线。从左到右分别叫做数据源(data source)、委托(delegate)和目标操作(target-action)。View是不能拥有数据的,所以当需要显示数据的时候,View会发送出请求,以获得所需要的数据,这种方法就被称作数据源。第二种方法叫做委托,C把自己设置为V的委托(delegate),它让V知道:如果V想知道更多的关于将如何显示的信息的话,就向C发送delegate信息,大多数委托信息包括三种形式:“应该做吗?(should)”、“将要做(will)”和“已经做了(did)”。通过接受V发过来的delegate信息,C就会做出相应的协调和处理。第三种方法叫目标操作,图上表现得非常形象,C中会出现一个“靶子”,由V发出动作命中靶子完成操作,这一点可以更加形象地表示,“靶子”相当于我们在屏幕上看到的按钮,当我们按下按钮时,V发出了action,命中了C的目标时,C再调用相应的函数和类向M发出要求。

CMV之间的联系都是白色虚线,因此C能轻易的了解到MV中的全部信息。反过来,MCVC之间的联系是白色实线,区别于MV之间的黄色实线,原因是原则上MV虽不能直接影响C,但是当MV中的东西发生变化时,MV需要告诉C,因此,这里就需要cocoa中的KVOnotification机制,它们能将变化发送给C,区别只是notification是需要一个发送notification的对象来通知观察者,而kvo是直接通知到观察对象。

结语

MVC的低耦合性、高重用性、可维护性等优点显而易见,使得原本复杂的代码与界面的交互变得简单、清晰、明了,开发者可以把更多的精力放在前端界面的设计上,而不用绞尽脑汁去思考究竟应该如何使界面得到同步,这样减轻了设计压力,也从另一方面使用户得到更多更好的享受体验。纵观ios经典Native App的所有应用软件,几乎都具有一个很大特点,那就是“炫”。清新的画面配以简单的手势操作,颠覆着用户的思维方式,小巧精悍。

在最初的JSP网页中,像数据库查询语句这样的数据层代码和像HTML这样的表示层代码混在一起。经验比较丰富的开发者会将数据从表示层分离开来,但这通常不是很容易做到的,它需要精心地计划和不断的尝试。MVC从根本上强制性地将它们分开。尽管构造MVC应用程序需要一些额外的工作,但是它带给我们的好处是毋庸置疑的。

多个视图能共享一个模型。如今,同一个Web应用程序会提供多种用户界面,例如用户希望既能够通过浏览器来收发电子邮件,还希望通过手机来访问电子邮箱,这就要求Web网站同时能提供Internet界面和WAP界面。控制器连接不同的模型和视图去完成用户的需求,也可以构造应用程序提供强有力的手段。给定一些可重用的模型和视图,控制器可以根据用户的需求选择适当的模型机型处理,然后选择适当的视图将处理结果显示给用户。在MVC设计模式中,模型响应用户请求并返回响应数据,视图负责格式化数据并把它们呈现给用户,业务逻辑和表示层分离,同一个模型可以被不同的视图重用,所以大大提高了代码的可重用性。

过去MVC模式并不适合小型甚至中等规模的应用程序,这样会带来额外的工作量,增加应用的复杂性。但现在多数软件设计框架,能直接快速提供MVC骨架,供中小型应用程序开发,此问题不再存在。对于开发存在大量用户界面,并且逻辑复杂的大型应用程序,MVC将会使软件在健壮性、代码重用和结构方面上一个新的台阶。尽管在最初构建MVC模式框架时会花费一定的工作量,但从长远的角度来看,它会大大提高后期软件开发的效率。


好的应用需要有好的体验,MVC模式正式为了提升用户体验而诞生的一种软件开发模式,虽然分离出MVC需要巧妙的构思以及完成更多的工作,但它更有利于软件的工程化管理,不同的层各司其职,使得软件的维护以及日后的升级更加从容与方便。在飞速发展的电子领域,技术的进步如白驹过隙,MVC要想获得巩固的地位,只要能更好地解决层与层之间的分离工作,不只是移动终端,MVC模式肯定将是日后软件开发的主流。

如果数据模型和数据库上下文是建立在解决方案的.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


PS,上述三条语句,第一条语句是在第一次迁移的时候使用,以后就不用了。第二第三条语句是每次更新了实体模型都需要键入的。



什么是MVC框架

MVC (Model View Controller)本来是存在于Desktop程序中的,M是指数据模型,V是指用户界面,C则是控制器。使用MVC的目的是将M和V实现代码分离,从而使同一个程序可以使用不同的表现形式。比如一批统计数据你可以分别用柱状图、饼图来表示。C存在的目的则是确保M和V的同步,一旦M改变,V应该同步更新。
模型 - 视图 - 控制器( Model-View-Controller MVC )是 Xerox PARC 20 世纪 80 年代为编程语言 Smalltalk 80 发明的一种软件设计模式,至今已广泛应用于用户交互应用程序中。每个 MVC 应用程序都包含 Model View Controller 三部分

Model = 你的应用程序是什么,应用是一个或多个类。  View = Controller的奴才(minion)、小跟班。 Controller = 你的应用程序如何将Model显示给用户(UI逻辑),是中心是桥梁,连通Model和View view一切听从Controller的指挥,并及时将重要事件报告给Controller

MVC如何工作

MVC是一个设计模式,它强制性的使应用程序的输入、处理和输出分开。使用MVC应用程序被分成三个核心部件:模型、视图、控制器。它们各自处理自己的任务。

模型

  模型表示企业数据和业务规则。在MVC的三个部件中,模型拥有最多的处理任务。例如它可能用像EJBs和ColdFusion Components这样的构件对象来处理数据库。被模型返回的数据是中立的,就是说模型与数据格式无关,这样一个模型能为多个视图提供数据。由于应用于模型的代码只需写一次就可以被多个视图重用,所以减少了代码的重复性。

视图

  视图是用户看到并与之交互的界面。对老式的Web应用程序来说,视图就是由HTML元素组成的界面,在新式的Web应用程序中,HTML依旧在视图中扮演着重要的角色,但一些新的技术已层出不穷,它们包括Macromedia Flash和像XHTML,XML/XSL,WML等一些标识语言和Web services.
  如何处理应用程序的界面变得越来越有挑战性。MVC一个大的好处是它能为你的应用程序处理很多不同的视图。在视图中其实没有真正的处理发生,不管这些数据是联机存储的还是一个雇员列表,作为视图来讲,它只是作为一种输出数据并允许用户操纵的方式。

控制器

  控制器接受用户的输入并调用模型和视图去完成用户的需求。所以当单击Web页面中的超链接和发送HTML表单 时,控制器本身不输出任何东西和做任何处理。它只是接收请求并决定调用哪个模型构件去处理请求,然后确定用哪个视图来显示模型处理返回的数据。


从下图中,我们可以看出控制器在MVC中起到非常重要的作用,它负责视图与模型相互间的交互。当视图上有了某些操作,会通过控制器反应至模型中。如果模型中的数据有所改变或者更新,则会通过控制器,对视图进行相关界面改变。视图与模型是永远都不直接进行通信的。 [转载]iOS开发模式(一)【MVC】

iOS下的MVC

iPhone程序开发中,所有的控件、窗口等都继承自 UIView,对应MVC中的VUIView及其子类主要负责UI的实现,而UIView所产生的事件都可以采用委托的方式,交给UIViewController实现。对于不同的UIView,有相应的UIViewController,对应MVC中的C。例如在iOS上常用的UITableView,它所对应的Controller就是UITableViewController。至于MVC中的M,就需要用户根据自己的需求来实现了。

iOSsdk中已经为我们提供了许多视图组件:例如:UIViewUIViewController。这也方便开发者进行开发。同时,也对数据模型中可能使用到的一些组件进行了封装:数据库、CoreDta等,这有利于开发者迅速的建立一个基于MVC设计模式的程序。

(一)通信 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的质量以节省内存。

注:突然冒出个delegate,让人不好理解,其实他不对应xcode为我们创建的XXAppDelegate文件,此文件不属于MVC中的任何一部分,虽然与MVC有联系。

[转载]iOS开发模式(一)【MVC】

(二)iOS开发中的MVC的使用步骤

在开发程序时,我们一般按照如下几个步骤来进行:

l 定义UIViewController

l 定义UIView

l 定义Model

l MVC相互间的通信

[转载]iOS开发模式(一)【MVC】

MVC框架模式的优点

大部分Web应用程序都是用像ASP,PHP,或者CFML这样的过程化语言来创建的。它们将像数据库查询语句这样的数据层代码和像HTML这样的表示层代码混在一起。经验比较丰富的开发者会将数据从表示层分离开来,但这通常不是很容易做到的,它需要精心的计划和不断的尝试。MVC从根本上强制性的将它们分开。尽管构造MVC应用程序需要一些额外的工作,但是它给我们带来的好处是无庸质疑的。
  首先,最重要的一点是多个视图能共享一个模型,正如我所提及的,现在需要用越来越多的方式来访问你的应用程序。对此,其中一个解决之道是使用MVC,无论你的用户想要Flash界面或是 WAP 界面;用一个模型就能处理它们。由于你已经将数据和业务规则从表示层分开,所以你可以最大化的重用你的代码了。
  由于模型返回的数据没有进行格式化,所以同样的构件能被不同界面使用。例如,很多数据可能用HTML来表示,但是它们也有可能要用Macromedia Flash和WAP来表示。模型也有状态管理和数据持久性处理的功能,例如,基于会话的购物车和电子商务过程也能被Flash网站或者无线联网的应用程序所重用。
  因为模型是自包含的,并且与控制器和视图相分离,所以很容易改变你的应用程序的数据层和业务规则。如果你想把你的数据库从MySQL移植到Oracle,或者改变你的基于RDBMS数据源到LDAP,只需改变你的模型即可。一旦你正确的实现了模型,不管你的数据来自数据库或是LDAP服务器,视图将会正确的显示它们。由于运用MVC的应用程序的三个部件是相互对立,改变其中一个不会影响其它两个,所以依据这种设计思想你能构造良好的松偶合的构件。
  对我来说,控制器的也提供了一个好处,就是可以使用控制器来联接不同的模型和视图去完成用户的需求,这样控制器可以为构造应用程序提供强有力的手段。给定一些可重用的模型和视图,控制器可以根据用户的需求选择模型进行处理,然后选择视图将处理结果显示给用户。

MVC框架模式的缺点

MVC模式的缺点是由于它没有明确的定义,所以完全理解MVC模式并不是很容易。使用MVC模式需要精心的计划,由于它的内部原理比较复杂,所以需要花费一些时间去思考。开发一个MVC模式架构的工程,将不得不花费相当可观的时间去考虑如何将MVC模式运用到应用程序中,同时由于模型和视图要严格的分离,这样也给调试应用程序带来了一定的困难。每个构件在使用之前都需要经过彻底的测试。另外由于MVC模式将一个应用程序分成了三个部件,所以这意味着同一个工程将包含比以前更多的文件。
  过去MVC模式并不适合小型甚至中等规模的应用程序,这样会带来额外的工作量,增加应用的复杂性。但现在多数软件设计框架,能直接快速提供MVC骨架,供中小型应用程序开发,此问题不再存在。对于开发存在大量用户界面,并且逻辑复杂的大型应用程序,JAVA将会使软件在健壮性、代码重用和结构方面上一个新的台阶。尽管在最初构建MVC模式框架时会花费一定的工作量,但从长远的角度来看,它会大大提高后期软件开发的效率。



IOS的生态系统


IOS生态系统不仅仅是指产品,更重要的是指 iPhone/iPad/iPod/Mac +iCloud+App整个系统,包括Siri (部分设备不支持)、FaceTime、Safari、Game Center、 地图、Passbook、电话、邮件。 苹果所有移动设备都使用自己的OS,且不能更换电池,不能插内存卡,数据线连电脑后只能通过自家软件iTunes进行文件的传输,只能使用经过苹果认可的软件,且软件也只能从App Store下载,这就组成了 一个封闭的生态圈。


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 OS技术的头文件位于目录<iPhoneSDK>/usr/include/,iPhoneSDK是SDK的安装目录。 

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

每个视图有一个相关的控制器组件(一一对应),控制器组件接受事件,并翻译成输入,事件如何发送到控制器由用户界面平台决定,事件被翻译成为对模型或者视图的请求,如果控制器的行为依赖于模型的状态,那么控制器也需要向模型登记请求变更通知。

例如:用户点击按钮,按钮的事件响应函数将采取相应的措施处理用户要求,用户仅仅通过控制器与系统交互 

 


注意:多个 MVC 可以协同一起工作


  • 0
    点赞
  • 0
    评论
  • 0
    收藏
  • 打赏
    打赏
  • 扫一扫,分享海报

©️2022 CSDN 皮肤主题:大白 设计师:CSDN官方博客 返回首页

打赏作者

Vic__li

你的鼓励将是我创作的最大动力

¥2 ¥4 ¥6 ¥10 ¥20
输入1-500的整数
余额支付 (余额:-- )
扫码支付
扫码支付:¥2
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值