简体   繁体   English

如何干净地覆盖属性设置器?

[英]How do I cleanly override a property setter?

If I want to define a custom UIView subclass that does something when its bounds are set, how do I override the setter? 如果我想定义一个自定义的UIView子类,它在设置边界时做了什么,我该如何覆盖setter? Overriding setBounds seems dangerous since, if I understand correctly, the getter and setter names are not part of the public interface and could change anytime. 覆盖setBounds似乎很危险,因为如果我理解正确,getter和setter名称不是公共接口的一部分,并且可能随时更改。

Of course, I use class_copyPropertyList to query the runtime for a list of properties defined in the class, then query it for the setter's name, and finally use class_addMethod to add the method, after first getting a reference to the earlier method to use for calling the original version. 当然,我使用class_copyPropertyList在运行时查询类中定义的属性列表,然后查询它以获取setter的名称,最后使用class_addMethod添加方法,首先获取对用于调用的早期方法的引用原始版本。

All this seems hacky. 这一切看起来都很糟糕。 Is there a clean way to do what I want, which is guaranteed to not break on future OS versions? 是否有一种干净的方式来做我想要的,保证在未来的操作系统版本上不会中断? Thanks. 谢谢。

You can override a setter/getter without having to poke around the internal state of the class (ie ivars) -- just call the super's methods in your overrides: 你可以覆盖一个setter / getter,而不必嘲笑类的内部状态(即ivars) - 只需在你的覆盖中调用super的方法:

- (Thing *)thing {
    // do your extra stuff here
    //  ...

    return [super thing];
}

- (void)setThing:(Thing *)thing {
    // do your extra stuff here
    //  ...

    [super setThing:thing];
}

An alternative that might suit your problem is to use KVO . 可能适合您的问题的替代方案是使用KVO

Update 更新

Of course, overriding setBounds might not be necessary. 当然,可能没有必要覆盖setBounds See this question -- layoutSubviews gets called if the frame changes, and changing the bounds causes the frame size to also be updated. 看到这个问题 - 如果帧更改,则调用layoutSubviews ,并且更改边界会导致帧大小也更新。 So consider putting your code into layoutSubviews . 因此,请考虑将您的代码放入layoutSubviews

Final update 最后更新

Ok, here is why Apple is never going to suddenly declare some @property items as using a non-standard method names (as you fear): 好的,这就是为什么Apple永远不会突然将某些@property项目声明为使用非标准方法名称(如您所愿):

It would break everything in the app store. 它会破坏应用商店中的所有内容。

Think about it this way: at compile time, any code that accesses a property using dot notation, eg the obj.x syntactic sugar, is converted to a message of the form [obj x] . 可以这样考虑:在编译时,使用点表示法访问属性的任何代码(例如obj.x语法糖)都将转换为[obj x]形式的消息。 Likewise for properties -- they are converted at compile time into regular methods. 同样对于属性 - 它们在编译时转换为常规方法。 So, compiled binaries know nothing about dot notation and properties -- they just call regular selectors. 因此, 编译后的二进制文件对点表示法和属性一无所知 - 它们只调用常规选择器。 So if Apple released an update to iOS that declared some public properties as having non-standard implementation methods, everything in the app store could break. 因此,如果Apple发布iOS更新,声称某些公共属性具有非标准实现方法,那么应用商店中的所有内容都可能会中断。 Everything. 一切。 There is no fault on your behalf in this scenario if your app broke like the rest -- it would be Apple's fault, not yours. 如果您的应用程序像其他应用程序一样崩溃,那么在这种情况下您没有任何错误 - 这将是Apple的错,而不是您的错。

@property(nonatomic) CGRect bounds; 

is shorthand for 是简写

-(CGRect)bounds; 
-(void)setBounds:(CGRect)bounds; 

,

view.bounds = rect; 

is shorthand for 是简写

[view setBounds:rect];

,

CGRect rect = view.bounds;

is shorthand for 是简写

CGRect rect = [view bounds];

Dot notation and @property declarations are SYNTACTIC SUGAR. 点符号和@property声明是SYNTACTIC SUGAR。 They are for shortening code and convenience. 它们用于缩短代码和方便性。 Messages and selectors are always always underneath them, and can always be relied on to be a stable, if not the most stable, part of the interface. 消息和选择器总是位于它们之下,并且始终可以依赖于接口的稳定(如果不是最稳定)部分。

Overriding "setBounds:" is a safe way to do this. 覆盖“setBounds:”是一种安全的方法。 "setBounds:" is not explicitly named in the public interface, because it is declared as a @property. “setBounds:”未在公共接口中显式命名,因为它被声明为@property。 However the standard is that the setter with "set"-capitalized property name is always created (unless its readonly). 但是标准是始终创建具有“set”-capitalized属性名称的setter(除非是readonly)。

There is an NSViewBoundsDidChange notification in OSX. OSX中有一个NSViewBoundsDidChange通知。 That does appear to be the better solution, although fears of overriding the @property methods seem unfounded. 这似乎是更好的解决方案,尽管对覆盖@property方法的担忧似乎没有根据。 I happened on this post with the same question about overriding the accessors, and you have convinced me to prefer notifications. 我在这篇文章中遇到了关于覆盖访问者的相同问题,你说服我更喜欢通知。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM