iOS应用的开发通常采用MVC(Model-View-Controller)架构,其中的View,在Cocoa框架中通常为UIView及其子类。
在一个iOS应用中,View通常是吃内存大户,因此有效地管理View的内存就显得格外重要。在UIViewController中,一个重要的属性为view,这个view是该Controller中所有View的superview,它的生存周期如下所示:
生成及初始化:
- (void)loadView { UIView *view = [[[UIView alloc] initWithMainFrame] auotorelease; //类别中的方法。 … UIView *subView = [[[UIView alloc] initWithFrame:aFrame] autorelease]; … //修饰subView。 self.subView = subView; //如有需要。 [view addSubview: self.subView]; self.view = view; }
释放:
释放:
- (void)viewDidUnload { ... self.subView = nil; //可以视作Objc中释放属性的标准做法。 [super viewDidUnload]; //必须放在最后,不能把次序搞反了。 }
这样的一种结构显得异常简单明了,每个View负责该View及其所有的subviews的内存管理,显示等工作(Composite Pattern)。需要注意的是,self.subView = nil这句宜放在viewDidUnload中,而不宜放在dealloc中。iOS不支持虚拟内存机制,当iOS内存紧张时,会让暂不显示的Controller们执行viewDidUnload,以释放部分暂用不到的内存空间。
这样的一种结构显得异常简单明了,每个View负责该View及其所有的subviews的内存管理,显示等工作(Composite Pattern)。需要注意的是,self.subView = nil这句宜放在viewDidUnload中,而不宜放在dealloc中。iOS不支持虚拟内存机制,当iOS内存紧张时,会让暂不显示的Controller们执行viewDidUnload,以释放部分暂用不到的内存空间。
再来谈谈与UIView相关的proxy pattern。
在MVC架构中,View只负责显示与交互媒介,而不负责交互响应,程序逻辑等任务,因此需要把交互响应和程序逻辑从View类分离出去,以符合高内聚,低耦合之编码原则,而proxy patter的意义正是“延后”方法的具体化。
Objc对proxy pattern提供了语言级别的支持,故实现起来较为简便——通常是在头文件中声明协议,在Controller中实现协议,并把View的delegate属性(或dataSource等)设为该Controller。很多情况下(代理方法有返回值,或有多个参数),在View中无法简单地通过[self.delegate performSelector:]来实现代理方法的调用,这时需要用到NSInvoke类。详细用法,略过不表。
后注1:UIView子类中的loadView方法不可继承UIView的loadView方法,须重写,官方建议,原因本人不明。
后注2:Objc承SmallTalk流派,称OO术语“方法”一词为“消息”,意略为Runtime绑定,文中因涉OOD较多,故仍用OO术语“方法”。