How to properly swizzle UIScrollView with 3D touch peek pop?

348 Views Asked by At

I'm trying to swizzle the UIScrollView that 3D Touch's peek and pop preview is embedded in. (I know it's a UIScrollView through the Reveal app.)

I want to know whenever the user moves their finger on this scroll view/on the 3D touch preview.

I tried swizzling it as follows:

+ (void)load {
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        Class class = [self class];

        SEL originalSelector = @selector(setContentOffset:);
        SEL swizzledSelector = @selector(xxx_setContentOffset:);

        Method originalMethod = class_getInstanceMethod(class, originalSelector);
        Method swizzledMethod = class_getInstanceMethod(class, swizzledSelector);

        BOOL didAddMethod =
        class_addMethod(class,
                        originalSelector,
                        method_getImplementation(swizzledMethod),
                        method_getTypeEncoding(swizzledMethod));

        if (didAddMethod) {
            class_replaceMethod(class,
                                swizzledSelector,
                                method_getImplementation(originalMethod),
                                method_getTypeEncoding(originalMethod));
        } else {
            method_exchangeImplementations(originalMethod, swizzledMethod);
        }
    });
}

#pragma mark - Method Swizzling

- (void)xxx_setContentOffset:(CGPoint)offset {
    [self xxx_setContentOffset:offset];

    NSLog(@"yes");

}

But it only calls "yes" once or twice when there should be hundreds of calls from sliding my finger across the screen.

Am I swizzling this wrong?

1

There are 1 best solutions below

0
On

I am not sure that the scroll view itself calls the "setter" therefor you will not necessarily get the callback.

I created a "floating" view in the scrollview through KVO on the contentOffset property and it is called as expected. You may be able to use the same mechanism in your case:

        /**
         *  We are using KVO to offset the background image view
        */

        [self addObserver:self forKeyPath:@"contentOffset" options:NSKeyValueObservingOptionNew|NSKeyValueObservingOptionOld context:nil];

-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString *,id> *)change context:(void *)context {
    if ([keyPath isEqualToString:@"contentOffset"]) {
        _bgImageView.frame = CGRectMake(self.contentOffset.x,0, self.frame.size.width, self.frame.size.height);
    }
}

but for reference I am swizzling like this:

+(void)load {
    NSArray *selectors = @[NSStringFromSelector(@selector(setText:)),...];

    for (NSString *name in selectors) {
        SEL originalSelector = NSSelectorFromString(name);
        SEL swizzledSelector = NSSelectorFromString([NSString stringWithFormat:@"iio_swizzled_%@",name]);
        Method originalMethod = class_getInstanceMethod(self, originalSelector);
        Method swizzledMethod = class_getInstanceMethod(self, swizzledSelector);
        class_addMethod(self,
                        originalSelector,
                        class_getMethodImplementation(self, originalSelector),
                        method_getTypeEncoding(originalMethod));
        class_addMethod(self,
                        swizzledSelector,
                        class_getMethodImplementation(self, swizzledSelector),
                        method_getTypeEncoding(swizzledMethod));
        method_exchangeImplementations(originalMethod, swizzledMethod);
    }

}

-(void)iio_swizzled_setText:(NSString *)text {
   ... do stuff
   // and if needed to call the original 
  [self iio_swizzled_setText:text];
}