组织内容
专注于你的用户数据
一次只显示一种东西
满屏幕的内容
组织内容的标准样式
导航栏(有小标题)
标签栏(显示相同应用程序的不同视图)
导航栏(Navigation Bar)
一个层级的内容
是一个drilldown模型,逐层深入到更多的信息
标签栏
Self-contained模式(独立的模式)
满载屏幕的内容
是应用程序的一部分
它是数据的一个种类,它由不同的部分组成,视图,对于每个视图控制器来说都是独特的,还有你显示的数据以及逻辑。逻辑本身是在你的控制器中。
在联系人应用中,我们有一个联系人数据库的模型(实际上是iPhoneOs的一部分,你可以使用它),在视图边上,你有代表每个用户的单元格,每个单元格显示了与这个单元格有关的数据,在两者之间,你会有控制器,控制器把数据从模型传递到视图,如果用户去改变一些东西,它们还会与视图互动,视图告诉控制器,然后控制器相应地修改模型,总的来说,这是一个沟通机制,控制器与模型交谈,模型向控制器提供数据,控制器再向视图提供数据,视图通过控制器来操纵数据,因此所有东西都会经过控制器。
Model– View – Controller
为什么是Model– View – Controller
曾经用过”spaghetti”来描述代码(spaghetticode是指由于太多的代码,所有的东西都互相引用,非常难以理清)
而Model– View –Controller让你把东西细分成小的部分,它使得你能够概念化你的架构,在这些不同部分之间有分界。由于有不同的控制器,你避免了在应用中出现一个控制所有东西的巨型类。
它会导致复用性出现,如果你建造一个非常聚焦于你应用的一个方面的控制器类,然后你能够在以后再使用它,与模型和视图相似,如果你建造一个完全不知道它代表的模型的视图,然后这个视图被用在不同的方式中。如果你想以下你创建了的多边形类,你能取那个多边形类,如果它设计正确,它不知道任何有关控制器或者视图的东西,你能把那个多边形类拿到另外的电脑上,然后在它上面建造用不同方式代表数据的应用。
复用性的另外一个优势是它能帮助减少代码的撰写,如果你用通用的方法建造事物,你能再用它们,你不需要重写或复制粘贴它们。
在MVC中,模型代表你的数据,你可以有对于数据的类,你能有对于控制器的类,此外,尽管视图是各不相同的类,有很多不同种类的类,有能代表信息自身的类,有管理工作流程的类,还有代表屏幕上事物的类,这些是MVC的分界线。
MVC之间的交流
模型的交流
在cocoa中有两种方式是非常有用的,一个是KVO(Key-ValueObserving),在这个机制中,一个对象能收听另外一个对象中的变化。另外一个方法更加普片,它是叫做通告的东西,在所有应用中都有一个singleton类叫做NSNotificationCenter,它允许消息的发布,假设消息是字符串,如果你的多边形,因为某些原因它改变了边的数目,它能创建一个消息叫myMessage,它会发布这个通告,通告中心听到这个,取得了消息然后发布,任何收听了myMessagechangeNumberOfSides的人会接收那个消息,并在那时做它们需要做的。通过这两个机制,模型能发布有关自身的改变,你通常可以自由地得到这个KVO,你在很多情况下自由地得到它,你也可以去override它。但是如果你使用属性或适当的setter和getter,当你说polygonclass.numberOfSize=3,然后那会自动发射消息给任何观察它的观察者。
视图的交流
视图同样不知道控制器,但它能够通过,目标行为发送消息。一个控制器对象能在试图对象中为自己设置特定行为的目标。另外一个方法是通过委托。委托是一种方法,它使到一个对象发布某些类型的信息或者为委托对象上调用功能,这是视图能与收听的人交流的两种方法。
控制器的交流
控制器使做所有脏活的那个,它了解它需要关心的模型和视图,它使整个操作的大脑,它完成所有中间的管理工作,它通常使针对特定应用的。
控制器有对于模型的出口,它有指向它尝试代表的模型的ivar,如果需要操纵视图的话,它有一个指向试图的出口,这两个,模型和视图都能通过上面所讨论的机制与控制器进行交流。
管理一个满屏幕的数据
视图控制器知道它的视图以及它所代表的数据,但它实际上是这些屏幕逻辑的中心,你会在应用中有几个这些东西,如果你有一个导航类型的应用,通常这些经过的屏幕是另外的视图控制器,这不是必须的。事实上,你能自己进去动画导航控制器,你可以告诉你的视图去做动画,你可以修改导航条。但如果你用视图控制器来建造它们,你可以获得免费的东西。
视图控制器,它们实际是一个能给你一个不错切入点的类就像UIView是代表屏幕上视图的很好切入点一样,视图控制器是类似的东西,它提供了一个标准的方式去代表控制器,需要我们考虑的是不同数据流动方式,它们相当频繁地使用视图控制器。比如说导航栏,当你踏进一个屏幕,它通常是另外一个视图控制器。再比如说标签栏,如果你想一下时钟程序,那里有四个不同的标签,因此有四个不同的视图控制器,一个是世界时钟,一个是闹钟,它们之间并不了解对方,你可以切换或者结合它们两个
UIViewController
视图控制器是你的导航和信息流的基础建造区块,它一次管理一个视图,你会倾向于子类化它,有一个同的UIViewController,你会把它用作你的视图控制器的子类,有一些特殊的控制器你可能不需要子类化,比如navigationcontroller和标签栏控制器,你通常不会子类化它们,但像一些像表格视图控制器,你需要提供一些特定的信息给你的视图控制器,你会子类化它,你的视图控制器包含了视图的数据和逻辑,视图控制器就像把数据和逻辑联系在一起的胶水一样,它会在中间发信息。
当你为你应用程序的特定部分创建另外一个视图控制器时,你会子类化UIViewController,你会把它们拿过来用不同的方法连接在一起。当我们说道标签栏和导航栏控制器时,对于导航栏,我们假设有三个不同的视图控制器,那是你的堆栈,那是你在导航控制器中的层级,而导航栏控制器让你能够在它们之中进出,同样地,在标签栏控制器中,你有在一起相邻的不同的视图控制器。
实现UIViewController subclass
在.h文件中
如下:
#import<UIKit/UIKit.h>
@interfaceMyViewController:UIViewController{
//一个视图控制器通常需要管理视图和数据
NSMutableArray*myData;
UILabel*mylabel;
}
//属性,以备任何人需要与你的视图控制器交流来获取数据和设置。
@property(readonly)NSMutableArray*myData;
//事件
-(void)doSomeAction:(id)sender;
@end
在视图控制器中设置视图
注意:首先是当你创建视图控制器时,它不会自动创建视图,视图只在你需要的时候才被创建。(这样做的原因是:你可能在你的应用中有多个不同的视图,多个不同的屏幕要去体现,但一次只需在屏幕上显示其中的一个视图,因此提前分配视图是没意义的,视图可能是你应用中资源占用最多的部分,在你需要它们之前分配是没有意义的)。应用程序会替你做的另外一件事是,当你的应用的内存过低时,UI应用会有一个方法提醒你,视图控制器零事情更加的简单,它会自动清除内存,还会告诉你它们什么时候这样做,因此你可以清除更多的东西否则它们将出去更多。但是默认的,它们会在内存过低时抛弃视图,然后你会在需要的时候创新创建它,它还能很好地完成比例调整和定位,当你想要旋转屏幕时,它可以提供帮助,它会帮助确保你的屏幕不是特别为一个大小而建造的。就iPhone来说,它是320X480的屏幕,当你放置视图时,如果填满屏幕,你还有一个在顶部的状态栏,因此视图时320X460大小,如果你放置一个相同的视图控制器在导航栏上,你失去了44像素,如果你在标签栏中放置相同的视图控制器,你会失去另外的49像素。因此你的视图控制器有可变的大小,你甚至可从一个视图控制器到另外一个,然后第二个控制器可以把标签栏甚至状态栏推开以获得更多的空间,也即使,视图控制器可以根据它所代表的屏幕的需要来重置视图的位置。
如何装载你的视图
有两种方法装载你的视图,一个是在nib中建造事物,另外一个是通过实现UIViewController中的一个叫做loadView的方法,当loadView被调用使,这是你开始创建在你视图中展现的子视图的信号,你不会自己调用loadView方法,系统会自动调用该方法。不需要自己调用的党法还有dealloc以及drawRect方法。如果你需要调用loadView或drawRect方法,你需要告诉视图的setNeedsDisplay,然后方法会在下一次需要的时候开始绘制.
建造子视图和代码
-(void)loadView
{
//在这里,你可以分配任何你想放进去的子视图
MyView *myView = [[MyView alloc] initWithFrame:frame];
self.view= myView;//为它分配自己的视图控制器的视图
//无论何时应用程序想要显示视图控制器的视图,它总会调用你的viewController.view
[myViewrelease];//释放分配的空间,优化内存
}
在IB中创建你的视图控制器
在IB中,排列视图
File'sowner是视图控制器类(你在创建视图控制器时设置了,默认情况下它会说initWithNibName,这个nib名字时你指定的任意nib,如果你把它命名为myViewController,你的nib名字会是myViewController,你把.xib放到最后,当它被装载的时候,它会变成文件所有人。但当你装载一个nib时,nib必须有一个作为所有人的对象,这就是它们如何取得分配到那里的引用。当视图控制器变成了nib的文件所有人,你可以把任何来自视图控制器文件所有人的出口连接到视图)
视图控制器的生命周期
首先是你的nib的指定初始化程序initWithNibName.
-(id)initWithNibName:(NSString*)nibNameOrNil bundle:(NSBundle*)nibBundleOrNil
{
self= [superinitWithNibName:nibNameOrNilbundle:nibBundleOrNil];
if(self==[superinit...]) {
//Custom initialization
myData= [[NSMutableArray alloc] init];
self.title=@"Foo";
//设置视图控制器的标题假设你把试图控制器放到导航栏或甚至是标签栏控制器中,这些标题会自动设置好,当你放入或取出这些视图控制器时,标题会改变成那个试图控制器的标题
}
returnself;
}
如果你从nib建中视图控制器,一旦你的nib装载了,viewDidLoad就会被调用,而且在这里,你可以为你的视图定制大小或者任何你想对视图所做的定制。
-(void)viewDidLoad
{
[superviewDidLoad];
view.someWeirdProperty=YES;
}
当视图进出的时候,有四个功能,当视图进入的时候,首先调用的方法时viewWillAppear。它在视图来到屏幕前发生,而且刚好是在显示前那点,这个是你可能想要开始装载昂贵的数据的时间,如果你必须从网页取得某些东西,这是你知道你的视图控制器将会被显示的时候,这是更新的时间。
-(void)viewWillAppear:(BOOL)animated
{
[superviewWillAppear:<#animated#>];
//你的视图将在屏幕上展示
[selfbeginLoadingDataFromTheWeb];
[selfstartShowingLoadingProgress];
}
在viewWillAppear在你的导航栏控制器(举例来说)展示对象之前出现,但是一旦你的视图控制器完全显示出来,然后停止了动画,你会获得一个viewDidAppear,它可能发挥用途的一个方式是假设你有一个表格视图,它显示一些内容,然后你进入到另外一个视图控制器,这代表用户选择了一个其中一个选项,当这个导航栏控制器弹出和回去时,你想要等它完成动画,然后再播放,取消选取单元的动画。
-(void)viewDidAppear:(BOOL)animated
{
}
在你的视图即将离开屏幕的之前,你有机会去做你需要做的,比如保存数据,因为它即将消失。
-(void)viewWillDisappear:(BOOL)animated
{
[superviewDidDisappear:animated];
//你的视图将离开屏幕
[selfrememberScrollPostion];
[selfsaveDataToDisk];
}
viewDidDisappear方法告诉你它再屏幕上完全消失,这个animated参数会告诉你,它的动画是否打开或如果它只是这样消失.-(void)viewDidDisappear:(BOOL)animated
装载和保存数据
例子:
-(void)viewWillAppear:(BOOL)animated
{
floatsliderValue = [[NSUserDefaultsstandardUserDefaults]floatForKey:@"sliderValue"];
slider.value=sliderValue;
label.text= [NSStringstringWithFormat:@"%f",sliderValue];
}
-(void)viewWillDisappear:(BOOL)animated
{
floatsliderValue = slider.value;
[[NSUserDefaultsstandardUserDefaults]setFloat:sliderValueforKey:@"sliderValue"];
}
其他的视图控制器的关联
自动转动你的用户接口
低内存警告
支持界面旋转
-(BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
//Return YES for supported orientations
return(interfaceOrientation != UIInterfaceOrientationPortraitUpsideDown);
}
interfaceOrientation方向可以为竖放(Portrait),竖直倒放(PortraitUpside Down),右横放(LandscapeRight),左横放(LandscapeLeft)
自动调整视图的大小
在code中
view.autoresizingMask= UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight
view.autoresizingMask= UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleTopMargin;//距顶端可变
内存警告
-(void)didReceiveMemoryWarning
{
//Releases the view if it doesn't have a superview.
[superdidReceiveMemoryWarning];
//Release any cached data, images, etc that aren't in use.
}