Can I swizzle didSelectRowAtIndexPath: of UITableViewDelegate?

怎甘沉沦 提交于 2021-01-20 20:25:30

问题


The problem is this:

I need to be able to get analytics on didSelectRowAtIndexPath throughout a big existing app with lots of tableViews.

My first thought of this is doing method swizzling on didSelectRowAtIndexPath: but my app crashes with "unrecognized selector sent to instance" message depending on the stuff is accessed in the original didSelectRowAtIndexPath implementation.

Here is how I try to achieve this in a UIViewController category:

#import "UIViewController+Swizzle.h"

@implementation UIViewController (Swizzle)

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPathSwizzled:(NSIndexPath *)indexPath {
    NSLog(@"Log something here");
    [self tableView:tableView didSelectRowAtIndexPathSwizzled:indexPath];
}

+ (void) initialize {
    BOOL conformsToTableViewDelegate = class_conformsToProtocol(self, @protocol(UITableViewDelegate));
    if(conformsToTableViewDelegate) {
        Method method1 = class_getInstanceMethod(self, @selector(tableView:didSelectRowAtIndexPath:));
        Method method2 = class_getInstanceMethod(self, @selector(tableView:didSelectRowAtIndexPathSwizzled:));
        method_exchangeImplementations(method1, method2);
    }
}


@end

Can this be accomplished? If so, what am I doing wrong?

Thanks!


回答1:


It might be late for giving answer, but hopefully it will help some other developer. Below link have help me a lot.

https://www.jianshu.com/p/9a93ae99fb27

   extension UITableView {

        @objc static func swizzleTableView() {

          guard self == UITableView.self else {
            return
          }

          let originalTableViewDelegateSelector = #selector(setter: self.delegate)
          let swizzledTableViewDelegateSelector = #selector(self.nsh_set(delegate:))

          let originalTableViewMethod = class_getInstanceMethod(self, originalTableViewDelegateSelector)
          let swizzledTableViewMethod = class_getInstanceMethod(self, swizzledTableViewDelegateSelector)

          method_exchangeImplementations(originalTableViewMethod!,
                                         swizzledTableViewMethod!)
        }

        @objc open func nsh_set(delegate: UITableViewDelegate?) {
          nsh_set(delegate: delegate)

          guard let delegate =  delegate else { return }

          let originalDidSelectSelector = #selector(delegate.tableView(_:didSelectRowAt:))
          let swizzleDidSelectSelector = #selector(self.tableView(_:didSelectRowAt:))

          let swizzleMethod = class_getInstanceMethod(UITableView.self, swizzleDidSelectSelector)
          let didAddMethod = class_addMethod(type(of: delegate), swizzleDidSelectSelector, method_getImplementation(swizzleMethod!), method_getTypeEncoding(swizzleMethod!))

          if didAddMethod {
            let didSelectOriginalMethod = class_getInstanceMethod(type(of: delegate), NSSelectorFromString("tableView:didSelectRowAt:"))
            let didSelectSwizzledMethod = class_getInstanceMethod(type(of: delegate), originalDidSelectSelector)
            if didSelectOriginalMethod != nil && didSelectSwizzledMethod != nil {
              method_exchangeImplementations(didSelectOriginalMethod!, didSelectSwizzledMethod!)
            }
          }
      }

      @objc open func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        self.tableView(tableView, didSelectRowAt: indexPath)

      }
    }


来源:https://stackoverflow.com/questions/19191803/can-i-swizzle-didselectrowatindexpath-of-uitableviewdelegate

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!