前言:最近刚刚结束一个项目,身心疲惫,还是得写写项目中用到的一些常见数据传递方案。
一、一对一方案
001 代理
通过一个子控件定义几个协议函数在父控件的 @interface ()<协议> 继承该代理,在父控件中实现这些函数,最经典就是UITableView的实现方式。要注意某些代理是否是required关键词声明了required关键词就得必须实现否则会报错
002 block
子控件声明block函数,在父控件中,子控件通过setBlock方法可以将子控件的参数传给父控件来进行使用,但是block使用特别要注意循环引用的风险,解决方案就是使用weakSelf关键字,这样就可以避免循环引用。子控件可以通过判断该block方法是否为空再执行该block方法。如果block中要进行UI刷新操作就得在主线程中进行操作,否则数据不会及时在UI中刷新出来。
#define WS(weakSelf) __weak __typeof(&*self)weakSelf = self;
003 runtime 设置forward关键字 将子控件执行的某方法通过runtime的动态解析将方法具体执行的对象只想父控件。
- (id)forwarder{
return objc_getAssociatedObject(self, @selector(forwarder));
}
- (void)setForwarder:(id)forwarder{
objc_setAssociatedObject(self, @selector(forwarder), forwarder, OBJC_ASSOCIATION_ASSIGN);
}
- (id)forwardingTargetForSelector:(SEL)aSelector{
return self.forwarder;
}
二、一对多方案
001 NSNotification通知
可以举个场景:一个父控件中有几个子控件。子控件1操作会让子控件2进行数据刷新操作,具体的场景就是购物车 待付款栏目的商品付款完成之后,会在待收货栏目显示出来,
[[NSNotificationCenter defaultCenter] postNotificationName:HomeListRefreshNotificationName object:nil];
- (void)registerNotifications{
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(homeVCDidAppear) name:HomeListRefreshNotificationName object:nil];
}
- (void)removeNotifications{
[[NSNotificationCenter defaultCenter] removeObserver:self name:HomeListRefreshNotificationName object:nil];
}
002 KVO 监听某个控件状态变化
#pragma mark - KVO
- (void)zy_addObserver
{
[self addObserver:self forKeyPath:@"attributedText" options:(NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld) context:nil];
}
- (void)zy_removeObserver
{
id info = self.observationInfo;
NSString * key = @"attributedText";
NSArray *array = [info valueForKey:@"_observances"];
for (id objc in array) {
id Properties = [objc valueForKeyPath:@"_property"];
NSString *keyPath = [Properties valueForKeyPath:@"_keyPath"];
if ([key isEqualToString:keyPath]) {
[self removeObserver:self forKeyPath:@"attributedText" context:nil];
}
}
}
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context
{
if ([keyPath isEqualToString:@"attributedText"]) {
if (self.isTapAction) {
if (![change[NSKeyValueChangeNewKey] isEqual: change[NSKeyValueChangeOldKey]]) {
}
}
}
}
三、全局方法
001 单例模式
例如商品筛选页面提交的参数和具体刷新的页面不在同一个模块,这样就得用单例模式将筛选的参数,保留起来在该刷新的页面拿到该筛选的参数进行网络接口请求
#define SingletonH(name) + (instancetype)shared##name
#if __has_feature(objc_arc)
#define SingletonM(name) \
\
static id instance; \
\
+ (instancetype)shared##name \
{ \
static dispatch_once_t onceToken; \
dispatch_once(&onceToken, ^{ \
instance = [[self alloc] init]; \
}); \
\
return instance; \
} \
\
+ (instancetype)allocWithZone:(NSZone *)zone \
{ \
static dispatch_once_t onceToken; \
dispatch_once(&onceToken, ^{ \
instance = [super allocWithZone:zone]; \
}); \
return instance; \
} \
\
- (id)copyWithZone:(NSZone *)zone \
{ \
return self; \
}
#else
#define SingletonM(name) \
\
static id instance; \
\
+ (instancetype)shared##name \
{ \
static dispatch_once_t onceToken; \
dispatch_once(&onceToken, ^{ \
instance = [[self alloc] init]; \
}); \
\
return instance; \
} \
\
+ (instancetype)allocWithZone:(NSZone *)zone \
{ \
static dispatch_once_t onceToken; \
dispatch_once(&onceToken, ^{ \
instance = [super allocWithZone:zone]; \
}); \
return instance; \
} \
\
- (id)copyWithZone:(NSZone *)zone \
{ \
return self; \
} \
\
- (instancetype)autorelease \
{ \
return self; \
} \
\
- (instancetype)retain \
{ \
return self; \
} \
\
- (NSUInteger)retainCount \
{ \
return 1; \
} \
\
- (oneway void)release \
{ \
\
}
#endif
四、总结
在项目中上述方案适用不同的需求场景,具体问题具体分析,多样化操作实现需求,可以让程序更加健壮。