Observing changes to a UIView's window and superview properties
Here is a way. Is it gross? Yes. Do I recommend such behavior? No. But we're all adults here.
The gist is that you use method_setImplementation to change the implementation of -[UIView didAddSubview:]
so you get notified whenever it's called (and you'd do the same thing for willRemoveSubview:
). Unfortunately, you will get called for all view hierarchy changes. You'll have to add your own filtering to find the specific views you're interested in.
static void InstallAddSubviewListener(void (^listener)(id _self, UIView* subview))
{
if ( listener == NULL )
{
NSLog(@"listener cannot be NULL.");
return;
}
Method addSubviewMethod = class_getInstanceMethod([UIView class], @selector(didAddSubview:));
IMP originalImp = method_getImplementation(addSubviewMethod);
void (^block)(id, UIView*) = ^(id _self, UIView* subview) {
originalImp(_self, @selector(didAddSubview:), subview);
listener(_self, subview);
};
IMP newImp = imp_implementationWithBlock((__bridge void*)block);
method_setImplementation(addSubviewMethod, newImp);
}
To use, do something like:
InstallAddSubviewListener(^(id _self, UIView *subview) {
NSLog(@"-[UIView didAddSubview:] self=%@, view=%@", _self, subview);
});
Override this method:
- (void)didMoveToSuperview
{
UIView *superView = [self superview];
}
And you can override these methods in your custom view for other use:
- (void)willMoveToSuperview:(UIView *)newSuperview;
- (void)didMoveToSuperview;
- (void)willMoveToWindow:(UIWindow *)newWindow;
- (void)didMoveToWindow;
based on the code by @doug-richardson, why not something a little cleaner that will allow KVO for the superview property?
//Make 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 void*)block);
method_setImplementation(method, newImp);