开发者

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? 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.

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.

All this seems hacky. Is the开发者_运维问答re 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 (i.e. ivars) -- just call the super's methods in your overrides:

- (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.

Update

Of course, overriding setBounds might not be necessary. See this question -- layoutSubviews gets called if the frame changes, and changing the bounds causes the frame size to also be updated. So consider putting your code into 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):

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, e.g. the obj.x syntactic sugar, is converted to a message of the form [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. 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.


@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. 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:" is not explicitly named in the public interface, because it is declared as a @property. However the standard is that the setter with "set"-capitalized property name is always created (unless its readonly).


There is an NSViewBoundsDidChange notification in OSX. That does appear to be the better solution, although fears of overriding the @property methods seem unfounded. I happened on this post with the same question about overriding the accessors, and you have convinced me to prefer notifications.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜