iOS: How do I know if a property is KVO-compliant?

前端 未结 4 1058
失恋的感觉
失恋的感觉 2020-11-30 07:36

In the Key-Value Observing Programming Guide, the section Registering for Key-Value Observing says \"Typically properties in Apple-supplied frameworks are only KVO-compliant

4条回答
  •  野趣味
    野趣味 (楼主)
    2020-11-30 08:16

    Based on @David DeLong's solution, this is what I came up with, and it works beautifully.

    Basically, I made a category on UIWindow. And in +load, I (run-time) check whether [UIWindow instancesRespondToSelector:@selector(rootViewController)]. If not, I use class_addMethod() to dynamically add the getter & setter methods for rootViewController. Also, I use objc_getAssociatedObject and objc_setAssociatedObject to get & set the rootViewController as an instance variable of UIWindow.

    // UIWindow+Additions.h
    
    @interface UIWindow (Additions)
    
    @end
    
    // UIWindow+Additions.m
    
    #import "UIWindow+Additions.h"
    #include 
    
    @implementation UIWindow (Additions)
    
    #if __IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_4_0
    // Add rootViewController getter & setter.
    static UIViewController *rootViewControllerKey;
    
    UIViewController *rootViewController3(id self, SEL _cmd);
    void setRootViewController3(id self, SEL _cmd, UIViewController *newRootViewController);
    
    UIViewController *rootViewController3(id self, SEL _cmd) {
        return (UIViewController *)objc_getAssociatedObject(self, &rootViewControllerKey);
    }
    
    void setRootViewController3(id self, SEL _cmd, UIViewController *newRootViewController) {
        UIViewController *rootViewController = [self performSelector:@selector(rootViewController)];
        if (newRootViewController != rootViewController) {
            // Remove old views before adding the new one.
            for (UIView *subview in [self subviews]) {
                [subview removeFromSuperview];
            }
            objc_setAssociatedObject(self, &rootViewControllerKey, newRootViewController,
                                     OBJC_ASSOCIATION_RETAIN_NONATOMIC);
            [self addSubview:newRootViewController.view];
        }
    }
    
    + (void)load {
        if (![UIWindow instancesRespondToSelector:@selector(rootViewController)]) {
            class_addMethod([self class], @selector(rootViewController),
                            (IMP)rootViewController3, "@@:");
            class_addMethod([self class], @selector(setRootViewController:),
                            (IMP)setRootViewController3, "v@:@");
        }
    }
    #endif
    
    @end
    

提交回复
热议问题