Re: Easier way to make NSView subclasses refresh on a property change?

2016-02-04 Thread Motti Shneor
>> On 3 Feb 2016, at 5:05 PM, Graham Cox > > 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 (Cocoa-dev@lists.apple.com)

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 arch...@mail-archive.com

Re: Easier way to make NSView subclasses refresh on a property change?

2016-02-03 Thread Keary Suska

> On Feb 2, 2016, at 11:05 PM, Graham Cox  wrote:
> 
> Hi all,
> 
> Whenever I make a custom view class, it often has a bunch of properties that 
> affect the content it renders. So, for each setter that does this, I have to 
> override the setter, do whatever it normally does plus call 
> -setNeedsDisplay:YES.
> 
> This gets tedious.
> 
> Is there a good way to automate this for a given set of properties? I 
> considered overriding -didChangeValueForKey: and checking the key against a 
> set of exported property names, and that would work, except all my custom 
> views would then need to subclass this one special kind of view instead of 
> NSView. Can it be done with a standard NSView? (MacOS)
> 
> A similar requirement applies to CALayer too.

I have had an analogous situation, and my solution, however kludgey, was to 
have a single property, say a BOOL “refresh”, observe that property, and then 
use +keyPathForValuesAffectingKey to notify the observer. In your case the 
observer would call setNeedsDisplay: or whatever was needed.

HTH,

Keary Suska
Esoteritech, Inc.
"Demystifying technology for your home or business"


___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

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 arch...@mail-archive.com

Re: Easier way to make NSView subclasses refresh on a property change?

2016-02-03 Thread Lee Ann Rucker
[self addObserver:self forKeyPaths:[Foo keyPathsThatAffectDisplay] 
...context:SomeUniquePtrValue];

(We have a class addition to NSObject to take an array of keyPaths and lopp 
through addObserver:forKeyPath: etc, because we use multiple key paths 
*everywhere*)

- (void)observeValueForKeyPath: ...
{
  if (context == SomeUniquePtrValue && [ [Foo keyPathsThatAffectDisplay] 
containsObject:keyPath]) 
 [self setNeedsDisplay:YES];
etc
}


> On Feb 2, 2016, at 10:05 PM, Graham Cox  wrote:
> 
> Hi all,
> 
> Whenever I make a custom view class, it often has a bunch of properties that 
> affect the content it renders. So, for each setter that does this, I have to 
> override the setter, do whatever it normally does plus call 
> -setNeedsDisplay:YES.
> 
> This gets tedious.
> 
> Is there a good way to automate this for a given set of properties? I 
> considered overriding -didChangeValueForKey: and checking the key against a 
> set of exported property names, and that would work, except all my custom 
> views would then need to subclass this one special kind of view instead of 
> NSView. Can it be done with a standard NSView? (MacOS)
> 
> A similar requirement applies to CALayer too.
> 
> —Graham
> 
> 
> 
> ___
> 
> Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)
> 
> 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/lrucker%40vmware.com
> 
> This email sent to lruc...@vmware.com


___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

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 arch...@mail-archive.com

Re: Easier way to make NSView subclasses refresh on a property change?

2016-02-03 Thread Alex Zavatone
Set a key value observer for each that would call the refresh method.

If there's a way to cluster them all into a collective set of things that would 
change (I think there may) I'm interested in hearing about it too.

Would it be possible (or wise) to add them to an array or set and put the 
observer on that object?


On Feb 3, 2016, at 10:31 AM, Keary Suska wrote:

> 
>> On Feb 2, 2016, at 11:05 PM, Graham Cox  wrote:
>> 
>> Hi all,
>> 
>> Whenever I make a custom view class, it often has a bunch of properties that 
>> affect the content it renders. So, for each setter that does this, I have to 
>> override the setter, do whatever it normally does plus call 
>> -setNeedsDisplay:YES.
>> 
>> This gets tedious.
>> 
>> Is there a good way to automate this for a given set of properties? I 
>> considered overriding -didChangeValueForKey: and checking the key against a 
>> set of exported property names, and that would work, except all my custom 
>> views would then need to subclass this one special kind of view instead of 
>> NSView. Can it be done with a standard NSView? (MacOS)
>> 
>> A similar requirement applies to CALayer too.
> 
> I have had an analogous situation, and my solution, however kludgey, was to 
> have a single property, say a BOOL “refresh”, observe that property, and then 
> use +keyPathForValuesAffectingKey to notify the observer. In your case the 
> observer would call setNeedsDisplay: or whatever was needed.
> 
> HTH,
> 
> Keary Suska
> Esoteritech, Inc.
> "Demystifying technology for your home or business"
> 
> 
> ___
> 
> Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)
> 
> 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/zav%40mac.com
> 
> This email sent to z...@mac.com


___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

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 arch...@mail-archive.com

Easier way to make NSView subclasses refresh on a property change?

2016-02-02 Thread Graham Cox
Hi all,

Whenever I make a custom view class, it often has a bunch of properties that 
affect the content it renders. So, for each setter that does this, I have to 
override the setter, do whatever it normally does plus call 
-setNeedsDisplay:YES.

This gets tedious.

Is there a good way to automate this for a given set of properties? I 
considered overriding -didChangeValueForKey: and checking the key against a set 
of exported property names, and that would work, except all my custom views 
would then need to subclass this one special kind of view instead of NSView. 
Can it be done with a standard NSView? (MacOS)

A similar requirement applies to CALayer too.

—Graham



___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

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 arch...@mail-archive.com

Re: Easier way to make NSView subclasses refresh on a property change?

2016-02-02 Thread Graham Cox

> On 3 Feb 2016, at 5:05 PM, Graham Cox  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?

—Graham



___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

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 arch...@mail-archive.com