一个简单的ios应用可以用sdk自带的interfaceBuilder ,UIViewController,UINavigationViewController这些工具来搭建,但是如果项目比较复杂要求较高就满足不了需求了,比如我要从任意一个页面切换到任意的非当前页面,切换出去的页面马上释放内存,还要有不同的切换效果。
我是这样做的,程序启动当然还是appDelegate ,全局只有一个UIViewController称为主控制器mainController由appDelegate载入,然后其它所有页面都附在它的view上面,其它每个页面都有一个单独的控制器,这个子控制器一直存在内存中不释放,子控制器管理页面上的UI逻辑,其它所有子控制器之间的通信全部经由mainController转发,mainController一个重要任务就是控制页面的进入和移出,需要知道子控制器页面的叠放次序,利用UIView的subviews顺序,subview的索引越大则越位于最上层,通过索引值找到最上面的和最上面第二层就可以实现页面推进和推出了。这个特殊页面自定义,可以反查到它所属的子控制器,这样就能响应页面动画开始和结束事件。
@implementation MYCusttomUIView //子控制器定制页面
@synthesize superController; //反查所属的子控制器
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
[super touchesBegan:touches withEvent:event];
//转发给所属的controller ,子controller 不是用的UIViewController的self.view 所以需要借助主控制器主动触发。
if (superController.isInit) {
[superController touchesBegan:touches withEvent:event];
}
}
-(void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event{
[super touchesCancelled:touches withEvent:event];
if (superController.isInit) {
[superController touchesCancelled:touches withEvent:event];
}
}
-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event{
[super touchesEnded:touches withEvent:event];
if (superController.isInit) {
[superController touchesEnded:touches withEvent:event];
}
}
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event{
[super touchesMoved:touches withEvent:event];
if (superController.isInit) {
[superController touchesMoved:touches withEvent:event];
}
}
@end
//获得最上两层的View
-(MYCusttomUIView*)topLayerView{
NSArray* subviews = [manageView subviews];
//NSLog(@"subviews:%@",subviews);
MYCusttomUIView* top = nil;
int viewCount = 0;
for (int i = subviews.count - 1; i >= 0; i--) {
UIView* _v = [subviews OBJECT_AT(i)];
//if (_v.tag == RESERVE_TAG) { //不用tag标记,判断类型最好
if ([_v isKindOfClass:[MYCusttomUIView class]]) {
viewCount++;
if (viewCount == 1) {
top = (MYCusttomUIView*)_v;
break;
}
}
}
return top;
}
-(MYCusttomUIView*)secondLayerView{
NSArray* subviews = [manageView subviews];
MYCusttomUIView* second = nil;
int viewCount = 0;
for (int i = subviews.count - 1; i >= 0; i--) {
UIView* _v = [subviews OBJECT_AT(i)];
//if (_v.tag == RESERVE_TAG) {
if ([_v isKindOfClass:[MYCusttomUIView class]]) {
viewCount++;
if (viewCount == 2) {
second = (MYCusttomUIView*)_v;
break;
}
}
}
return second;
}
//主控制器还有个重要功能就是内存警告的管理,如果不理会这个肯定会闪退。策略就是释放掉所以非当前的显示的controller的内存,事实证明效果很明显。
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
NSLog(@"mainController memorywarning self.view:%@",self.view);
//释放掉非当前显示的View
NSArray* exceptionNames = [NSArray arrayWithObjects:@"releaseNoteViewController", nil];
for (NSString* controllerName in [controllerDict allKeys]) {
AllViewFatherController* controller = [controllerDict objectForKey:controllerName];
UIView* topView = [self topLayerView];
if ([controller isInit] && topView != controller.goodBorad && ![exceptionNames containsObject:controllerName]) {
[controller releaseData];
}
}
}
@interface AllViewFatherController : UIViewController{//子控制器父类,此类里面不用UIViewController的功能和self.view
CGSize screenSize;
MYCusttomUIView* goodBorad; //子页面容器
UIView* managerView; //方便移除释放所有内存
int viewEdition;
MainViewController* mainController;//主控制器,方便给其它子控制器发消息。
NSMutableDictionary* requestDict;//网络请求容器,退出时取消所有网络请求,以免出现错误
DataBaseTools* database;
NSMutableDictionary* argumentDict; //外界传过来的参数保存在本地,方便取用。
int homeNoticeCount;
}
@property (nonatomic,assign)MainViewController* mainController;
@property (nonatomic,assign)BOOL isInit; //是否初始化,控制器不释放,以此表示判断是否初始化。
@property (nonatomic,assign)NSMutableDictionary* argumentDict;
@property (nonatomic,assign)int homeNoticeCount;
-(MYCusttomUIView*)goodBorad;
-(void)initData:(id)arg; //初始化内存
-(void)releaseData; //释放内存
-(void)appearFinished;//显示动画结束。
-(void)disappearFinished;//消失动画结束,一般在
-(void)setViewEdition:(int)edition;
结构上还有两个常驻内存的单例对象,公共请求对象PublicRequest 处理和页面无关的网络请求。数据库对象DataBaseTool。