how to override/swizzle a method of a private class in runtime objective-c?

后端 未结 2 804
温柔的废话
温柔的废话 2021-01-07 04:37

To give a bit of context of why I\'m asking this: basically I would like to change the location of the myLocationButton of the google map on iOS. So I first fet

2条回答
  •  一整个雨季
    2021-01-07 05:37

    UPDATE

    If you want to preserve original implementation you can get it and call it inside the blockImp. Then after that call [[aClass superclass] layoutSubviews] or call it with function pointer. Note that all this code need some error check and exception prevents.

    //get method encoding
    const char * encoding = method_getTypeEncoding(class_getInstanceMethod(NSClassFromString(@"GMSUISettingsView"), @selector(layoutSubviews)));
    
    void(^oldImplementation)(id aClass, SEL aSelector) = imp_getBlock(method_getImplementation(class_getInstanceMethod(NSClassFromString(@"GMSUISettingsView"), @selector(layoutSubviews))));
    
    id blockImp = ^void(id aClass, SEL aSelector)
    {
        //old imlpementation
        oldImplementation(aClass, aSelector);
    
        //calling [super layoutSubviews]
        IMP aImp = [[aClass superclass] methodForSelector:@selector(layoutSubviews)];
        id (*func)(id, SEL) = (void *)aImp;
        func([aClass superclass], @selector(layoutSubviews));
    };
    IMP newImp = imp_implementationWithBlock(blockImp);
    class_replaceMethod(NSClassFromString(@"GMSUISettingsView"), @selector(layoutSubviews), newImp, encoding);
    

    ORIGINAL ANSWER

    I'm sorry but I didn't fully understand do you want to completely override 'layoutsubviews' or to have original implementation and change just part of it. If it's the first you could use class_replaceMethod instead of swizzling. It will have performance hits though! Something like this should do the trick:

    //get method encoding
    const char * encoding = method_getTypeEncoding(class_getInstanceMethod(NSClassFromString(@"GMSUISettingsView"), @selector(layoutSubviews)));
    
    id blockImp = ^void(id aClass, SEL aSelector)
    {
        //what you want to happen in layout subviews
    };
    IMP newImp = imp_implementationWithBlock(blockImp);
    class_replaceMethod(NSClassFromString(@"GMSUISettingsView"), @selector(layoutSubviews), newImp, encoding);
    

    I've not tested this on device/simulator but something like this should work for you. I assume you know it's not a really bright idea to manipulate private classes ;)

提交回复
热议问题