3

i've used the following code below to determine when views get added to a superview:

//Makes views announce their change of superviews
Method method = class_getInstanceMethod([UIView class], @selector(willMoveToSuperview:));
IMP originalImp = method_getImplementation(method);

void (^ block)(id, UIView *) = ^(id _self, UIView *superview) {
    [_self willChangeValueForKey:@"superview"];
    originalImp(_self, @selector(willMoveToSuperview:), superview);
    [_self didChangeValueForKey:@"superview"];
};

IMP newImp = imp_implementationWithBlock((__bridge id)((__bridge void*)block));
method_setImplementation(method, newImp);

i haven't had any issues with this, but when i try to run it in 64-bit, i get

EXC_BAD_ACCESS (code=EXC_I386_GPFLT) on originalImp(_self, @selector(willMoveToSuperview:), superview);

anyone have any insight?

thanks

Pawan Rai
  • 3,434
  • 4
  • 32
  • 42
Martin
  • 33
  • 3
  • 1
    Methods are invoked with a minimum of 2 parameters (id self, SEL selector, ...) Never mind, imp_implementationWithBlock doesn't take a SEL argument, but it does seem to have self twice looking at the reference page, not sure if it's a typo or not though. – David Berry Mar 21 '14 at 19:53
  • Personally I would try to implement this functionality without using swizzling...although it is interesting for this to be crashing on arm64. Are you building for arm64, or only building for 32-bit? – Jack Mar 21 '14 at 20:00
  • 1
    @JackWu id prefer not to use swizzling here. any suggestions? i'd like to build for arm64. – Martin Mar 21 '14 at 20:06
  • What if you try using [plblockimp](https://github.com/plausiblelabs/plblockimp)? It supposedly has ARM64 support (and a cursory look at their ARM64 assembly looks logical). – Richard J. Ross III Mar 21 '14 at 20:37
  • After further testing, I'm unable to make it crash at all. Your error is elsewhere, as this is a general protection fault (meaning originalImp is probably NULL). – Richard J. Ross III Mar 21 '14 at 20:51
  • @RichardJ.RossIII i just tried creating a brand new project and added the code in. A deployment target of 7.1 produces no crash. Anything lower does. – Martin Mar 22 '14 at 01:05
  • @Martin Really? Could you update your answer with some updates / changes you made? I just tested it a minute ago, it crashes. – Unheilig Mar 22 '14 at 02:22
  • @Unheilig as i mentioned in my previous comment, when i created a new proj (that's using Xcode 5.1), everything was fine and had no issues. but as soon as i changed the deployment target down to 7.0, i immediately saw the crash. i ended up going with AliSoftware's suggestion, swizzling the old school way. – Martin Mar 22 '14 at 23:44

1 Answers1

2

It seems like using an imp_implementationWithBlock crashes on arm64.

You may try classic swizzling instead (put the code in your block in a dedicated swizzledWillMoveToSuperview: method, exchanging implementations of the two methods / selectors, and call [self swizzledWillModeToSuperview:superview] in swizzledWillModeToSuperview: to actually call the original implementation).

Avoiding using imp_implementationWithBlock and using an implementation of an existing method instead seems to work for both 32 and 64 bit architectures.

Be aware that this won't cover all the cases anyway, especially if someone subclasses an UIView and override willMoveToSuperview without calling super, then those implementations won't be swizzled as you expect and the observation on these won't work.

AliSoftware
  • 32,623
  • 6
  • 82
  • 77