类间两种关系:继承、 组合。类间非继承关系,而调用了其它类的对象方法或访问了其它类的成员变量,那么他们间的关系统称组合关系。
广义上讲,组合也包含另两个特别的情况:单例访问、 通过根控制器或导航控制器找到对应页面控制器进行操作。
第一种关系:继承。
大家都知道通过父子类的继承关系,子类对象可以访问父类对象的公有成员变量和公有成员函数,这个就不多说了。
@interface SettingProfileHeadCell : SettingProfileCell
@property UIImageView *headImageView;
@property UILabel *describeLabel;
@end
第二种关系:普通组合关系。
类间的组合关系大家也经常用,一个类的成员对象是另一个类的对象。这个也不难了解。
它又包含两种情况:
1.生成的另一个类的对象是本类的一个成员对象。
2.生成的另一个类的对象是本类的成员函数的一个临时对象,随着本类的成员函数的调用结束,系统就销毁了该临时对象。
第一种情况:
生成的另一个类的对象是本类的一个成员对象的声明部分
@interface DrawMoneyViewController ()
{
}
@property CustomCommonNavigationBar *customCommonNavigationBar;
@end
@implementation DrawMoneyViewController
生成对象的部分:
- (void)setupSubViews {
self.view.backgroundColor = BACKGROUND_COLOR;
_customCommonNavigationBar = [[CustomCommonNavigationBar alloc] initWithLeftBtnImageName:@”NavBar_icon_Back_dark” LeftBtnShift:19 RightBtnTitle:@”” title:@”提现” titleIsBold:NO];
[self.view addSubview:_customCommonNavigationBar];
_customCommonNavigationBar.sd_layout
.leftSpaceToView(self.view, 0)
.rightSpaceToView(self.view, 0)
.topSpaceToView(self.view, 0)
.heightIs(64 + LINE_THICK); // 设置高度约束
[self loadButtonAction];
}
使用页面控制器包含的控件block:
-(void)loadButtonAction
{
[_customCommonNavigationBar backResult:^(BOOL iSuccess) {
[self.navigationController popViewControllerAnimated:YES];
}];
}
第二种情况:成员函数临时变量的数据序列化例子:
- (void)storageDataModelWithFileName:(NSString *)fileName dataArr:(NSMutableArray *)dataArr; { if(![fileName isKindOfClass:[NSString class]] || ![dataArr isKindOfClass:[NSMutableArray class]] || (dataArr.count == 0)) { return; } NSString *plistFileName = [fileName stringByReplacingOccurrencesOfString:@” ” withString:@”“]; if(plistFileName.length == 0) { return; } NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); NSFileManager* fm = [NSFileManager defaultManager]; NSString *path=[paths objectAtIndex:0]; path = [path stringByAppendingPathComponent:LOCATION_DATA]; if (![fm fileExistsAtPath:path]) { [fm createDirectoryAtPath:path withIntermediateDirectories:YES attributes:nil error:nil]; } NSString *filePath = [path stringByAppendingPathComponent:plistFileName]; //获取路径 if([plistFileName isEqualToString:ORDER_CENTER_PLIST_FILE_NAME]) { OrderOperateModel *orderOperateModel = nil; NSMutableArray *arr = [NSMutableArray array]; for(NSUInteger i = 0; i < dataArr.count; i++) { OrderCellModel *model = dataArr[i]; if(![model isKindOfClass:[OrderCellModel class]]) { return; } orderOperateModel = [[OrderOperateModel alloc] initWithDictionary:model]; [arr addObject:orderOperateModel]; } if(arr.count > 0) { NSData * tempArchive = [NSKeyedArchiver archivedDataWithRootObject:arr]; [tempArchive writeToFile:filePath atomically:YES]; } } } 第二种情况:成员函数临时变量的页面跳转例子: -(void)openOnlineServiceViewController : (NSMutableDictionary *)orderInfo { OnlineServiceViewController *onlineServiceViewController = [OnlineServiceViewController new]; [onlineServiceViewController displayOrderInfo : orderInfo]; [self.navigationController pushViewController:onlineServiceViewController animated:YES]; } 特殊的组合关系:单例访问。 一个类的对象中的函数可以访问全局的单例。 使用系统的单例的block: __weak typeof(self) weakSelf = self; AppDelegate app = (AppDelegate )[UIApplication sharedApplication].delegate; [app regisiterXYContinueListenOrderCallback:^{ [weakSelf continueListenOrder]; }]; 使用单例的变量: [SingleObject sharedInstance].keyboardWasShownFlag = NO; 使用单例的函数: [[SingleObject sharedInstance] initData];
使用单例的block:
[[SocketManager shareInstance] regisiterOnlineServiceCallBackMessageCallBack:^(NSMutableDictionary *message) { [weakSelf handleMessageWithMessage:message]; }];
特殊的组合关系:通过根控制器或导航控制器找到对应页面控制器进行操作。
它和第二种关系的主要区别是它不是直接在本类生成该对象,而是找到已经存在的对象,并进行操作。
它和第三种关系的主要区别是它不是直接找到该对象,而是通过根控制器(也可能是导航控制器)找到,甚至根控制器(也可能是导航控制器)也是被间接找到的。
在一个页面控制器里可以通过导航控制器找到其它页面控制器,对它的公有成员数据进行赋值,也可以对它的公有函数进行调用,一般近接着就要跳到找到的这个页面控制器。
-(void)openOnlineServiceViewController : (NSMutableDictionary *)orderInfo
{
for (UIViewController *viewController in self.navigationController.viewControllers) {
if ([viewController isKindOfClass:[OnlineServiceViewController class]]) {
OnlineServiceViewController onlineServiceViewController = (OnlineServiceViewController )viewController;
[self.navigationController popToViewController:onlineServiceViewController animated:YES];
return;
}
}
OnlineServiceViewController *onlineServiceViewController = [OnlineServiceViewController new];
[onlineServiceViewController displayOrderInfo : orderInfo];
[self.navigationController pushViewController:onlineServiceViewController animated:YES];
}
在一个页面控制器里或非页面控制器里可以通过keyWindow找到rootViewController,然后通过它可以找到本导航控制器,然后通过本导航控制器找到指定的页面控制器,对它的公有成员数据进行赋值,也可以对它的公有函数进行调用,一般近接着就要跳到找到的这个页面控制器。
所以这种情况算着上一种情况的一种特殊情况。
使用这种方式找页面控制器时要注意一下三种情况:
1.当你在高德导航地图页面,你找到的就不是rootViewController了,是导航地图图层。
2.若你的页面出现了循环跳转,当使用该方法循环跳转了多次,你再用该种方法找页面可能出现异常情况(我的首页使用了两个子试图,一个做侧边栏,一个作普通的首页,在两个子试图间产生页面循环,使用该方法多次循环跳转后崩溃。估计普通的循环页面跳转使用该方法不会产生崩溃)。
3.当你的页面有多于一个导航控制器时(如:有侧边栏的应用),要注意导航控制器的层级。
-(void)goToLoginViewControlNotification
{
NSArray *cv = [[self getCurrentVC] childViewControllers];
NSLog(@”%@”,cv);
if(cv.count == 0)
{
return;
}
[[GlobalShare getGlobalShare] clearUserInfo];
UIViewController viewCtrl = (UIViewController )(cv[0]);
if([viewCtrl isKindOfClass:[LoginViewController class]]) { return; } for (UIViewController *viewController in self.navigationController.viewControllers) { if ([viewController isKindOfClass:[LoginViewController class]]) { [self.navigationController popToViewController:viewController animated:YES]; } }
}
(UIViewController *)getCurrentVC
{
UIViewController *result = nil;
UIWindow * window = [[UIApplication sharedApplication] keyWindow];
if (window.windowLevel != UIWindowLevelNormal)
{
NSArray *windows = [[UIApplication sharedApplication] windows];
for(UIWindow * tmpWin in windows)
{
if (tmpWin.windowLevel == UIWindowLevelNormal)
{
window = tmpWin;
break;
}
}
}
UIView *frontView = [[window subviews] objectAtIndex:0];
id nextResponder = [frontView nextResponder];
if ([nextResponder isKindOfClass:[UIViewController class]])
result = nextResponder;
else
result = window.rootViewController;
return result;
}