页面的逻辑管理是衡量ios程序猿的重要标准,尽量避免页面的循环引用,若实在避免不了,要注意不能循环产生相同的页面,注意监听事件的添加与删除。
若你不你不小心产生了两个相同的页面,并且离开页面时,没有移除监听事件。对不起你将产生很多意向不到的问题,若你发送一个通知,你的那个重复的页面会产生两个通知,点击一个按钮,你可能两个按钮响应。
这些监听事件,通常包括广播通知,按钮事件。
当你的应用有被别人在其它设备踢出的逻辑处理,对不起,你肯定会出现页面的循环应用。还是关注下循环引用页面的会出现的问题。他不单会出现内存泄露,每循环引用引用一次你就会多申请一个相同的页面,虽然苹果的arc不会傻的看到你申请一大堆相同的页面,但是他会给保留两个相同的页面也算对得起你了,虽然内存不暴涨到崩溃得地步,但是让你出一些抓框得怪异现象也是很正常。所以要保证你相同页面的唯一性,特别是带监听的页面(这样的页面一定要离开页面时移除监听事件)。
解决办法一是:
在要PUSH到你想要的页面时,先在self.navigationController.viewControllers找下,看是否有,若你找到了就别申请了,直接跳到对应页面去吧,注意页面数据的初始化,不然你跳到的页面是原来的数据。找不到你再alloc不迟。
当页面出现时增加监听事件,当页面消失时移除监听事件。
注意当你的应用有侧边栏时,你的页面navigationController有两个,一个是侧边栏的,另一个是费侧边栏了。这样乱跳,就要设计侧边栏根控制器,侧边栏根控制器收到踢出的通知,调用dismissViewControllerAnimated回侧边栏根控制器。
来点实际的代码片段吧!
[GlobalShare getGlobalShare].user.servicingOrderId = -1;
NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithDictionary: result[@”body”]];
// NSLog(@”detailDict = %@”,_detailDict);
for (UIViewController *viewController in self.navigationController.viewControllers) {
if ([viewController isKindOfClass:[OrderDetailViewController class]]) {
OrderDetailViewController orderVC = (OrderDetailViewController )viewController;
orderVC.isCheckout = YES;
orderVC.orderId = self.orderId;
orderVC.currentData = [OrderDataList GetOrderDataListWithDictionary:dict]; [GlobalShare getGlobalShare].user.processingOrderStat = PROCESSING_ORDER_STATE_WAIT_NEW_ORDER; // 保存在本地 [[GlobalShare getGlobalShare] saveinfo:[GlobalShare getGlobalShare].user]; [SingleObject sharedInstance].noConnectPage = NO_CONNECT_PAGE_IS; [self.navigationController pushViewController:viewController animated:YES]; return; } } OrderDetailViewController *orderVC = [[OrderDetailViewController alloc] initWithNibName:NSStringFromClass([OrderDetailViewController class]) bundle:nil];//[OrderDetailViewController new]; orderVC.isCheckout = YES; orderVC.orderId = self.orderId; orderVC.currentData = [OrderDataList GetOrderDataListWithDictionary:dict]; [GlobalShare getGlobalShare].user.processingOrderStat = PROCESSING_ORDER_STATE_WAIT_NEW_ORDER; // 保存在本地 [[GlobalShare getGlobalShare] saveinfo:[GlobalShare getGlobalShare].user]; [SingleObject sharedInstance].noConnectPage = NO_CONNECT_PAGE_IS;
[self.navigationController pushViewController:orderVC animated:YES];
(void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:YES];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(RefreshOrderStatusNotification:) name:PASSENGER_PAY_NOTIFICATION object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(hiddenComplaintButtonNotification:) name:HIDDEN_COMPLAIN_BUTTON_NOTIFICATION object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(backStageModifyEndOrderNotification:) name:BACK_STAGE_MODIFY_END_ORDER_NOTIFICATION object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(backStageCancelOrderNotification:) name:BACK_STAGE_CANCEL_ORDR_NOTIFICATION object:nil];
}
(void)viewWillDisappear:(BOOL)animated
{
FLDDLogDebug(@”函数”);
[super viewWillDisappear:YES];
[[NSNotificationCenter defaultCenter] removeObserver:self name:PASSENGER_PAY_NOTIFICATION object:nil];
[[NSNotificationCenter defaultCenter] removeObserver:self name:HIDDEN_COMPLAIN_BUTTON_NOTIFICATION object:nil];
[[NSNotificationCenter defaultCenter] removeObserver:self name:BACK_STAGE_MODIFY_END_ORDER_NOTIFICATION object:nil];
[[NSNotificationCenter defaultCenter] removeObserver:self name:BACK_STAGE_CANCEL_ORDR_NOTIFICATION object:nil];
}
if (NO == [[Singleton sharedInstance] getNeedReloginFlag]) {
setNeedReloginFlag:YES];
// 账号被踢出
[[NSNotificationCenter defaultCenter] postNotificationName:PresentFirstViewControllerNotification object:nil];
}
(void)PresentFirstViewControllerNotification
{
if (nil == [GlobalShare getGlobalShare].user)
{
return;
}
FLDDLogDebug(@”PresentFirstViewControllerNotification”);
if((LOGIN_ORDER_STATE_SUCESS == [[Singleton sharedInstance] getLoginOrderStat]) || (LOGIN_ORDER_STATE_SUCESS_NO_MAIN_VIEW == [[Singleton sharedInstance] getLoginOrderStat]))
{
// [[NSNotificationCenter defaultCenter] postNotificationName:REMOVE_MAIN_VIEW_CONTROL_NOTIFICATION object:nil];
}
if ([NSThread isMainThread])
{
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@”温馨提示” message:@”您的账号已经在其他设备上登陆!” delegate:self cancelButtonTitle:@”重新登录” otherButtonTitles:nil, nil];
@try
{
[alertView show];
}
@catch (NSException *exception) {
}
}
else
{
dispatch_sync(dispatch_get_main_queue(), ^{
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@”温馨提示” message:@”您的账号已经在其他设备上登陆!” delegate:self cancelButtonTitle:@”重新登录” otherButtonTitles:nil, nil];
@try
{
[alertView show];
}
@catch (NSException *exception) {
}
});
}
[self PresentFirstViewController];
}
(void)PresentFirstViewController
{
[SVProgressHUD dismiss];
[self ClearUserInfo];
FirstViewController *firstVC = [[FirstViewController alloc] initWithNibName:NSStringFromClass([FirstViewController class]) bundle:nil];
firstNav = [[UINavigationController alloc] initWithRootViewController:firstVC];
FLDDLogDebug(@”%@”, firstNav);
UIViewController *viewController = [CGeneralFunction findCurrentResponderViewController];
if (![viewController isKindOfClass:[StartOrderViewController class]] || ![viewController isKindOfClass:[FirstViewController class]])
{
[viewController dismissViewControllerAnimated:NO completion:^{
}];
}
[self presentViewController:firstNav animated:YES completion:^{
[[NSNotificationCenter defaultCenter] postNotificationName:REMOVE_MAIN_VIEW_CONTROL_NOTIFICATION object:nil];
}];
}
这个方案的优点是内存利用率高,不用频繁的申请申请过的页面;缺点时,当重新跳到这个已经存在的页面时要保证你的数据与页面元素都被初始化,该替换为新数据的换为新数据,要防止重复注册相同的通知。
方法二最直接:
想要跳到哪个页面,在self.navigationController.viewControllers或app.window.rootViewController.childViewControllers找它,若它存在直接删掉它,重新申请一个新的,跳转过去就可以了。每次都保证你的页面是唯一的,每次进入页面都是新面孔,不用再为了喜新厌旧老数据而纠结了。当然若你的应用存在侧边栏就要注意了,想从侧边栏进入主页面不是那么容易,必定他们在两个不同的控制器,你找不到所以删除不了,搞不好你会产生两个相同的主页面。
AppDelegate *app = (AppDelegate *)[UIApplication sharedApplication].delegate; UINavigationController *rootCT = [app.window.rootViewController.childViewControllers firstObject]; FLDDLogDebug(@" %@",rootCT.viewControllers); for (UIViewController *viewController in rootCT.viewControllers) { if ([viewController isKindOfClass:[MainViewController class]]) { [viewController removeFromParentViewController]; break; } } MainViewController *mainVC = [[MainViewController alloc] initWithNibName:NSStringFromClass([MainViewController class]) bundle:nil]; if((nil != rootCT) && (nil != mainVC)) { MainViewController *mainVC = [[MainViewController alloc] init]; mainVC.isBookingServicing = YES; [self dismissViewControllerAnimated:YES completion:^{ [self.navigationController popToRootViewControllerAnimated:YES]; }]; } 事例二: for (UIViewController *viewController in self.navigationController.viewControllers) { if ([viewController isKindOfClass:[MainViewController class]]) { [viewController removeFromParentViewController]; break; } } MainViewController *mainVC = [[MainViewController alloc] initWithNibName:NSStringFromClass([MainViewController class]) bundle:nil]; if((nil != self.navigationController) && (nil != mainVC)) { [self.navigationController pushViewController:mainVC animated:YES]; }
优缺点就不用说了吧?你明白的。