一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第27天,点击查看活动详情。
方案二:动态子类
初始思路
在运行时,给实现了UITableViewDelegate协议的- tableView:didSelectRow-AtIndexPath:方法的类创建一个子类,让该子类的对象变成我们自己创建的子类的对象。同时,在创建的子类中动态添加- tableView:didSelectRowAtIndexPath:方法。那么,当用户点击UITableViewCell控件时,就会先运行自己创建的子类中的- tableView:didSelectRow-AtIndexPath:方法。我们在实现该方法的时候,先调用delegate原来的方法实现,再触发$AppClick事件,即可实现 UITableView控件$AppClick事件全埋点。
创建一个动态添加子类的工具类:TableViewDynamicDelegate
TableViewDynamicDelegate.h声明如下:
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
NS_ASSUME_NONNULL_BEGIN
@interface TableViewDynamicDelegate : NSObject
+ (void)proxyWithTableViewDelegate:(id <UITableViewDelegate>)delegate;
@end
NS_ASSUME_NONNULL_END
TableViewDynamicDelegate.m声明如下:
#import "TableViewDynamicDelegate.h"
#import <UIKit/UIKit.h>
#import <objc/runtime.h>
#import "SensorsAnalyticsSDK.h"
/// Delegate 的子类前缀
static NSString *const kSensorsDelegatePrefix = @"cn.countData.";
// tableView:didSelectRowAtIndexPath: 方法指针类型
typedef void (*TableDidSelectImplementation)(id, SEL, UITableView *, NSIndexPath *);
@implementation TableViewDynamicDelegate
+ (void)proxyWithTableViewDelegate:(id <UITableViewDelegate>)delegate {
SEL originalSelector = NSSelectorFromString(@"tableView:didSelectRowAtIndexPath:");
//当Delegate中没有实现tbaleView:didSelectRowAtIndexPath:方法时,直接返回
if (![delegate respondsToSelector:originalSelector]) {
NSLog(@"没有实现tbaleView:didSelectRowAtIndexPath:方法");
return;
}
//动态创建一个新类
Class originalClass = object_getClass(delegate);
NSString *originalClassName = NSStringFromClass(originalClass);
//判断这个delegate对象是否已经动态创建的类时,无须重复设置,直接返回
if([originalClassName hasPrefix:kSensorsDelegatePrefix]) {
return;
}
//删除自动创建类名的私有方法
- (Class)sensorsdata_class {
// 获取对象的类
Class class = object_getClass(self);
// 将类名前缀替换成空字符串,获取原始类名
NSString *className = [NSStringFromClass(class) stringByReplacingOccurrencesOfString:kSensorsDelegatePrefix withString:@""];
// 通过字符串获取类,并返回
return objc_getClass([className UTF8String]);
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
//第一步:获取原始的类
Class cla = object_getClass(tableView.delegate);
NSString *className = [NSStringFromClass(cla) stringByReplacingOccurrencesOfString:kSensorsDelegatePrefix withString:@""];
Class originalClass = objc_getClass([className UTF8String]);
//第二步:调用开发者自己实现的方法
SEL originalSelector = NSSelectorFromString(@"tableView:didSelectRowAtIndexPath:");
Method originalMethod = class_getInstanceMethod(originalClass, originalSelector);
IMP originalIMP = method_getImplementation(originalMethod);
if (originalIMP) {
((TableDidSelectImplementation)originalIMP)(tableView.delegate,originalSelector,tableView,indexPath);
}
//第三步:埋点
[[SensorsAnalyticsSDK sharedInstance]AppClickWithTableView:tableView didSelectRowAtIndexPath:indexPath properties:@{@"$app_click":@"动态创建类事件"}];
}
最后调用:修改UITableView+CountData.m文件中的-CountData_setDelegate:方法,添加调用TableViewDynamicDelegate类的+proxyWithTableViewDelegate方法`
+ (void)load {
[UITableView sensorsdata_swizzleMethod:@selector(setDelegate:) withMethod:@selector(CountData_setDelegate:)];
}
- (void)CountData_setDelegate:(id<UITableViewDelegate>)delegate {
// 方案2 动态子类
[self CountData_setDelegate:delegate];
//设置delegate的动态子类
[TableViewDynamicDelegate proxyWithTableViewDelegate:delegate];
}