美文网首页iOS 的那些事儿
iOS swizzle 系统的代理方法

iOS swizzle 系统的代理方法

作者: 站在下一刻 | 来源:发表于2019-06-22 17:57 被阅读0次

需求背景

这次有个需求,就是滑动tableView的时候需要记录一些事件,停止的时候也要记录一些事件,而项目里面的tableView很多,而且以后加的tableView也需要监听这些事件,所以需要统一处理一下,现在的方案就是通过交换tableView的相关代理方法来做统一的处理

实现思路

  • swizzle的事件都为scrollView的事件,从scrollView这个类下手
  • swizzle scrollView的setDelegate:方法
  • 在自定义的setDelegate:方法中swizzle相应的代理方法
  • 在自定义的swizzle方法中做相关的处理

最初实现(有问题版本)

思路很简单,接下来看看实现

  • 添加用于交换方法的函数
/**
 * class : 替换方法的类
 * originalSelector : 原始方法SEL
 * swizzledSelector : 用于交换的SEL
 * noneSelector : 原方法SEL对应IMP不存在的时候用的SEL
**/
void classInstanceMethodSwizzle(Class class, SEL originalSelector, SEL swizzledSelector,SEL noneSelector)
{
    Method originalMethod = class_getInstanceMethod(class, originalSelector);
    Method swizzledMethod = class_getInstanceMethod(class, swizzledSelector);
    Method noneMethod = class_getInstanceMethod(class, noneSelector);
    //已经交换过了
    if (method_getImplementation(originalMethod) == method_getImplementation(swizzledMethod)) {
        return;
    }
    
    BOOL originMethodExist = originalMethod != nil;
    //源方法不存在就直接添加noneSEL对应的IMP
    if (!originMethodExist&&noneMethod) {
            class_addMethod(class, originalSelector, method_getImplementation(noneMethod), method_getTypeEncoding(noneMethod));
        return;
    }
    
    BOOL didAddMethod = class_addMethod(class, originalSelector, method_getImplementation(swizzledMethod), method_getTypeEncoding(swizzledMethod));
    if (didAddMethod) {
        //当前类不存在originalSelector而父类存在的时候didAddMethod为YES,避免影响父类的相关方法功能走replaceMethod
        class_replaceMethod(class, swizzledSelector, method_getImplementation(originalMethod),method_getTypeEncoding(originalMethod));
    } else {
        method_exchangeImplementations(originalMethod, swizzledMethod);
    }
}
  • 添加scrollView的分类,swizzle setDelegate:方法

#import "LHSwizzle.h"

@implementation UIScrollView (LHExtension)
+ (void)load
{
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        classInstanceMethodSwizzle(self.class,
                                   @selector(setDelegate:),
                                   @selector(cs_setDelegate:),
                                   nil);
    });
}

  • 在自定义的setDelegate:方法中swizzle相应的代理方法
- (void)cs_setDelegate:(id<UIScrollViewDelegate>)delegate
{
    if ([self isKindOfClass:UITableView.class]) {
        if (delegate) {
            classInstanceMethodSwizzle([delegate class],
                                       @selector(scrollViewWillBeginDragging:),
                                       @selector(swizzling_tableViewWillBeginDragging:),
                                       @selector(none_tableViewWillBeginDragging:));
            
            classInstanceMethodSwizzle([delegate class],
                                       @selector(scrollViewDidEndDecelerating:),
                                       @selector(swizzling_tableViewDidEndDecelerating:),
                                       @selector(none_tableViewDidEndDecelerating:));
            
            
            classInstanceMethodSwizzle([delegate class],
                                       @selector(scrollViewDidEndDragging:willDecelerate:),
                                       @selector(swizzling_tableViewDidEndDragging:willDecelerate:),
                                       @selector(none_tableViewDidEndDragging:willDecelerate:));
            
            
            classInstanceMethodSwizzle([delegate class],
                                       @selector(tableView:didEndDisplayingCell:forRowAtIndexPath:),
                                       @selector(swizzling_tableView:didEndDisplayingCell:forRowAtIndexPath:),
                                       @selector(none_tableView:willDisplayCell:forRowAtIndexPath:));
            
            
        }
        
    }else if ([self isKindOfClass:UICollectionView.class]) {
        if (delegate) {
            classInstanceMethodSwizzle([delegate class],
                                       @selector(scrollViewWillBeginDragging:),
                                       @selector(swizzling_collectionViewWillBeginDragging:),
                                       @selector(none_collectionViewWillBeginDragging:));
            
            
            
            
            classInstanceMethodSwizzle([delegate class],
                                       @selector(scrollViewDidEndDecelerating:),
                                       @selector(swizzling_collectionViewDidEndDecelerating:),
                                       @selector(none_collectionViewDidEndDecelerating:));
            
            
            
            classInstanceMethodSwizzle([delegate class],
                                       @selector(scrollViewDidEndDragging:willDecelerate:),
                                       @selector(swizzling_collectionViewDidEndDragging:willDecelerate:),
                                       @selector(none_collectionViewDidEndDragging:willDecelerate:));
            
            
            
            
            
            classInstanceMethodSwizzle([delegate class],
                                       @selector(collectionView:willDisplayCell:forItemAtIndexPath:),
                                       @selector(none_collectionView:willDisplayCell:forItemAtIndexPath:),
                                       @selector(none_collectionView:willDisplayCell:forItemAtIndexPath:));
            
            
        }
    }
    
    [self cs_setDelegate:delegate];
}
  • 在自定义的swizzle方法中做相关的处理
#import "NSObject+LHScrollSwizzleMethod.h"

@implementation NSObject (LHScrollSwizzleMethod)

- (void)swizzling_collectionViewWillBeginDragging:(UICollectionView *)collectionView
{
    [self none_collectionViewWillBeginDragging:collectionView];
    [self swizzling_collectionViewWillBeginDragging:collectionView];
}

- (void)none_collectionViewWillBeginDragging:(UICollectionView *)collectionView
{
    [GBEventRecord event:@"scrollBegin"];
}


- (void)swizzling_collectionViewDidEndDragging:(UICollectionView *)collectionView willDecelerate:(BOOL)decelerate
{
    [self none_collectionViewDidEndDecelerating:collectionView];
    [self swizzling_collectionViewDidEndDragging:collectionView willDecelerate:decelerate];
    
}

- (void)none_collectionViewDidEndDragging:(UICollectionView *)collectionView willDecelerate:(BOOL)decelerate
{
    [self none_collectionViewDidEndDecelerating:collectionView];
}

- (void)swizzling_collectionViewDidEndDecelerating:(UICollectionView *)collectionView
{
    [self none_collectionViewDidEndDecelerating:collectionView];
    [self swizzling_collectionViewDidEndDecelerating:collectionView];
}

- (void)none_collectionViewDidEndDecelerating:(UICollectionView *)collectionView
{
    [GBEvent event:@"scrollEnd"];
}

- (void)swizzling_collectionView:(UICollectionView *)collectionView willDisplayCell:(UICollectionViewCell *)cell forItemAtIndexPath:(NSIndexPath *)indexPath
{
    [self none_collectionView:collectionView willDisplayCell:cell forItemAtIndexPath:indexPath];
    [self swizzling_collectionView:collectionView
                   willDisplayCell:cell
                forItemAtIndexPath:indexPath];
}

- (void)none_collectionView:(UICollectionView *)collectionView willDisplayCell:(UICollectionViewCell *)cell forItemAtIndexPath:(NSIndexPath *)indexPath
{
    [GBEvent event:@"cellWillShow"];
}

- (void)swizzling_tableView:(UITableView *)tableView didEndDisplayingCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath
{
    [self none_tableView:tableView willDisplayCell:cell forRowAtIndexPath:indexPath];
    [self swizzling_tableView:tableView didEndDisplayingCell:cell forRowAtIndexPath:indexPath];
}

- (void)none_tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath
{
    [self none_tableViewWillBeginDragging:tableView];
}

- (void)swizzling_tableViewWillBeginDragging:(UITableView *)tableView
{
    [self none_tableViewWillBeginDragging:tableView];
    [self swizzling_collectionViewWillBeginDragging:tableView];
}

- (void)none_tableViewWillBeginDragging:(UITableView *)tableView
{
    [GBEvent event:@"scrollBegin"];
}

- (void)swizzling_tableViewDidEndDragging:(UITableView *)tableView willDecelerate:(BOOL)decelerate
{
    [self none_tableViewDidEndDecelerating:tableView];
    [self swizzling_tableViewDidEndDragging:tableView willDecelerate:decelerate];
}

- (void)none_tableViewDidEndDragging:(UITableView *)tableView willDecelerate:(BOOL)decelerate
{
    [GBEvent event:@"scrollEnd"];
}

- (void)swizzling_tableViewDidEndDecelerating:(UITableView *)tableView
{
    [self none_tableViewDidEndDecelerating:tableView];
    [self swizzling_collectionViewDidEndDecelerating:tableView];
}

- (void)none_tableViewDidEndDecelerating:(UITableView *)tableView
{
    [GBEvent event:@"scrollEnd"];
}

@end

遇到的问题

  • 相同的scrollView 的 setDelegate:方法会调用多次,对应的delegate会执行多次方法交换,调用两次setDelegate:后相当于没有交换
  • 自定义的tableView和UITableView是父子关系,会存在子类父类重复交换的问题

最终实现

分析

  • 需要解决相同类多次交换的问题;可以通过给setDelegate:进来的每个类添加带类名的SEL,让这个SEL指向对应的swizzle方法的IMP,对这个SEL进行交换,然后再次交换的时候判断是否存在这个SEL就行
  • 需要解决子类父类重复交换的问题;可以判定originSEL和swizzleSEL的IMP是否相等判断
  • 在前两条的情况下,子类可能不去做方法交换的逻辑,所以存在子类可以调用了自定义处理逻辑,但是调用不到父类方法源方法的问题;可以通过superClass向上查找父类的swizzle方法进行调用

代码

  • UIScrollView分类的改动


#define GET_CLASS_CUSTOM_SEL(sel,class)  NSSelectorFromString([NSString stringWithFormat:@"%@_%@",NSStringFromClass(class),NSStringFromSelector(sel)])

- (BOOL)isContainSel:(SEL)sel inClass:(Class)class
{
    unsigned int count;
    Method *methodList = class_copyMethodList(class,&count);
    for (int i = 0; i < count; i++) {
        Method method = methodList[i];
        NSString *tempMethodString = [NSString stringWithUTF8String:sel_getName(method_getName(method))];
        if ([tempMethodString isEqualToString:NSStringFromSelector(sel)]) {
            free(methodList);
            return YES;
        }
    }
    free(methodList);
    return NO;
}

- (void)cs_setDelegate:(id<UIScrollViewDelegate>)delegate
{
    if ([self isKindOfClass:UITableView.class]) {
        if (delegate) {
            BOOL hasSwizzled = NO;
            SEL delegateSEL = GET_CLASS_CUSTOM_SEL(@selector(scrollViewWillBeginDragging:),[delegate class]);
            if (class_getMethodImplementation(delegate.class, @selector(scrollViewWillBeginDragging:)) ==
                class_getMethodImplementation(delegate.class, @selector(swizzling_tableViewWillBeginDragging:))) {
                hasSwizzled = YES;
            }
            if (!hasSwizzled&&![self isContainSel:delegateSEL inClass:[delegate class]]) {
                [self class_addMethod:[delegate class]
                             selector:delegateSEL
                                  imp:method_getImplementation(class_getInstanceMethod([delegate class],@selector(swizzling_tableViewWillBeginDragging:)))
                                types:"v@:@"];
                classInstanceMethodSwizzle([delegate class],
                                           @selector(scrollViewWillBeginDragging:),
                                           delegateSEL,
                                           @selector(none_tableViewWillBeginDragging:));
            }
            hasSwizzled = NO;
            if (class_getMethodImplementation(delegate.class, @selector(scrollViewDidEndDecelerating:)) ==
                class_getMethodImplementation(delegate.class, @selector(swizzling_tableViewDidEndDecelerating:))) {
                hasSwizzled = YES;
            }
            delegateSEL = GET_CLASS_CUSTOM_SEL(@selector(scrollViewDidEndDecelerating:),[delegate class]);
            if (!hasSwizzled&&![self isContainSel:delegateSEL inClass:[delegate class]]) {
                [self class_addMethod:[delegate class]
                             selector:delegateSEL
                                  imp:method_getImplementation(class_getInstanceMethod([delegate class],@selector(swizzling_tableViewDidEndDecelerating:)))
                                types:"v@:@"];
                
                classInstanceMethodSwizzle([delegate class],
                                           @selector(scrollViewDidEndDecelerating:),
                                           delegateSEL,
                                           @selector(none_tableViewDidEndDecelerating:));
            }
            
            hasSwizzled = NO;
            if (class_getMethodImplementation(delegate.class, @selector(scrollViewDidEndDragging:willDecelerate:)) ==
                class_getMethodImplementation(delegate.class, @selector(swizzling_tableViewDidEndDragging:willDecelerate:))) {
                hasSwizzled = YES;
            }
            delegateSEL = GET_CLASS_CUSTOM_SEL(@selector(scrollViewDidEndDragging:willDecelerate:),[delegate class]);
            if (!hasSwizzled&&![self isContainSel:delegateSEL inClass:[delegate class]]) {
                [self class_addMethod:[delegate class]
                             selector:delegateSEL
                                  imp:method_getImplementation(class_getInstanceMethod([delegate class],@selector(swizzling_tableViewDidEndDragging:willDecelerate:)))
                                types:"v@:@"];
                
                classInstanceMethodSwizzle([delegate class],
                                           @selector(scrollViewDidEndDragging:willDecelerate:),
                                           delegateSEL,
                                           @selector(none_tableViewDidEndDragging:willDecelerate:));
            }
            hasSwizzled = NO;
            if (class_getMethodImplementation(delegate.class, @selector(tableView:didEndDisplayingCell:forRowAtIndexPath:)) ==
                class_getMethodImplementation(delegate.class, @selector(swizzling_tableView:didEndDisplayingCell:forRowAtIndexPath:))) {
                hasSwizzled = YES;
            }
            delegateSEL = GET_CLASS_CUSTOM_SEL(@selector(tableView:didEndDisplayingCell:forRowAtIndexPath:),[delegate class]);
            if (!hasSwizzled&&![self isContainSel:delegateSEL inClass:[delegate class]]) {
                [self class_addMethod:[delegate class]
                             selector:delegateSEL
                                  imp:method_getImplementation(class_getInstanceMethod([delegate class],@selector(swizzling_tableView:didEndDisplayingCell:forRowAtIndexPath:)))
                                types:"v@:@"];
                
                classInstanceMethodSwizzle([delegate class],
                                           @selector(tableView:didEndDisplayingCell:forRowAtIndexPath:),
                                           delegateSEL,
                                           @selector(none_tableView:willDisplayCell:forRowAtIndexPath:));
            }
            
        }
        
    }else if ([self isKindOfClass:UICollectionView.class]) {
        if (delegate) {
            BOOL hasSwizzled = NO;
            SEL delegateSEL = GET_CLASS_CUSTOM_SEL(@selector(scrollViewWillBeginDragging:),[delegate class]);
            if (class_getMethodImplementation(delegate.class, @selector(scrollViewWillBeginDragging:)) ==
                class_getMethodImplementation(delegate.class, @selector(swizzling_collectionViewWillBeginDragging:))) {
                hasSwizzled = YES;
            }
            if (!hasSwizzled&&![self isContainSel:delegateSEL inClass:[delegate class]]) {
                [self class_addMethod:[delegate class]
                             selector:delegateSEL
                                  imp:method_getImplementation(class_getInstanceMethod([delegate class],@selector(swizzling_collectionViewWillBeginDragging:)))
                                types:"v@:@"];
                classInstanceMethodSwizzle([delegate class],
                                           @selector(scrollViewWillBeginDragging:),
                                           delegateSEL,
                                           @selector(none_collectionViewWillBeginDragging:));
            }
            
            hasSwizzled = NO;
            if (class_getMethodImplementation(delegate.class, @selector(scrollViewDidEndDecelerating:)) ==
                class_getMethodImplementation(delegate.class, @selector(swizzling_collectionViewDidEndDecelerating:))) {
                hasSwizzled = YES;
            }
            delegateSEL = GET_CLASS_CUSTOM_SEL(@selector(scrollViewDidEndDecelerating:),[delegate class]);
            if (!hasSwizzled&&![self isContainSel:delegateSEL inClass:[delegate class]]) {
                [self class_addMethod:[delegate class]
                             selector:delegateSEL
                                  imp:method_getImplementation(class_getInstanceMethod([delegate class],@selector(swizzling_collectionViewDidEndDecelerating:)))
                                types:"v@:@"];
                
                classInstanceMethodSwizzle([delegate class],
                                           @selector(scrollViewDidEndDecelerating:),
                                           delegateSEL,
                                           @selector(none_collectionViewDidEndDecelerating:));
            }
            
            hasSwizzled = NO;
            if (class_getMethodImplementation(delegate.class, @selector(scrollViewDidEndDragging:willDecelerate:)) ==
                class_getMethodImplementation(delegate.class, @selector(swizzling_collectionViewDidEndDragging:willDecelerate:))) {
                hasSwizzled = YES;
            }
            delegateSEL = GET_CLASS_CUSTOM_SEL(@selector(scrollViewDidEndDragging:willDecelerate:),[delegate class]);
            if (!hasSwizzled&&![self isContainSel:delegateSEL inClass:[delegate class]]) {
                [self class_addMethod:[delegate class]
                             selector:delegateSEL
                                  imp:method_getImplementation(class_getInstanceMethod([delegate class],@selector(swizzling_collectionViewDidEndDragging:willDecelerate:)))
                                types:"v@:@i"];
                classInstanceMethodSwizzle([delegate class],
                                           @selector(scrollViewDidEndDragging:willDecelerate:),
                                           delegateSEL,
                                           @selector(none_collectionViewDidEndDragging:willDecelerate:));
                
                
            }
            
            hasSwizzled = NO;
            if (class_getMethodImplementation(delegate.class, @selector(collectionView:willDisplayCell:forItemAtIndexPath:)) ==
                class_getMethodImplementation(delegate.class, @selector(swizzling_collectionView:willDisplayCell:forItemAtIndexPath:))) {
                hasSwizzled = YES;
            }
            delegateSEL = GET_CLASS_CUSTOM_SEL(@selector(collectionView:willDisplayCell:forItemAtIndexPath:),[delegate class]);
            if (!hasSwizzled&&![self isContainSel:delegateSEL inClass:[delegate class]]) {
                [self class_addMethod:[delegate class]
                             selector:delegateSEL
                                  imp:method_getImplementation(class_getInstanceMethod([delegate class],@selector(swizzling_collectionView:willDisplayCell:forItemAtIndexPath:)))
                                types:"v@:@@@"];
                classInstanceMethodSwizzle([delegate class],
                                           @selector(collectionView:willDisplayCell:forItemAtIndexPath:),
                                           delegateSEL,
                                           @selector(none_collectionView:willDisplayCell:forItemAtIndexPath:));
            }
            
        }
    }
    
    [self cs_setDelegate:delegate];
}
  • NSObject分类的改动
@implementation NSObject (LHScrollSwizzleMethod)

- (id)lh_performSelector:(SEL)selector withObjects:(NSArray *)objects
{
    // 方法签名(方法的描述)
    NSMethodSignature *signature = [[self class] instanceMethodSignatureForSelector:selector];
    if (signature == nil) {
        return nil;
        //可以抛出异常也可以不操作。
    }
    
    // NSInvocation : 利用一个NSInvocation对象包装一次方法调用(方法调用者、方法名、方法参数、方法返回值)
    NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature];
    invocation.target = self;
    invocation.selector = selector;
    
    // 设置参数
    NSInteger paramsCount = signature.numberOfArguments - 2; // 除self、_cmd以外的参数个数
    paramsCount = MIN(paramsCount, objects.count);
    for (NSInteger i = 0; i < paramsCount; i++) {
        id object = objects[i];
        if ([object isKindOfClass:[NSNull class]]) continue;
        [invocation setArgument:&object atIndex:i + 2];
    }
    
    // 调用方法
    [invocation invoke];
    
    // 获取返回值
    id returnValue = nil;
    if (signature.methodReturnLength) { // 有返回值类型,才去获得返回值
        [invocation getReturnValue:&returnValue];
    }
    
    return returnValue;
}

- (void)callOriginSEL:(SEL)sel params:(NSArray *)arr
{
    Class curClass = self.class;
    while (curClass) {
        SEL delegateSEL = GET_CLASS_CUSTOM_SEL(sel,curClass);
        if ([self respondsToSelector:delegateSEL]) {
            [self snk_performSelector:delegateSEL withObjects:arr];
            break;
        }
        curClass = [curClass superclass];
    }
}

- (void)swizzling_collectionViewWillBeginDragging:(UICollectionView *)collectionView
{
    [self none_collectionViewWillBeginDragging:collectionView];
    [self callOriginSEL:@selector(scrollViewWillBeginDragging:) params:@[collectionView]];
}

- (void)swizzling_collectionViewDidEndDragging:(UICollectionView *)collectionView willDecelerate:(BOOL)decelerate
{
    [self none_collectionViewDidEndDecelerating:collectionView];
    [self callOriginSEL:@selector(scrollViewDidEndDragging:willDecelerate:) params:@[collectionView,@(decelerate)]];
}

- (void)swizzling_collectionViewDidEndDecelerating:(UICollectionView *)collectionView
{
    [self none_collectionViewDidEndDecelerating:collectionView];
    [self callOriginSEL:@selector(scrollViewDidEndDecelerating:) params:@[collectionView]];
}

- (void)swizzling_collectionView:(UICollectionView *)collectionView willDisplayCell:(UICollectionViewCell *)cell forItemAtIndexPath:(NSIndexPath *)indexPath
{
    [self none_collectionView:collectionView willDisplayCell:cell forItemAtIndexPath:indexPath];
    [self callOriginSEL:@selector(collectionView:willDisplayCell:forItemAtIndexPath:) params:@[collectionView,cell,indexPath]];
}


- (void)swizzling_tableView:(UITableView *)tableView didEndDisplayingCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath
{
    [self none_tableView:tableView willDisplayCell:cell forRowAtIndexPath:indexPath];
    [self callOriginSEL:@selector(tableView:didEndDisplayingCell:forRowAtIndexPath:) params:@[tableView,cell,indexPath]];
}

- (void)swizzling_tableViewWillBeginDragging:(UITableView *)tableView
{
    [self none_tableViewWillBeginDragging:tableView];
    [self callOriginSEL:@selector(scrollViewWillBeginDragging:) params:@[tableView]];
}

- (void)swizzling_tableViewDidEndDragging:(UITableView *)tableView willDecelerate:(BOOL)decelerate
{
    [self none_tableViewDidEndDecelerating:tableView];
    [self callOriginSEL:@selector(scrollViewDidEndDragging:willDecelerate:) params:@[tableView,@(decelerate)]];
}

- (void)swizzling_tableViewDidEndDecelerating:(UITableView *)tableView
{
    [self none_tableViewDidEndDecelerating:tableView];
    [self callOriginSEL:@selector(scrollViewDidEndDecelerating:) params:@[tableView]];
}

- (void)swizzling_collectionViewWillBeginDragging:(UICollectionView *)collectionView
{
    [self none_collectionViewWillBeginDragging:collectionView];
    [self swizzling_collectionViewWillBeginDragging:collectionView];
}

- (void)none_collectionViewWillBeginDragging:(UICollectionView *)collectionView
{
    [GBEventRecord event:@"scrollBegin"];
}

- (void)none_collectionViewDidEndDragging:(UICollectionView *)collectionView willDecelerate:(BOOL)decelerate
{
    [self none_collectionViewDidEndDecelerating:collectionView];
}

- (void)none_collectionViewDidEndDecelerating:(UICollectionView *)collectionView
{
    [GBEvent event:@"scrollEnd"];
}

- (void)none_collectionView:(UICollectionView *)collectionView willDisplayCell:(UICollectionViewCell *)cell forItemAtIndexPath:(NSIndexPath *)indexPath
{
    [GBEvent event:@"cellWillShow"];
}

- (void)none_tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath
{
    [self none_tableViewWillBeginDragging:tableView];
}

- (void)none_tableViewWillBeginDragging:(UITableView *)tableView
{
    [GBEvent event:@"scrollBegin"];
}

- (void)none_tableViewDidEndDragging:(UITableView *)tableView willDecelerate:(BOOL)decelerate
{
    [GBEvent event:@"scrollEnd"];
}

- (void)none_tableViewDidEndDecelerating:(UITableView *)tableView
{
    [GBEvent event:@"scrollEnd"];
}

@end

相关文章

  • iOS swizzle 系统的代理方法

    需求背景 这次有个需求,就是滑动tableView的时候需要记录一些事件,停止的时候也要记录一些事件,而项目里面的...

  • iOS Method Swizzle 源码分析

    iOS Method Swizzle 代码 平常我们用的方法都是method_exchangeImplementa...

  • HOOK技术

    iOS中HOOK技术的几种方式 Method Swizzle利用OC的Runtime特性,动态改变SEL(方法编号...

  • tableView

    tableView代理的调用顺序 tableView代理方法执行顺序,随着iOS系统版本的不断升级,执行顺序也有所...

  • 通讯录

    系统通讯录 AddressBook(iOS9之前) 引入头文件 遵循代理 实现代理方法 ContactsUI(iO...

  • 【iOS】Hook系统代理方法,添加UIScrollView滚动

    title: 【iOS】Hook系统代理方法,添加UIScrollView滚动停止回调date: 2018-01-...

  • 自定义UINavigationController push和p

    前言 首先, push/pop 动效在iOS7.0以后系统就已经提供了相关的代理方法, 在代理方法中我们可以自定义...

  • 14-Hook原理(一)fishHook

    前言 本篇文章开始给大家分享下Hook(钩子)的原理,包括iOS系统原生的Method Swizzle,还有很有名...

  • 分析移动端APP的网络请求

    为了方便,本文以 iOS 系统来进行演示。 使用代理 移动操作系统中都有可以设定系统代理的设置,比如在 iOS 中...

  • iOS逆向之反HOOK的基本防护

    iOS逆向之Method Swizzle iOS逆向之fishHook原理探究 iOS逆向之fishHook怎么通...

网友评论

    本文标题:iOS swizzle 系统的代理方法

    本文链接:https://www.haomeiwen.com/subject/wyeuqctx.html