iOS 全埋点-UITaleView和UICollectionView的点击事件2

151 阅读2分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 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];    
}