|
马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有帐号?立即注册
x
除了在程序加载的时候把我的view加载到他上目前我还没用到过其他的苹果一直很推崇MVC的程序结构视图模型控制器简单说就是视图负责显示内容模型负责所有数据的保存结构或者一些其他数据操作控制器是用来协调视图和模型举车的发动机系统的例子门面形式针对庞大的子体系供应了单一的接口,不必要暴漏一些列的类和API给用户,你仅仅暴漏一个复杂一致的API。
上面的图注释了这个观点:
<br>
这个API的利用者完整不必要体贴面前的庞大性。这个形式十分合适有一年夜堆很难利用大概了解的类的情形。
门面形式解耦了利用体系的代码和必要埋没的接口和完成类。它也下降了内部代码对外部子体系的依附性。当埋没在门面以后的类很简单产生变更的时分,此形式就很有效了,由于当面前的类产生变更的时分,门面类一直坚持了一样的API。
举个例子来讲,假如有一天你想代替后端服务,你不必要改动API的利用者,由于API没有产生变更。
怎样利用门面形式
以后你已用PersistencyManager当地保留专辑数据,利用HTTPClient处置远程毗连,工程中的别的类临时与本次完成的逻辑有关。
为了完成这个形式,只要LibraryAPI应当保留PersistencyManager和HTTPClient的实例,然后LibraryAPI将暴漏一个复杂的API往会见这些服务。
注重:一般来讲,单例类的性命周期贯串于全部使用的性命周期中,你不该对保留太多别的对象的强援用,由于他们只要到使用封闭的时分才干被开释。
本次计划看起来像下图:
<br>
LibraryAPI将暴漏给别的代码,可是它埋没了HTTPClient和PersistencyManager的庞大性。
翻开LibraryAPI.h,在文件头部增添上面的导进语句:
Objective-c代码http://www.kuqin.com/upimg/allimg/130917/21551421O-2.jpg
<br>
接上去,在LibraryAPI.h中增添以下的办法界说:
Objective-c代码http://www.kuqin.com/upimg/allimg/130917/21551421O-2.jpg
<br>
- -(NSArray*)getAlbums;
- -(void)addAlbum:(Album*)albumatIndex:(int)index;
- -(void)deleteAlbumAtIndex:(int)index;
今朝有一些你必要暴漏给别的类的办法。
翻开LibraryAPI.m,增添以下的两个导进语句:
Objective-c代码http://www.kuqin.com/upimg/allimg/130917/21551421O-2.jpg
<br>
- #import"PersistencyManager.h"
- #import"HTTPClient.h"
这里将是独一的导进这两个类的中央。记着:你的API是关于庞大体系独一的会见点。
如今,增添经由过程类扩大(classextension)增添一些公有的变量(在@implementation行之上):
Objective-c代码http://www.kuqin.com/upimg/allimg/130917/21551421O-2.jpg
<br>
- @interfaceLibraryAPI(){
- PersistencyManager*persistencyManager;
- HTTPClient*httpClient;
- BOOLisOnline;
- }
- @end
isOnline决意了是不是服务器中任何专辑数据的改动应当被更新,比方增添大概删除专辑。
你如今必要经由过程init初始化这些变量。在LibraryAPI.m中增添以下的代码:
Objective-c代码http://www.kuqin.com/upimg/allimg/130917/21551421O-2.jpg
<br>
- -(id)init{
- self=[superinit];
- if(self){
- persistencyManager=[[PersistencyManageralloc]init];
- httpClient=[[HTTPClientalloc]init];
- isOnline=NO;
- }
- returnself;
- }
HTTP客户端实践上不会真实的和一个服务器交互,它在这里仅仅是用来演示门面形式的利用,以是isOnline将老是NO。
接上去,增添以下的三个办法到LibraryAPI.m:
Objective-c代码http://www.kuqin.com/upimg/allimg/130917/21551421O-2.jpg
<br>
- -(NSArray*)getAlbums
- {
- return[persistencyManagergetAlbums];
- }
- -(void)addAlbum:(Album*)albumatIndex:(int)index
- {
- [persistencyManageraddAlbum:albumatIndex:index];
- if(isOnline)
- {
- [httpClientpostRequest:@"/api/addAlbum"body:[albumdescription]];
- }
- }
- -(void)deleteAlbumAtIndex:(int)index
- {
- [persistencyManagerdeleteAlbumAtIndex:index];
- if(isOnline)
- {
- [httpClientpostRequest:@"/api/deleteAlbum"body:[@(index)description]];
- }
- }
我们来看一看addAlbum:atIndex:.这个类起首更新当地的数据,然后假如有收集毗连,它更新远程服务器。这就是门面形式的壮大的地方。当某些内部的类增添一个新的专辑的时分,它不晓得也不必要晓得面前的庞大性。
注重:当为子体系的类计划门面的时分,要记着:任何工具都不克不及制止客户端间接会见这些埋没的类。不要对这些进攻性的代码太甚于小气,而且也不要假定一切的客户端城市和门面一样利用你的类。
构建并运转你的使用。你将看到一个冲动民气的空缺的黑屏(哈哈):
<br>
接上去,你将必要在屏幕上显现专辑数据,利用你的下个计划形式-粉饰器计划形式将长短常好的选择。
粉饰器(Decorator)形式
粉饰器形式在不修正本来代码的情形下静态的给对象增添新的举动和职责,它经由过程一个对象包装被粉饰对象的办法来修正类的举动,这类办法能够做为子类化的一种替换办法。
在Objective-C中,存在两种十分罕见的完成:Category(种别)和Delegation(托付)。
Category(种别)
Category(种别)是一种不必要子类化就能够让你能静态的给已存在的类增添办法的强无力的机制。新增的办法是在编译期增添的,这些办法实行的时分和被扩大的类的别的办法是一样的。它大概与粉饰器计划形式的界说略微有点分歧,由于Category(种别)不会保留被扩大类的援用。
注重:你除能够扩大你本人的类之外,你还能够给Cocoa本人的类增添办法。
怎样利用种别
假想一种情形,你必要让Album(专辑)对象显现在一个表格视图(TableView)中:
<br>
专辑的题目从何而来?由于专辑是模子对象,它自己不必要体贴你怎样显现它的数据。你必要增添一些代码往扩大专辑类的举动,可是不必要间接修正专辑类。
你将创立一个专辑类扩大的种别,它将界说一个新的办法,这个办法会前往能很简单和UITableViews利用的数据布局。这个数据布局以下图所示:
<br>
为了给Album增添一个种别,导航到“FileNewFile...",选择Objective-Ccategory模板,不要习气性的选择Objective-Cclass模板。在Category域输出TableRepresentation,Categoryon域输出Album.
注重:你已注重到了新建文件的名字了吗?Album+TableRepresentation意味着你正在扩大Album类。这类商定长短常主要,由于它便利浏览和制止和你大概其别人创立的种别抵触。
翻开Album+TableRepresentation.h类,新增以下的办法原型:
Objective-c代码http://www.kuqin.com/upimg/allimg/130917/21551421O-2.jpg
<br>
- -(NSDictionary*)tr_tableRepresentation;
注重在办法开首有一个tr_前缀,它是种别TableRepresentation的缩写。再一次,这类商定也能够制止和别的的办法抵触。
注重:假如办法与本来类的办法重名了,大概与一样的类(乃至它的父类)的别的的扩大重名,那末运转期究竟应当挪用哪一个办法是不决义的。当你仅仅是在扩大你本人写的类时,这没甚么成绩,可是当你在扩大尺度的Cocoa大概CocoaTouch类的时分,它大概会招致严峻的成绩。
翻开Album+TableRepresentation.m,增添上面的办法:
Objective-c代码http://www.kuqin.com/upimg/allimg/130917/21551421O-2.jpg
<br>
- -(NSDictionary*)tr_tableRepresentation
- {
- return@{@"titles":@[@"Artist",@"Album",@"Genre",@"Year"],
- @"values":@[self.artist,self.title,self.genre,self.year]};
- }
咋们稍停半晌来看看这个形式的壮大的地方:
1.你能够间接利用Album的属性
2.你不必要子类化就能够增添办法。固然假如你想子类化Album,你任然能够那样做。
3.简复杂单的几句代码就让你在不修正Album的情形下,前往了一个UITableView作风的Album。
苹果在Foundation类中大批利用了Category。想晓得他们是怎样做的,你能够代开NSString.h文件,找到@interfaceNSString,你将看到类和别的三个种别的界说:NSStringExtensionMethods,NSExtendedStringPropertyListParsing,NSStringDeprecated.种别让办法构造成互相自力的部分。
Delegation(托付)
托付作为别的一个粉饰器形式,它是一种和别的对象交互的机制。举例来讲,当你利用UITableView的时分,你必需要完成tableView:numberOfRowsInSection:办法。
你不成能让UITableView晓得它必要在每一个地区显现几行,由于这些是使用特定的数据。因而盘算每一个地区必要显现几行的职责就给了UITableView的托付。这就让UITableView类自力于它要显现的数据。
这里经由过程一个图来注释当你创立UITableView的时分会产生甚么:
<br>
UITableView的职责就是显现一个表格视图。但是终极它必要一些它本身没有的信息。那末它就乞助于它的托付,经由过程发送动静给托付来猎取信息。在Objective-C完成托付形式的时分,一个类能够经由过程协定(Protocol)来声明可选和需要的办法。本指南稍后会触及协定方面的内容。
子类化一个对象,复写必要的办法看起来仿佛更简单一点,可是思索到你只能子类化一个类,假如你想一个对象作为两个大概更多对象的托付的话,利用子类化将不克不及完成。
注重:这个是一个主要的形式。苹果在UIKit类中大批利用了它:UITableView,UITextView,UITextField,UIWebView,UIAlert,UIActionSheet,UICollectionView,UIPickerView,UIGestureRecognizer,UIScrollView等等等。
怎样利用托付形式
翻开ViewController.m文件,在文件开首增添上面的导进语句:
Objective-c代码http://www.kuqin.com/upimg/allimg/130917/21551421O-2.jpg
<br>
- #import"LibraryAPI.h"
- #import"Album+TableRepresentation.h"
如今,给类的扩大增添以下的公有变量,终极类的扩大以下所示:
Objective-c代码http://www.kuqin.com/upimg/allimg/130917/21551421O-2.jpg
<br>
- @interfaceViewController(){
- UITableView*dataTable;
- NSArray*allAlbums;
- NSDictionary*currentAlbumData;
- intcurrentAlbumIndex;
- }
- @end
然后用上面的代码代替范例扩大中@interface一行:
Objective-c代码http://www.kuqin.com/upimg/allimg/130917/21551421O-2.jpg
<br>
- @interfaceViewController()<UITableViewDataSource,UITableViewDelegate>{
这就是怎样使得托付切合协定,你能够把它以为是托付实行协定办法左券的商定。在这里,你指定ViewController将完成UITableViewDataSource和UITableViewDelegate协定。这类体例使得UITableView十分断定那些托付必需要完成的办法。
接上去,用以下代码代替viewDidLoad办法:
Objective-c代码http://www.kuqin.com/upimg/allimg/130917/21551421O-2.jpg
<br>
- -(void)viewDidLoad
- {
- [superviewDidLoad];
- //1
- self.view.backgroundColor=[UIColorcolorWithRed:0.76fgreen:0.81fblue:0.87falpha:1];
- currentAlbumIndex=0;
- //2
- allAlbums=[[LibraryAPIsharedInstance]getAlbums];
- //3
- //theuitableviewthatpresentsthealbumdata
- dataTable=[[UITableViewalloc]initWithFrame:CGRectMake(0,120,self.view.frame.size.width,self.view.frame.size.height-120)style:UITableViewStyleGrouped];
- dataTable.delegate=self;
- dataTable.dataSource=self;
- dataTable.backgroundView=nil;
- [self.viewaddSubview:dataTable];
- }
上面我们来注释一下下面代码中标志了数字的中央:
1.改动背景致为大度的躲青色
2.经由过程API猎取专辑数据。你不必要间接利用PersistencyManager。
3.创立UITableView,声明viewController为UITableView的托付和数据源;因而viewController将供应一切的被UITableView必要的信息。
如今,在ViewController.m中增添以下的办法:
Objective-c代码http://www.kuqin.com/upimg/allimg/130917/21551421O-2.jpg
<br>
- -(void)showDataForAlbumAtIndex:(int)albumIndex
- {
- //defensivecode:makesuretherequestedindexislowerthantheamountofalbums
- if(albumIndex<allAlbums.count)
- {
- //fetchthealbum
- Album*album=allAlbums[albumIndex];
- //savethealbumsdatatopresentitlaterinthetableview
- currentAlbumData=[albumtr_tableRepresentation];
- }
- else
- {
- currentAlbumData=nil;
- }
- //wehavethedataweneed,letsrefreshourtableview
- [dataTablereloadData];
- }
showDataForAlbumAtIndex:从专辑数组中猎取必要的专辑数据。当你想往显现新的数据的时分,你仅仅必要挪用reloadData.这将使得UITableView往问托付一些以下的信息:表格视图有几个地区,每一个地区应当显现几行,每一个单位格长甚么样。
在viewDidLoad最初增添上面一行代码:
Objective-c代码http://www.kuqin.com/upimg/allimg/130917/21551421O-2.jpg
<br>
- [selfshowDataForAlbumAtIndex:currentAlbumIndex];
下面的代码会在app启动的时分加载以后的专辑,由于currentAlbumIndex设置为0,以是它将显现第一个专辑。
构建并运转你的工程;你将失掉一个溃散信息,在调试把持台下面将显现以下的非常:
<br>
这里出了甚么成绩?你声明ViewController作为UITableView的托付和数据源,可是如许做了,也就意味着你必需完成所必需的办法-这些办法包含你还没有完成的tableView:numberOfRowsInSection:办法.
在ViewController.m文件中@implementation和@end之间的任何地位,增添上面的代码:
Objective-c代码http://www.kuqin.com/upimg/allimg/130917/21551421O-2.jpg
<br>
- -(NSInteger)tableView:(UITableView*)tableViewnumberOfRowsInSection:(NSInteger)section
- {
- return[currentAlbumData[@"titles"]count];
- }
- -(UITableViewCell*)tableView:(UITableView*)tableViewcellForRowAtIndexPath:(NSIndexPath*)indexPath
- {
- UITableViewCell*cell=[tableViewdequeueReusableCellWithIdentifier:@"cell"];
- if(!cell)
- {
- cell=[[UITableViewCellalloc]initWithStyle:UITableViewCellStyleValue1reuseIdentifier:@"cell"];
- }
- cell.textLabel.text=currentAlbumData[@"titles"][indexPath.row];
- cell.detailTextLabel.text=currentAlbumData[@"values"][indexPath.row];
- returncell;
- }
tableView:numberOfRowsInSection:办法前往表格视图必要显现的行数。这个和数据布局中的题目数目是婚配的。
tableView:cellForRowAtIndexPath:创立并前往一个包括题目和题目值的的单位格。
构建并运转你的工程,你的app应当会一般启动并显现下图所示的画面:
<br>
Model的改变最好通过Notification来传播之前吃过这样的亏最好不要用delegate模式)UIViewController |
|