主页 > IT业界  > 

iOS使用消息转发机制实现多代理功能

iOS使用消息转发机制实现多代理功能

在iOS开发中,我们有时候会用到多代理功能,比如我们列表的埋点事件,需要我们在列表的某个特定的时机进行埋点上报,我们当然可以用最常见的做法,就是设置代理实现代理方法,然后在对应的代理方法里面进行上报,但是这样做有个问题,就是会做大量重复的工作,我们想要到达的效果是,我们只需要实现业务逻辑,而埋点操作,只需需要我们配置一下数据,就会自动进行,这样就为我们减少了大量的重复性工作。 下面介绍一下我们实现列表的自定化埋点的思路 我们自定义一个列表类,继承于系统类,然后该类有一个代理中心, 该代理中心类负责消息转发,他引用了真正的原始代理,和一个代理对象,该代理对象也实现了列表的代理方法,里面的实现只进行埋点操作。 我们重写自定义列表类的setDelegate方法,在里面创建代理对象,并将列表的代理设置为代理中心,在代理中心中将消息转发给代理对象和原始代理, 通过这样的方式,实现了自动化埋点 代码 代理中心

// // LBDelegateCenter.m // TEXT // // Created by mac on 2025/3/2. // Copyright © 2025 刘博. All rights reserved. // #import "LBDelegateCenter.h" @implementation LBDelegateCenter - (instancetype)initWithTarget:(id)target proxy:(id)proxy { if (self = [super init]) { _target = target ? target : [NSNull null]; _proxy = proxy ? proxy : [NSNull null]; } return self; } - (NSMethodSignature *)methodSignatureForSelector:(SEL)sel { NSMethodSignature *targetSign = [_target methodSignatureForSelector:sel]; if (targetSign) { return targetSign; } NSMethodSignature *proxySign = [_proxy methodSignatureForSelector:sel]; if (proxySign) { return proxySign; } return [super methodSignatureForSelector:sel]; } - (void)forwardInvocation:(NSInvocation *)anInvocation { //AUKLogInfo(@"New proxy = %@, selector=%@", [self.proxy class], NSStringFromSelector([anInvocation selector])); BOOL hit = NO; if ([_target respondsToSelector:[anInvocation selector]]) { hit = YES; [anInvocation invokeWithTarget:_target]; } if ([_proxy respondsToSelector:[anInvocation selector]]) { //AUKLogInfo(@"New proxy handle"); hit = YES; [anInvocation invokeWithTarget:_proxy]; } if (!hit && [super respondsToSelector:[anInvocation selector]]) { [super forwardInvocation:anInvocation]; } } - (BOOL)respondsToSelector:(SEL)aSelector { if ([_target respondsToSelector:aSelector]) { return YES; } if ([_proxy respondsToSelector:aSelector]) { return YES; } return [super respondsToSelector:aSelector]; } - (BOOL)conformsToProtocol:(Protocol *)aProtocol { if ([_target conformsToProtocol:aProtocol]) { return YES; } if ([_proxy conformsToProtocol:aProtocol]) { return YES; } return [super conformsToProtocol:aProtocol]; } - (BOOL)isKindOfClass:(Class)aClass { if ([_target isKindOfClass:aClass]) { return YES; } if ([_proxy isKindOfClass:aClass]) { return YES; } return [super isKindOfClass:aClass]; } - (BOOL)isMemberOfClass:(Class)aClass { if ([_target isMemberOfClass:aClass]) { return YES; } if ([_proxy isMemberOfClass:aClass]) { return YES; } return [super isMemberOfClass:aClass]; } @end

代理对象

// // LBScrollViewDelegate.m // TEXT // // Created by mac on 2025/3/2. // Copyright © 2025 刘博. All rights reserved. // #import "LBScrollViewDelegate.h" #import <UIKit/UIKit.h> #import "UITableViewCell+Event.h" #import "UICollectionViewCell+Event.h" @implementation LBScrollViewDelegate // 自动轮播的开始,但是需要重点关注是否可能存在触发scrollViewDidScroll - (void)scrollViewDidScroll:(UIScrollView *)scrollView { //执行滚动 } - (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView { //开始拖动,执行曝光埋点 } // - (void)scrollViewWillBeginDecelerating:(UIScrollView *)scrollView { //开始减速, 停止滚动 } // - (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView { //停止减速 } // - (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate { if (!decelerate) { //停止滚动 } } // - (void)scrollViewDidEndScrollingAnimation:(UIScrollView *)scrollView { // } // 10.3.86 切换使用新方法代替点击捕获 - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath]; [cell setMonitorSelected:YES]; } - (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath { UICollectionViewCell *cell = [collectionView cellForItemAtIndexPath:indexPath]; [cell setMonitorSelected:YES]; } // 结束显示周期是准确的,但开始显示可能只显示一次,可能显示并不完全,所以暂只开了开始。 - (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath { if ([self needCheckCellIn:tableView isStart:YES]) { } } - (void)collectionView:(UICollectionView *)collectionView willDisplayCell:(UICollectionViewCell *)cell forItemAtIndexPath:(NSIndexPath *)indexPath { if ([self needCheckCellIn:collectionView isStart:YES]) { } } - (void)tableView:(UITableView *)tableView didEndDisplayingCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath*)indexPath { if ([self needCheckCellIn:tableView isStart:NO]) { } } - (void)collectionView:(UICollectionView *)collectionView didEndDisplayingCell:(UICollectionViewCell *)cell forItemAtIndexPath:(NSIndexPath *)indexPath { if ([self needCheckCellIn:collectionView isStart:NO]) { } } - (BOOL)needCheckCellIn:(UIView *)view isStart:(BOOL)start { return YES; } @end

自定义列表类

// // LBCollectionView.m // TEXT // // Created by mac on 2025/3/2. // Copyright © 2025 刘博. All rights reserved. // #import "LBEventCollectionView.h" #import "LBScrollViewDelegate.h" #import "LBDelegateCenter.h" @implementation LBEventCollectionView - (void)didMoveToWindow { [super didMoveToWindow]; //执行cell 曝光埋点 } - (void)reloadData { [super reloadData]; [self checkNeedReportLog_auk]; } - (void)checkNeedReportLog_auk { if (!self.window || !self.superview) { return; } // 上报当前visiblecell及其子view的所有埋点,放到下一个runloop,等到cell渲染完成 [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(performCommitScroll) object:nil]; [self performSelector:@selector(performCommitScroll) withObject:nil afterDelay:0.5]; } - (void)performCommitScroll { //执行曝光埋点 } - (LBScrollViewDelegate *)collectionDelegate_auk { if (!_collectionDelegate_auk) { _collectionDelegate_auk = [[LBScrollViewDelegate alloc] init]; } return _collectionDelegate_auk; } - (void)setDelegate:(id<UICollectionViewDelegate>)delegate { if (delegate == nil) { // self.delegateProxy_auk = nil; [super setDelegate:nil]; return; } self.delegateProxy_auk = [[LBDelegateCenter alloc] initWithTarget:self.collectionDelegate_auk proxy:delegate]; self.delegateProxy_auk.scrollView = self; [super setDelegate:(id)self.delegateProxy_auk]; } - (NSMutableDictionary *)visibleCellInfos_auk { if (!_visibleCellInfos_auk) { _visibleCellInfos_auk = [[NSMutableDictionary alloc] init]; } return _visibleCellInfos_auk; } - (NSMutableDictionary *)lastVisibleInfos_auk { if (!_lastVisibleInfos_auk) { _lastVisibleInfos_auk = [[NSMutableDictionary alloc] init]; } return _lastVisibleInfos_auk; } - (NSHashTable *)validViews_auk { if (!_validViews_auk) { _validViews_auk = [NSHashTable hashTableWithOptions:NSHashTableWeakMemory]; } return _validViews_auk; } - (void)dealloc { // self.delegate = nil; _delegateProxy_auk = nil; _collectionDelegate_auk = nil; } - (BOOL)supportAspectExposure { return NO; } @end
标签:

iOS使用消息转发机制实现多代理功能由讯客互联IT业界栏目发布,感谢您对讯客互联的认可,以及对我们原创作品以及文章的青睐,非常欢迎各位朋友分享到个人网站或者朋友圈,但转载请说明文章出处“iOS使用消息转发机制实现多代理功能