>> On 3 Feb 2016, at 5:05 PM, Graham Cox <[email protected]
>> <mailto:[email protected]>> wrote:
>>
>> Is there a good way to automate this for a given set of properties?
>
>
> BTW, it would be really great if this were an extension of property
> attributes, e.g:
>
> @property (nonatomic, assign, refresh) BOOL goesWild;
>
> Then the compiler’s synthesis mechanism coould just add the appropriate call
> for views or layers as it finds. For other classes, this flags a warning.
>
> Good idea?
Hi Graham.
I don’t know how to extend language definitions like property attributes, and
further, I’m not sure such attribute could be bound to specific code that will
call setNeedsDisplay on the instance, as language is usually unaware of the
object types being handled.
Yet — your original wish can be easily granted using KVC/KVO protocol, by
creating dependencies.
If, for example, your NSView subclass has 3 properties whose changes should
cause the NSView to setNeedsDisplay — e.g.
@property (nonatomic) NSString *dependentPropertyA;
@property (nonatomic) BOOL dependentPropertyB;
@property (nonatomic) CGColor dependentPropertyC;
You can do the following in your NSView subclass implementation file.
1. Define a single property (e.g. “BOOL viewShouldRefresh) whose change drives
the setNeedsDisplay. It will act like a “calculated property” dependent on your
other properties.
@property (atomic, readonly) BOOL viewShouldRefresh; // atomic, to prevent
reentrance if dependent properties change in different threads.
2. Introduce the following KVC class method, to create dependency of
viewShouldRefresh on the other properties:
+ (NSSet *)keyPathsForValuesAffectingViewShouldRefresh {
return [NSSet setWithObjects: @“dependentPropertyA”,
@“dependentPropertyB”, @“dependentPropertyC” ];
}
3. Implement the getter of viewShouldRefresh (not really necessary, but if you
want to elaborate and add logic that will decide whether or not to refresh
based on actual state of the triggering properties, you can put the logic here.
This is the simplest: any change of any dependent property will refresh the
view.
- (BOOL) viewShouldRefresh:(BOOL) {
return YES;
}
4. Add KVO observation for the viewShouldRefresh to your NSView subclass (say
in the -init)
-(instancetype) init {
…
[self addObserver:self forKeyPath:@“viewShouldRefresh”
options:NSKeyValueObservingOptionNew | options:NSKeyValueObservingOptionOld];
}
-(void) dealloc {
[self removeObserver:self forKeyPath:@“viewShouldRefresh”];
}
5. Finally - add the KVO generic observation method.
- (void)observeValueForKeyPath:(NSString *)keyPath of object:(id)object
change:(NSDictionary *)change context:(void *)context {
if (obj != self || ![keyPath isEqualToString:@“viewShouldRefresh” )
// ignore KVO of other objects and paths.
return;
if (self.viewShouldRefresh) // the property will calculate
the need to refresh — in this sample - always YES.
[self setNeedsDisplay];
}
That’s it.
From now on - adding a new dependent property will be as easy as adding its
name to the NSSet returned by keyPathsForValuesAffectingViewShouldRefresh.
This technique applies of course to CALayers and other things - it’s just
creating the dependency - not dictating the function.
Motti Shneor.
_______________________________________________
Cocoa-dev mailing list ([email protected])
Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com
Help/Unsubscribe/Update your Subscription:
https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com
This email sent to [email protected]