iOS:如何知道某个属性是否符合KVO? [英] iOS: How do I know if a property is KVO-compliant?

查看:221
本文介绍了iOS:如何知道某个属性是否符合KVO?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

键值观察编程指南中,部分注册键值观察说通常属性在苹果提供的框架只有KVO兼容,如果他们这样记录。但是,我没有发现在文档中记录为KVO兼容的任何属性。



具体来说,我想知道 @property(nonatomic,retain)UIViewController * rootViewController

code>的 UIWindow 是KVO兼容的。原因是我为 UIWindow 添加 rootViewController 属性为iOS< 4,并想知道是否应该使其符合KVO标准。

  @interface UIWindow(添加)

#if __IPHONE_OS_VERSION_MIN_REQUIRED< __IPHONE_4_0
@property(nonatomic,retain)UIViewController * rootViewController;
#endif;

@end

@implementation UIWindow(添加)

#if __IPHONE_OS_VERSION_MIN_REQUIRED< __IPHONE_4_0
@dynamic rootViewController;

- (void)setRootViewController:(UIViewController *)newRootViewController {
if(newRootViewController!= _rootViewController){
//在添加新视图之前删除旧视图。
for(UIView * subview in [self subviews]){
[subview removeFromSuperview];
}
[_rootViewController release];
_rootViewController = newRootViewController;
[_rootViewController retain];
[self addSubview:_rootViewController.view];
}
}
#endif

@end




很长的答案:UIKit中没有任何内容可以保证符合KVO标准。如果你碰巧发现KVO一个属性工作,感激,这是无意的。另外:要谨慎。



如果您发现这是您需要的,请提交增强请求






关于您的实际代码,它本身有缺陷。 尝试以 UIWindow 的方式添加rootViewController设置器。在iOS 4上编译代码时,会中断,但有人在iOS 5设备上运行代码。因为您使用4.x SDK编译, #if 语句将计算为true,这意味着您的类别方法粉碎器将包含在二进制文件中。但是,当您在iOS 5设备上运行它时,您现在将得到一个方法冲突,因为 UIWindow 上的两个方法将具有相同的方法签名, >



不要像这样使用框架。如果你有这个,使用一个子类。






您的子类别如下所示:

  @interface CustomWindow:UIWindow 

@property(nonatomic,retain)UIViewController * rootViewController;

@end

@implementation CustomWindow:UIWindow

static BOOL UIWindowHasRootViewController = NO;

@dynamic rootViewController;

- (void)_findRootViewControllerMethod {
static dispatch_once_t predicate;
dispatch_once(& predicate,^ {
IMP uiwindowMethod = [UIWindow instanceMethodForSelector:@selector(setRootViewController :)];
IMP customWindowMethod = [CustomWindow instanceMethodForSelector:@selector(setRootViewController :)];
UIWindowHasRootViewController =(uiwindowMethod!= NULL&& uiwindowMethod!= customWindowMethod);
});
}

- (UIViewController *)rootViewController {
[self _findRootViewControllerMethod];
if(UIWindowHasRootViewController){
//这将是一个编译错误,除非你转发声明属性
//我将作为练习留给读者;
return [super rootViewController];
}
//返回子类中的一个
}

- (void)setRootViewController:(UIViewController *)rootViewController {
[self _findRootViewControllerMethod ];
if(UIWindowHasRootViewController){
//这将是一个编译错误,除非你转发声明属性
//我将作为练习留给读者;
[ super setRootViewController:rootViewController];
} else {
//在子类中设置一个
}
}

Caveat实施者:我在浏览器窗口中输入了这个


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 if they are documented as such." But, I haven't found any properties in the documentation that are documented as KVO-compliant. Would you please point me to some?

Specifically, I would like to know if the @property(nonatomic,retain) UIViewController *rootViewController of UIWindow is KVO-compliant. The reason is that I'm adding the rootViewController property to UIWindow for iOS < 4 and want to know if I should make it KVO-compliant.

@interface UIWindow (Additions)

#if __IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_4_0
@property (nonatomic, retain) UIViewController *rootViewController;
#endif;

@end

@implementation UIWindow (Additions)

#if __IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_4_0
@dynamic rootViewController;

- (void)setRootViewController:(UIViewController *)newRootViewController {
    if (newRootViewController != _rootViewController) {
        // Remove old views before adding the new one.
        for (UIView *subview in [self subviews]) {
            [subview removeFromSuperview];
        }
        [_rootViewController release];
        _rootViewController = newRootViewController;
        [_rootViewController retain];
        [self addSubview:_rootViewController.view];
    }
}
#endif

@end

解决方案

Short answer: No.

Long answer: Nothing in UIKit is guaranteed to be KVO-compliant. If you happen to find that KVO-ing a property works, be grateful, it's unintentional. Also: be wary. It could very well break in the future.

If you find that this is something you need, please file an enhancement request.


About your actual code, it's inherently flawed. Do NOT attempt to add a "rootViewController" setter to UIWindow this way. It will break when you compile your code on iOS 4 but someone runs it on an iOS 5 device. Because you compiled using the 4.x SDK, the #if statements will evaluate to true, meaning your category method smasher will be included in the binary. However, when you run it on an iOS 5 device, you're now going to get a method conflict because two methods on UIWindow will have the same method signature, and there's no guarantee as to which one will be used.

Don't screw with the frameworks like this. If you have to have this, use a subclass. THIS IS WHY SUBCLASSING EXISTS.


Your subclass would look something like this:

@interface CustomWindow : UIWindow

@property (nonatomic, retain) UIViewController *rootViewController;

@end

@implementation CustomWindow : UIWindow

static BOOL UIWindowHasRootViewController = NO;

@dynamic rootViewController;

- (void)_findRootViewControllerMethod {
  static dispatch_once_t predicate;
  dispatch_once(&predicate, ^{
    IMP uiwindowMethod = [UIWindow instanceMethodForSelector:@selector(setRootViewController:)];
    IMP customWindowMethod = [CustomWindow instanceMethodForSelector:@selector(setRootViewController:)];
    UIWindowHasRootViewController = (uiwindowMethod != NULL && uiwindowMethod != customWindowMethod);
  });
}

- (UIViewController *)rootViewController {
  [self _findRootViewControllerMethod];
  if (UIWindowHasRootViewController) {
    // this will be a compile error unless you forward declare the property
    // i'll leave as an exercise to the reader ;)
    return [super rootViewController];
  }
  // return the one here on your subclass
}

- (void)setRootViewController:(UIViewController *)rootViewController {
  [self _findRootViewControllerMethod];
  if (UIWindowHasRootViewController) {
    // this will be a compile error unless you forward declare the property
    // i'll leave as an exercise to the reader ;)
    [super setRootViewController:rootViewController];
  } else {
    // set the one here on your subclass
  }
}

Caveat Implementor: I typed this in a browser window

这篇关于iOS:如何知道某个属性是否符合KVO?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆