Re: Translating KVO-ed property to Swift

2017-04-24 Thread Charles Srstka
> On Apr 24, 2017, at 1:17 PM, Quincey Morris 
>  wrote:
> 
> On Apr 24, 2017, at 10:11 , Charles Srstka  > wrote:
>> 
>> What Quincey seemed to be referring to was a property that was not backed by 
>> any kind of persistent value.
> 
> That wasn’t actually the kind of property I had in mind. I was thinking of 
> settable, computed properties that did not depend on the value(s) of other 
> KVO-observable properties. There probably aren’t many plausible *simple* 
> examples, but I was thinking of such cases as when the value is stored in an 
> I/O device rather than RAM, or when the value is retrieved from a server.

In this case, I would try to see if I could find some way to monitor changes in 
the underlying storage, and call the willChange and didChange methods manually 
when changes occur. I’d only make the property dynamic if it was completely 
impossible to do this, and I’d keep this to a last resort. The reason is 
because in this case, the property is not fully KVO-compliant, because its 
value can change without notifications being sent.

I did kind of touch on this with the UserDefaults-example I provided a while 
back. Pretending that NSUserDefaults still notified via NSNotifications only, 
as was the case before native KVO support was added to it, you would register 
for the NSNotification, check whether your default had changed, and fire the 
willSet and didSet notifications once it did. This is a lot more robust than 
depending on the automatic notifications when your property’s value may change 
without going through the property’s setter.

Charles

___

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: Translating KVO-ed property to Swift

2017-04-24 Thread Quincey Morris
On Apr 24, 2017, at 10:11 , Charles Srstka  wrote:
> 
> What Quincey seemed to be referring to was a property that was not backed by 
> any kind of persistent value.

That wasn’t actually the kind of property I had in mind. I was thinking of 
settable, computed properties that did not depend on the value(s) of other 
KVO-observable properties. There probably aren’t many plausible *simple* 
examples, but I was thinking of such cases as when the value is stored in an 
I/O device rather than RAM, or when the value is retrieved from a server.

One problem with such examples, though, is that it’s not clear in the abstract 
whether you would keep a stored (RAM) value as well. Another problem I’ve been 
brooding over is whether a property (stored or computed) that has KVO 
dependencies can actually be regarded as a dependent property *if it has a 
setter*. Depending on the details, I suspect, the property could be regarded as 
fully dependent, partially dependent, not dependent, or not classifiable.

Separately, I’ve been brooding over the kinds of audiences that might need 
advice (advisories) about using “dynamic”. I think there’s a large fraction of 
the developer population, perhaps a majority, who aren’t aware of the details 
of how KVO notifications are implemented, and an explanation is just a 
distraction that’s more confusing than enlightening. (For any one developer, 
that can change over time, of course.)

This makes me think that there need to be two rules, one simple and one 
advanced, for two different audiences.

The simple rule applies when you allow Cocoa to generate KVO notifications 
automatically (when setters are called or when you use 
“keyPathsForValuesAffecting”), but in deference to Charles’ concerns isn’t 
quite as simple as what the documentation says. It’s now this:

> Add the “dynamic” keyword if the property has a setter.


This covers the cases where “dynamic” is absolutely required (independent 
properties), and it covers all dependent properties without a setter (which, in 
practice, is most of them). It *might* add an unnecessary “dynamic” to a 
computed property with a setter, but I really think it’s the safest solution in 
such cases.

The advanced rule goes something like this:

> For any property with a setter, if you generate notifications manually via 
> willSet/didSet, and you don’t need or want automatic notifications produced 
> by the setter, you must implement “automaticallyNotifiesObserversOf” to 
> return ‘false’, and the property doesn’t need the “dynamic” keyword. 
> Otherwise, add “dynamic” if there is a setter.


That is (I hope/intend) exactly equivalent to what Charles has being saying.

___

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: Translating KVO-ed property to Swift

2017-04-24 Thread Charles Srstka
> On Apr 24, 2017, at 10:07 AM, Richard Charles  wrote:
> 
>> 
>> On Apr 23, 2017, at 11:27 AM, Charles Srstka > > wrote:
>> 
>>> On Apr 20, 2017, at 3:06 PM, Quincey Morris 
>>> >> > wrote:
>>> 
>>> Where I disagree is in your much stronger claim that a computed property is 
>>> *necessarily* a dependent property. I think this is just false. The Swift 
>>> distinction between computed and stored properties is syntactic and has 
>>> nothing to do with KVO**. A KVO-observed computed property should 
>>> therefore, according to the documented principle, be marked “dynamic”. For 
>>> anyone following your extended principle, if it’s also a dependent 
>>> property, they can omit the “dynamic”. If not, not.
>> 
>> Do you have any example of a property not backed by anything where KVO even 
>> makes sense? The whole purpose of KVO is to watch changes to values, and if 
>> there’s no value, it seems like the wrong tool.
> 
> I have a property that returns an array. A setter for this property makes no 
> sense. The property returns a collection of managed objects that is the 
> composite value of several to-many relationships.
> 
> This property is KVO compliant and bound to the NSContentArrayBinding of an 
> array controller.
> 
> There is most likely more than one way to do this but I find using bindings 
> convienient. You can bind to a KVO compliant property. You can't bind to a 
> notification.
> 
> This is in an Objective-C project that requires interoperability with a C++ 
> library. So using Swift is not possible but maybe someday it will be.
> 
> --Richard Charles

But it sounds like this property *is* backed by a value. The backing is the 
collection of managed objects. I take it you’re simply watching changes to the 
C++ source data and calling didChange/willChange when appropriate—basically 
translating one type of notification to another. This makes perfect 
sense—although not having a setter, being marked ‘dynamic’ would not change its 
behavior at all.

What Quincey seemed to be referring to was a property that was not backed by 
any kind of persistent value. Presumably, this property would also have a 
setter, since otherwise ‘dynamic’ isn’t really in play. I’m very curious as to 
what the applicability of such a thing would be, because I can’t think of any 
myself.

Charles

___

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: Translating KVO-ed property to Swift

2017-04-24 Thread Richard Charles

> On Apr 23, 2017, at 11:27 AM, Charles Srstka  wrote:
> 
>> On Apr 20, 2017, at 3:06 PM, Quincey Morris 
>>  wrote:
>> 
>> Where I disagree is in your much stronger claim that a computed property is 
>> *necessarily* a dependent property. I think this is just false. The Swift 
>> distinction between computed and stored properties is syntactic and has 
>> nothing to do with KVO**. A KVO-observed computed property should therefore, 
>> according to the documented principle, be marked “dynamic”. For anyone 
>> following your extended principle, if it’s also a dependent property, they 
>> can omit the “dynamic”. If not, not.
> 
> Do you have any example of a property not backed by anything where KVO even 
> makes sense? The whole purpose of KVO is to watch changes to values, and if 
> there’s no value, it seems like the wrong tool.

I have a property that returns an array. A setter for this property makes no 
sense. The property returns a collection of managed objects that is the 
composite value of several to-many relationships.

This property is KVO compliant and bound to the NSContentArrayBinding of an 
array controller.

There is most likely more than one way to do this but I find using bindings 
convienient. You can bind to a KVO compliant property. You can't bind to a 
notification.

This is in an Objective-C project that requires interoperability with a C++ 
library. So using Swift is not possible but maybe someday it will be.

--Richard Charles

___

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: Translating KVO-ed property to Swift

2017-04-23 Thread Charles Srstka
Sorry I didn’t get around to replying sooner; I’ve had a busy past few days.

> On Apr 20, 2017, at 3:06 PM, Quincey Morris 
>  wrote:
> 
> On Apr 20, 2017, at 10:24 , Charles Srstka  > wrote:
>> 
>> I mean, yes, we could go all the way down to explaining how everything works 
>> in terms of the physics and chemistry of electrons and semiconductors, but 
>> that wouldn’t be very practical, would it?
> 
> I subscribe to the principle already quoted from the documentation: If you 
> KVO-observe a property, mark it “dynamic”. I like this because it is simple 
> and unambiguous. If anyone asked me for advice, I’d say to follow this 
> principle and don’t agonize any further.

It is simple, and it’ll work, and there’s certainly nothing wrong with it. It’s 
a little non-ideal performance-wise, though, which is why I prefer using 
dynamic only where it’s needed.

> As a different discussion, at a different level, I agree that there are 
> scenarios where you can omit “dynamic” and still get all the KVO 
> notifications you wanted. What scenarios? Well, I think the essence of your 
> argument is that it can be omitted for a KVO-observed *dependent* property.

The essence of my argument is pretty simple; it can be omitted for any property 
where willChange and didChange are already being called.

For a dependent property, those calls will be made in your dependency, so you 
don’t need dynamic. For a stored property where you’re calling willChange and 
didChange yourself, you don’t need dynamic. For, I dunno, weird situations 
where willChange and didChange are getting called somewhere else but at the 
appropriate times, you don’t need dynamic. Dynamic is only needed to let Cocoa 
add the willChange and didChange notifications for you.

> That at least sounds pretty plausible to me, and it may even be true by 
> definition. If anyone asked you for advice, then I guess you’d say to accept 
> this as an extension of the documented principle. Me, I’m not 100% certain 
> about this, if for no other reason than the documented principle is 
> future-proof against a change in the way things work where Apple says, “Well, 
> we told to you mark all KVO-observed properties dynamic.” But, people can go 
> for advice where they want.

This isn’t just based on empirical observation, though; it’s based on the 
documentation of the KVO mechanism, which predates Swift by quite a lot. KVO 
isn’t a mysterious black box; the details of it are all available in the 
documentation, and once you understand them, you understand *why* dynamic is 
needed. And once you understand *why* it’s needed, you also will understand 
*where* it’s needed. Personally, I prefer to, when possible, understand the 
reasons behind doing things rather than repeating magical incantations.

As for future-proof, I fully expect that in some future version of Swift (Swift 
5, hopefully, maybe Swift 6), we’ll get a new and improved, Swift-native 
replacement for KVC and KVO and we’ll all be ripping out our existing KVO code 
in favor of that anyway.

> Where I disagree is in your much stronger claim that a computed property is 
> *necessarily* a dependent property. I think this is just false. The Swift 
> distinction between computed and stored properties is syntactic and has 
> nothing to do with KVO**. A KVO-observed computed property should therefore, 
> according to the documented principle, be marked “dynamic”. For anyone 
> following your extended principle, if it’s also a dependent property, they 
> can omit the “dynamic”. If not, not.

Do you have any example of a property not backed by anything where KVO even 
makes sense? The whole purpose of KVO is to watch changes to values, and if 
there’s no value, it seems like the wrong tool.

I mean, sure, I could make this observable:

var whyWouldIObserveThis: Int {
return Int(arc4random())
}

and then send didChange/willChange notifications on a timer or something. 
But... *why?*

Charles

___

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: Translating KVO-ed property to Swift

2017-04-20 Thread Jean-Daniel
Just a tough that go in the ‘always use dynamic’ side. I think setter 
interposition is not the only issue with KVO. KVO also need to be able to fetch 
the old property value when -willChange: is called. I’m not sure about how it 
does that, but I’m pretty confident it will break if the getter is not properly 
exposed in Obj-C, which may be the case if the property is neither declare 
@objc, nor dynamic.

> Le 20 avr. 2017 à 22:06, Quincey Morris  
> a écrit :
> 
> On Apr 20, 2017, at 10:24 , Charles Srstka  wrote:
>> 
>> I mean, yes, we could go all the way down to explaining how everything works 
>> in terms of the physics and chemistry of electrons and semiconductors, but 
>> that wouldn’t be very practical, would it?
> 
> I subscribe to the principle already quoted from the documentation: If you 
> KVO-observe a property, mark it “dynamic”. I like this because it is simple 
> and unambiguous. If anyone asked me for advice, I’d say to follow this 
> principle and don’t agonize any further.
> 
> As a different discussion, at a different level, I agree that there are 
> scenarios where you can omit “dynamic” and still get all the KVO 
> notifications you wanted. What scenarios? Well, I think the essence of your 
> argument is that it can be omitted for a KVO-observed *dependent* property. 
> That at least sounds pretty plausible to me, and it may even be true by 
> definition. If anyone asked you for advice, then I guess you’d say to accept 
> this as an extension of the documented principle. Me, I’m not 100% certain 
> about this, if for no other reason than the documented principle is 
> future-proof against a change in the way things work where Apple says, “Well, 
> we told to you mark all KVO-observed properties dynamic.” But, people can go 
> for advice where they want.
> 
> Where I disagree is in your much stronger claim that a computed property is 
> *necessarily* a dependent property. I think this is just false. The Swift 
> distinction between computed and stored properties is syntactic and has 
> nothing to do with KVO**. A KVO-observed computed property should therefore, 
> according to the documented principle, be marked “dynamic”. For anyone 
> following your extended principle, if it’s also a dependent property, they 
> can omit the “dynamic”. If not, not.
> 
> 
> ** Indeed, it’s trivially easy to convert a public stored property into a 
> public computed property that uses a private, stored, non-KVO-observed 
> property as its instance storage.
> 
> ___
> 
> 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/mailing%40xenonium.com
> 
> This email sent to mail...@xenonium.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: Translating KVO-ed property to Swift

2017-04-20 Thread Quincey Morris
On Apr 20, 2017, at 10:24 , Charles Srstka  wrote:
> 
> I mean, yes, we could go all the way down to explaining how everything works 
> in terms of the physics and chemistry of electrons and semiconductors, but 
> that wouldn’t be very practical, would it?

I subscribe to the principle already quoted from the documentation: If you 
KVO-observe a property, mark it “dynamic”. I like this because it is simple and 
unambiguous. If anyone asked me for advice, I’d say to follow this principle 
and don’t agonize any further.

As a different discussion, at a different level, I agree that there are 
scenarios where you can omit “dynamic” and still get all the KVO notifications 
you wanted. What scenarios? Well, I think the essence of your argument is that 
it can be omitted for a KVO-observed *dependent* property. That at least sounds 
pretty plausible to me, and it may even be true by definition. If anyone asked 
you for advice, then I guess you’d say to accept this as an extension of the 
documented principle. Me, I’m not 100% certain about this, if for no other 
reason than the documented principle is future-proof against a change in the 
way things work where Apple says, “Well, we told to you mark all KVO-observed 
properties dynamic.” But, people can go for advice where they want.

Where I disagree is in your much stronger claim that a computed property is 
*necessarily* a dependent property. I think this is just false. The Swift 
distinction between computed and stored properties is syntactic and has nothing 
to do with KVO**. A KVO-observed computed property should therefore, according 
to the documented principle, be marked “dynamic”. For anyone following your 
extended principle, if it’s also a dependent property, they can omit the 
“dynamic”. If not, not.


** Indeed, it’s trivially easy to convert a public stored property into a 
public computed property that uses a private, stored, non-KVO-observed property 
as its instance storage.

___

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: Translating KVO-ed property to Swift

2017-04-20 Thread Charles Srstka
> On Apr 19, 2017, at 9:12 PM, Quincey Morris 
>  wrote:
> 
> On Apr 19, 2017, at 15:49 , Charles Srstka  wrote:
>> 
>> Cocoa automagically does its secret subclass thing to wrap the setter and 
>> call the didChange/willChange calls for any property you didn’t tell it not 
>> to do. It needs the property to be dynamic for this to work. 
> 
> Yes, that’s almost exactly what I said**. But it still doesn’t make the 
> “dynamic” keyword an on/off switch. Again, the KVO notifications aren’t 
> activated *because* the method has the Swift-specific dynamic attribute, but 
> because the method uses Obj-C dispatching. The “dynamic” keyword [currently] 
> forces the method to use Obj-C dispatching, but the reverse isn’t true. In 
> the absence of the keyword, there’s nothing formally stopping the compiler 
> from using Obj-C dispatching if it chooses to.
> 
> At some level, though, I’m prepared to stipulate that it’s a distinction 
> without much practical difference.

The statement didn’t say anything about “dynamic” being an “on/off switch.” The 
statement that you were quibbling was that you can mark a stored property as 
‘dynamic’, and Cocoa will do the rest. It didn’t say anything about what 
*causes* it, it was meant to be a practical guide to how to implement KVO 
properties in Swift. And to make Cocoa automatically handle the 
didChange/willChange calls, you mark a property as dynamic. I mean, yes, we 
could go all the way down to explaining how everything works in terms of the 
physics and chemistry of electrons and semiconductors, but that wouldn’t be 
very practical, would it?

>> I should add that if a computed property needs ‘dynamic’ in order for its 
>> notifications to fire, the property is not properly KVO-compliant.
> 
> It’s impossible to say in general what counts as a change to a mutable 
> property. Indeed it’s perfectly possible for a property to exist for the 
> purpose of generating KVO notifications without having any meaningful value, 
> and there are plenty more un-generalizable considerations:

The entire purpose of KVO is to monitor changes to values. The word “value” is 
literally right there in the title, as well as most of the major APIs that make 
it work. observeValue. willChangeValue. didChangeValue. value(forKey:). 
setValue. keyPathsForValuesAffecting. Using KVO without a meaningful value is, 
frankly, using a hammer to drive in a screw. For a value-less notification, 
something like NSNotificationCenter is a much better choice.

> — It’s up to an individual property (with a meaningful value) to decide 
> whether KVO notifications are issued when the setter is called (in effect, 
> the default case) or when the value actually changes (as in Rick’s original 
> code), or under some other conditions (e.g. I can imagine a property limiting 
> the rate of notifications using a timer).

Which does not require a property to be dynamic, and in fact would require 
*disabling* Cocoa’s use of dynamism for the property, via returning false for 
automaticallyNotifiesObserversOf.

> — There’s no general presumption whether the value returned by the getter is 
> synchronized with the value passed to the setter.

The setter, however, is likely to make some kind of change to the underlying 
storage such that we will be notified of it. And if no such change is made, 
then there is little point in sending change notifications.

> — There’s no general presumption whether the value returned by the getter is 
> synchronized with the notification, in a multi-threaded environment.

Assuming you’re referring to the fact that something in another thread could 
change the property in the middle of your observer, this still has little that 
I can see to do with the ‘dynamic’ keyword.

> — There’s no general presumption that KVO notifications originate in the 
> property's setter at all, or in the setter only.
> 
> Etc. “keyPathsForValuesAffecting…”-style dependencies are just a convenient 
> short-cut to a specific, simple, typical behavior.

Who said there was?

The bottom line with KVO notifications is that you’ll get one when either:
1. willChange and didChange get called for the property you’re 
watching, or
2. willChange and didChange get called for something that the property 
you’re watching is dependent on.

In case 1, you can either call willChange or didChange yourself, or you can let 
Cocoa do it for you. In Swift, you need to mark it ‘dynamic’ for the latter to 
happen.

In case 2, you don’t need willChange or didChange to get called for your 
property, because we will already get notified when the dependency’s willChange 
and didChange get called. In fact, we might not want them to, because it’ll 
cause the notification to double-post—once in the setter, and then again in the 
dependency’s setter, as in the example below:

> import Foundation
> 
> class Foo: NSObject {
>   @objc dynamic var bar: String = ""
>  

Re: Translating KVO-ed property to Swift

2017-04-19 Thread Quincey Morris
On Apr 19, 2017, at 15:49 , Charles Srstka  wrote:
> 
> Cocoa automagically does its secret subclass thing to wrap the setter and 
> call the didChange/willChange calls for any property you didn’t tell it not 
> to do. It needs the property to be dynamic for this to work. 

Yes, that’s almost exactly what I said**. But it still doesn’t make the 
“dynamic” keyword an on/off switch. Again, the KVO notifications aren’t 
activated *because* the method has the Swift-specific dynamic attribute, but 
because the method uses Obj-C dispatching. The “dynamic” keyword [currently] 
forces the method to use Obj-C dispatching, but the reverse isn’t true. In the 
absence of the keyword, there’s nothing formally stopping the compiler from 
using Obj-C dispatching if it chooses to.

At some level, though, I’m prepared to stipulate that it’s a distinction 
without much practical difference.

> I should add that if a computed property needs ‘dynamic’ in order for its 
> notifications to fire, the property is not properly KVO-compliant.

It’s impossible to say in general what counts as a change to a mutable 
property. Indeed it’s perfectly possible for a property to exist for the 
purpose of generating KVO notifications without having any meaningful value, 
and there are plenty more un-generalizable considerations:

— It’s up to an individual property (with a meaningful value) to decide whether 
KVO notifications are issued when the setter is called (in effect, the default 
case) or when the value actually changes (as in Rick’s original code), or under 
some other conditions (e.g. I can imagine a property limiting the rate of 
notifications using a timer).

— There’s no general presumption whether the value returned by the getter is 
synchronized with the value passed to the setter.

— There’s no general presumption whether the value returned by the getter is 
synchronized with the notification, in a multi-threaded environment.

— There’s no general presumption that KVO notifications originate in the 
property's setter at all, or in the setter only.

Etc. “keyPathsForValuesAffecting…”-style dependencies are just a convenient 
short-cut to a specific, simple, typical behavior.



** Incidentally, when I was testing in Swift, I didn’t see any indication the 
backtrace that a subclass was being used, or that any actual swizzling was 
being done. It looked more like the dynamic dispatch was diverted to a 
general-purpose function that generated the notifications around the actual 
setter invocation. Here’s a partial backtrace when a breakpoint in the 
“version” didSet accessor was hit:

frame #0: 0x0001190b 
TestKVO`ViewController.version.willset(newValue="1", self=0x618000100900) 
at ViewController.swift:16
frame #1: 0x00011877 
TestKVO`ViewController.version.setter(newValue="1", self=0x618000100900) at 
ViewController.swift:0
frame #2: 0x000117d8 TestKVO`@objc ViewController.version.setter at 
ViewController.swift:0
frame #3: 0x7fff91d6c897 
Foundation`-[NSObject(NSKeyValueObservingPrivate) 
_changeValueForKeys:count:maybeOldValuesDict:usingBlock:] + 848
frame #4: 0x7fff91bf1c7d 
Foundation`-[NSObject(NSKeyValueObservingPrivate) 
_changeValueForKey:key:key:usingBlock:] + 60
frame #5: 0x7fff91c5a55b Foundation`_NSSetObjectValueAndNotify + 261
frame #6: 0x0001310f 
TestKVO`ViewController.buttonClicked(sender=some, self=0x618000100900) -> 
() at ViewController.swift:57
frame #7: 0x00013200 TestKVO`@objc 
ViewController.buttonClicked(Any?) -> () at ViewController.swift:0
frame #8: 0x7fffa5b903a7 
libsystem_trace.dylib`_os_activity_initiate_impl + 53
frame #9: 0x7fff8e475791 AppKit`-[NSApplication(NSResponder) 
sendAction:to:from:] + 456

and here is a disassembly of the Swift code (frame 6) that invokes the setter:

0x130f2 <+434>: movq   0x3ebf(%rip), %rsi; "setVersion:"
0x130f9 <+441>: movq   %rax, %rcx
0x130fc <+444>: movq   -0x20(%rbp), %rdx
0x13100 <+448>: movq   %rdx, %rdi
0x13103 <+451>: movq   %rcx, %rdx
0x13106 <+454>: movq   %rax, -0x80(%rbp)
0x1310a <+458>: callq  0x147d2   ; symbol stub for: 
objc_msgSend

That is, the objc_msgSend ended up in the Foundation function 
_NSSetObjectValueAndNotify. I traced through the objc_msgSend, and it goes 
straight to _NSSetObjectValueAndNotify from the method dispatch tables.

Just an interesting sidelight to this discussion. In the old days, you could 
definitely see the secret subclass if you looked.

___

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 

Re: Translating KVO-ed property to Swift

2017-04-19 Thread Charles Srstka
> On Apr 19, 2017, at 4:50 PM, Quincey Morris 
>  wrote:
> 
>> 3. Computed properties do not need to be dynamic, […].
> 
> This is also not exactly true. Computed properties that have only a getter do 
> not need to be dynamic, because they don’t generate any KVO notifications via 
> a setter, and so “dynamic” is irrelevant.
> 
> However, a computed property that has a setter will *not* produce the 
> expected notifications unless it is marked “dynamic”, even if marked “@objc”. 
> (I tested this to be sure.) There’s nothing special about computed vs. stored 
> properties in this regard.

I should add that if a computed property needs ‘dynamic’ in order for its 
notifications to fire, the property is not properly KVO-compliant. There are 
three ways this could happen that I can think of off the top of my head:

Case #1: Derived from another KVO property

> @objc dynamic var foo: String
> 
> @objc var bar: String {
>   get { return self.foo }
>   set { self.foo = newValue }
> }

The above will not fire notifications for bar. Making bar ‘dynamic’ appears to 
fix the problem, but it is in fact still not compliant; if foo changes, bar’s 
value is changed as well, but its notifications will not fire. The proper way 
to fix this is to add keyPathsForValuesAffectingBar.

Case #2: Backed by something not exposed to Objective-C

> enum Option: String {
>   case foo = “Foo"
>   case bar = “Bar"
>   case baz = “Baz"
> }
> 
> var option: Option
> 
> @objc var objcOption: String {
>   get { return self.option.rawValue }
>   set {
>   if let option = Option(rawValue: newValue) {
>   self.option = option
>   }
>   }
> }

The above will not fire notifications for objcOption. Making objcOption 
‘dynamic’ appears to fix the problem, but if option is changed, objcOptions’s 
value will change as well, and its notifications will not fire. The proper way 
to fix this is to add willChangeValue(forKey:) and didChangeValue(forKey:) 
calls in option’s willSet and didSet accessors.

Case #3: It’s backed by something other than a property

> @objc var isFoo: Bool {
>   get { return UserDefaults.bool(forKey: “Foo”) }
>   set { UserDefaults.set(newValue, forKey: “Foo”) }
> }

The above will not fire notifications for isFoo. Making isFoo ‘dynamic’ appears 
to fix the problem, but if the “Foo” defaults key changes by some mechanism 
other than isFoo’s setter, isFoo’s value will have changed, but the 
notifications will not fire. The better solution is to register for changes on 
UserDefaults or NSUserDefaultsController via one of the several available 
mechanisms that Cocoa provides to do that and ensure that isFoo’s clients are 
notified when the underlying value changes.

Charles

___

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: Translating KVO-ed property to Swift

2017-04-19 Thread Charles Srstka
> On Apr 19, 2017, at 4:50 PM, Quincey Morris 
>  wrote:
> 
> On Apr 19, 2017, at 10:56 , Charles Srstka  wrote:
>> 
>> 2. Stored properties need to call willChangeValue(forKey:) and 
>> didChangeValue(forKey:).
>>  a. In most cases, just add “dynamic” to the property declaration, and 
>> Cocoa will automagically insert the needed calls.
> 
> The problem with saying it this way is that it can be taken to imply that the 
> calls will be inserted statically *into the setter’s implementation*, which 
> is not true. It is true that Cocoa will automagically *execute* the needed 
> calls.
> 
> It also can be taken to imply that Cocoa does this automagically because the 
> property is dynamic, which is also not really true. Cocoa does this because 
> it’s a setter for an Obj-C property which returns true from its corresponding 
> automaticallyNotifiesObserversOfFoo class method. That is, “dynamic” doesn’t 
> turn the automagic behavior off or on, it’s simply a requirement to ensure 
> that the property is fully in the Obj-C domain.

Cocoa automagically does its secret subclass thing to wrap the setter and call 
the didChange/willChange calls for any property you didn’t tell it not to do. 
It needs the property to be dynamic for this to work. Thus, if you add 
“dynamic” to the property declaration, Cocoa will do the rest. That’s really 
all that’s relevant from a usage standpoint.

>> 3. Computed properties do not need to be dynamic, […].
> 
> This is also not exactly true. Computed properties that have only a getter do 
> not need to be dynamic, because they don’t generate any KVO notifications via 
> a setter, and so “dynamic” is irrelevant.
> 
> However, a computed property that has a setter will *not* produce the 
> expected notifications unless it is marked “dynamic”, even if marked “@objc”. 
> (I tested this to be sure.) There’s nothing special about computed vs. stored 
> properties in this regard.
> 
> I think you were “really” talking about derived properties, which are 
> typically computed properties with only a getter, no setter.

Nope, you can have a setter. You just have to make sure you’ve properly set up 
keyPathsForValuesAffecting. Here is some test code you can run yourself 
and verify this:

> import Foundation
> 
> class Foo: NSObject {
>   @objc dynamic var bar: String = ""
>   
>   @objc private static let keyPathsForValuesAffectingBaz: Set = 
> [#keyPath(bar)]
>   @objc var baz: String {
>   get { return self.bar }
>   set { self.bar = newValue }
>   }
>   
>   private var kvoContext = 0
>   
>   override init() {
>   super.init()
>   self.addObserver(self, forKeyPath: #keyPath(baz), options: [], 
> context: )
>   }
>   
>   override func observeValue(forKeyPath keyPath: String?, of object: 
> Any?, change: [NSKeyValueChangeKey : Any]?, context: 
> UnsafeMutableRawPointer?) {
>   if context ==  {
>   print("baz changed to \(self.baz)")
>   } else {
>   super.observeValue(forKeyPath: keyPath, of: object, 
> change: change, context: context)
>   }
>   }
> }
> 
> let foo = Foo()
> 
> foo.bar = "Bar"
> foo.baz = “Baz"

When run, this outputs:

baz changed to Bar
baz changed to Baz

Exactly as you would expect.

> In addition, “dynamic” is documented as needed, in the place I linked to 
> before:
> 
>   
> https://developer.apple.com/library/content/documentation/Swift/Conceptual/BuildingCocoaApps/AdoptingCocoaDesignPatterns.html#//apple_ref/doc/uid/TP40014216-CH7-ID6
> 
> under the heading Key-Value Observing where it says: "Add the dynamic 
> modifier to any property you want to observe.” This may be overly 
> conservative, but it is at least official.
> 
> For all those reasons, I think it’s pointless to try to figure out the 
> contexts where “dynamic” is unnecessary. It seems to me that the best advice 
> is that from the documentation: unconditionally add “dynamic” to any property 
> you want to observe. (Well, in the future, add “@objc dynamic”.)

It’s an oversimplification. If you understand the reasons why the ‘dynamic’ 
keyword is necessary, you will also be able to identify where it serves solely 
as unnecessary overhead.

Charles

___

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: Translating KVO-ed property to Swift

2017-04-19 Thread Quincey Morris
On Apr 19, 2017, at 10:56 , Charles Srstka  wrote:
> 
> 2. Stored properties need to call willChangeValue(forKey:) and 
> didChangeValue(forKey:).
>   a. In most cases, just add “dynamic” to the property declaration, and 
> Cocoa will automagically insert the needed calls.

The problem with saying it this way is that it can be taken to imply that the 
calls will be inserted statically *into the setter’s implementation*, which is 
not true. It is true that Cocoa will automagically *execute* the needed calls.

It also can be taken to imply that Cocoa does this automagically because the 
property is dynamic, which is also not really true. Cocoa does this because 
it’s a setter for an Obj-C property which returns true from its corresponding 
automaticallyNotifiesObserversOfFoo class method. That is, “dynamic” doesn’t 
turn the automagic behavior off or on, it’s simply a requirement to ensure that 
the property is fully in the Obj-C domain.

> 3. Computed properties do not need to be dynamic, […].

This is also not exactly true. Computed properties that have only a getter do 
not need to be dynamic, because they don’t generate any KVO notifications via a 
setter, and so “dynamic” is irrelevant.

However, a computed property that has a setter will *not* produce the expected 
notifications unless it is marked “dynamic”, even if marked “@objc”. (I tested 
this to be sure.) There’s nothing special about computed vs. stored properties 
in this regard.

I think you were “really” talking about derived properties, which are typically 
computed properties with only a getter, no setter.

In addition, “dynamic” is documented as needed, in the place I linked to before:


https://developer.apple.com/library/content/documentation/Swift/Conceptual/BuildingCocoaApps/AdoptingCocoaDesignPatterns.html#//apple_ref/doc/uid/TP40014216-CH7-ID6
 


under the heading Key-Value Observing where it says: "Add the dynamic modifier 
to any property you want to observe.” This may be overly conservative, but it 
is at least official.

For all those reasons, I think it’s pointless to try to figure out the contexts 
where “dynamic” is unnecessary. It seems to me that the best advice is that 
from the documentation: unconditionally add “dynamic” to any property you want 
to observe. (Well, in the future, add “@objc dynamic”.)


___

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: Translating KVO-ed property to Swift

2017-04-19 Thread Charles Srstka
> On Apr 17, 2017, at 7:40 AM, Jean-Daniel  wrote:
> 
>> Le 17 avr. 2017 à 10:52, Quincey Morris > > a écrit :
>> 
>> On Apr 17, 2017, at 01:43 , Jean-Daniel >  > >> wrote:
>>> 
>>> var version: String? {
>> 
>> A slight correction: this declaration actually must be:
>> 
>>> dynamic var version: String? {
>> 
>> 
>> otherwise KVO isn’t guaranteed to work in Swift.
> 
> This is a good practice, but I don’t think this is required for computed 
> property, especially if you take care of willChange/didChange manually, as 
> the OP does.

Here’s the set of rules I recommend for writing KVO-compliant properties in 
Swift:

1. Always put @objc in front of every declaration involved, whether it’s the 
property itself or the static properties that are there to support it.

2. Stored properties need to call willChangeValue(forKey:) and 
didChangeValue(forKey:).
a. In most cases, just add “dynamic” to the property declaration, and 
Cocoa will automagically insert the needed calls.
b. If you call willChangeValue and didChangeValue manually, add the 
following static property, changing Foo to the property’s name. Since this is 
easy to misspell accidentally, it’s best to make an Xcode code snippet for it.

@objc private static let automaticallyNotifiesObserversOfFoo = false

3. Computed properties do not need to be dynamic, but should register their 
dependencies. The properties that form these dependencies also need to be 
KVO-compliant. To register dependencies, add the following static property. 
This is also helpful to set as an Xcode snippet to avoid typos.

@objc private static let keyPathsForValuesAffectingFoo: Set = 
[#keyPath(bar)]

The snippet above tells Cocoa that the KVO-compliant property “foo” depends on 
the KVO-compliant property “bar”, meaning that if “bar” changes, “foo”’s 
observers will be notified as well.

Charles

___

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: Translating KVO-ed property to Swift

2017-04-17 Thread Rick Mann
Thanks, Charles, that's helpful. In the end I left the class as Obj-C, because 
I still had to derive from it in Obj-C and you annoyingly can't do that.

> On Apr 17, 2017, at 08:06 , Charles Srstka  wrote:
> 
>> On Apr 17, 2017, at 3:24 AM, Rick Mann  wrote:
>> 
>> I have a number of properties in Objective-C written like this, 
>> short-circuiting notifications when the value doesn't change:
>> 
>> -
>> @synthesize version = mVersion
>> 
>> - (void)
>> setVersion: (NSString *) inVersion
>> {
>>if (inVersion == nil && mVersion == nil)
>>{
>>return;
>>}
>>if ([inVersion isEqualToString: mVersion])
>>{
>>return;
>>}
>> 
>>[self willChangeValueForKey: @"version"];
>>mVersion = inVersion;
>>[self didChangeValueForKey: @"version"];
>> }
>> -
>> 
>> Now I want to translate this method into Swift. Thing is, AFAIK you can't 
>> name the ivar created for a property. Is there a way to translate this to 
>> swift?
> 
> I’ve been converting a lot of KVO properties to Swift lately. Here’s how I’d 
> do this:
> 
> // Only needed if the property will be accessed by Objective-C code, since 
> Swift code won’t see the swizzled accessors anyway for a non-dynamic property.
> // @objc annotation is needed on every method we write here, since otherwise 
> it’ll quit working when @objc inference is removed in Swift 4 (SE-0160)
> @objc private static let automaticallyNotifiesObserversOfVersion: Bool = false
> 
> // Our actual version property. If you want, you can create a private 
> property named “mVersion” and it will function like an instance variable.
> // But I’d probably just use willSet and didSet.
> // Note that this doesn’t need to be dynamic, since we are not relying on 
> Cocoa’s built-in automatic swizzling,
> // which is only needed if we are not calling willChangeValue(forKey:) and 
> didChangeValue(forKey:) ourselves.
> @objc var version: String {
> willSet {
> // Send the willChange notification, if the value is different from 
> its old value.
> if newValue != self.version {
> self.willChangeValue(forKey: #keyPath(version))
> }
> }
> didSet {
> // Send the didChange notification, if the value is different from 
> its old value.
> if oldValue != self.version {
> self.didChangeValue(forKey: #keyPath(version))
> }
> }
> }
> 
> Charles
> 


-- 
Rick Mann
rm...@latencyzero.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: Translating KVO-ed property to Swift

2017-04-17 Thread Quincey Morris
On Apr 17, 2017, at 12:03 , Charles Srstka  wrote:
> 
> You cannot guarantee that the property will be called via objc_msgSend, which 
> is important if you’re relying on the swizzled accessor to send the property 
> notifications. If you’re sending them yourself, it doesn’t matter one way or 
> another how the property was called, as long as you add @objc so that clients 
> that do expect to be able to use objc_msgSend (most importantly, NSObject’s 
> observation support) can do it.

If you’re sending them yourself, then what matters is that you don’t 
*accidentally* let the property generate automatic notifications as well. There 
is only one way (AFAIK) to *guarantee* that automatic notifications aren’t 
generated as well, and that’s by returning false from 
‘automaticallyNotifiesObserversOfVersion’. There’s no other way in Swift 
(AFAIK) to ensure that, since there’s no “nondynamic” keyword. There’s also no 
other way in Obj-C (AFAIK) to ensure that.

This issue wasn’t supposed to be about Swift, though Swift makes it a bit 
murkier. Rick’s original code was wrong unless he had an Obj-C 
automaticallyNotifiesObserversOfVersion method elsewhere. For all I know, since 
he didn’t weigh back in with more information, he had that method all along.

> You also forgot the automaticallyNotifiesObserversOfVersion property in the 
> first bit of my example.

Yes, sorry, I just didn’t see it tucked up against the comment. Your code was 
correct in every detail.

___

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: Translating KVO-ed property to Swift

2017-04-17 Thread Charles Srstka
> On Apr 17, 2017, at 1:09 PM, Quincey Morris 
>  wrote:
> 
> On Apr 17, 2017, at 05:40 , Jean-Daniel  wrote:
> 
>> This is a good practice, but I don’t think this is required for computed 
>> property, especially if you take care of willChange/didChange manually, as 
>> the OP does.
> 
> Here is what the Swift interoperability documentation says 
> (https://developer.apple.com/library/content/documentation/Swift/Conceptual/BuildingCocoaApps/AdoptingCocoaDesignPatterns.html):

And the reason for this is because Cocoa swizzles the accessor and adds the 
willChangeValue() and didChangeValue() calls. If you’re calling these yourself 
(or if you’re a computed property that registers its dependencies via 
keyPathsForValuesAffecting methods), you don’t need dynamic.

>> "You can use key-value observing with a Swift class, as long as the class 
>> inherits from the NSObject class. You can use these three steps to implement 
>> key-value observing in Swift.
>> 
>> "1. Add the dynamic modifier to any property you want to observe. […]”
> 
> Here is what the Swift language documentation says 
> (https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/Declarations.html):
> 
>> “dynamic”
>> 
>> "Apply this modifier to any member of a class that can be represented by 
>> Objective-C. When you mark a member declaration with the dynamic modifier, 
>> access to that member is always dynamically dispatched using the Objective-C 
>> runtime. Access to that member is never inlined or devirtualized by the 
>> compiler.”
> 
> That is, unless you specify “dynamic” there’s no *guarantee* that invocations 
> to the property accessors will use obj_msgSend, and since there’s no way in 
> Swift to guarantee that obj_msgSend *won’t* be used for the property, the 
> outcome for automatic KVO is unpredictable. 

You cannot guarantee that the property will be called via objc_msgSend, which 
is important if you’re relying on the swizzled accessor to send the property 
notifications. If you’re sending them yourself, it doesn’t matter one way or 
another how the property was called, as long as you add @objc so that clients 
that do expect to be able to use objc_msgSend (most importantly, NSObject’s 
observation support) can do it.

> On Apr 17, 2017, at 08:07 , Charles Srstka  wrote:
>> 
>> // Note that this doesn’t need to be dynamic, since we are not relying on 
>> Cocoa’s built-in automatic swizzling,
>> // which is only needed if we are not calling willChangeValue(forKey:) and 
>> didChangeValue(forKey:) ourselves.
>> @objc var version: String {
>>willSet {
>>// Send the willChange notification, if the value is different from 
>> its old value.
>>if newValue != self.version {
>>self.willChangeValue(forKey: #keyPath(version))
>>}
>>}
>>didSet {
>>// Send the didChange notification, if the value is different from 
>> its old value.
>>if oldValue != self.version {
>>self.didChangeValue(forKey: #keyPath(version))
>>}
>>}
>> }
> 
> I tested what happens (in Swift 3.1, Xcode 8.3.1) using this code:
> 
>> private var versionContext = 0
>> 
>> class ViewController: NSViewController {
>>  @objc /*dynamic*/ var version: String = “” {
>>  willSet {
>>  if newValue != self.version {
>>  self.willChangeValue (forKey: 
>> #keyPath(version)) }
>>  }
>>  didSet {
>>  if oldValue != self.version {
>>  self.didChangeValue (forKey: #keyPath(version)) 
>> }
>>  }
>>  }
>>  override func viewDidLoad () {
>>  super.viewDidLoad ()
>>  addObserver (self, forKeyPath: #keyPath(version), options: [], 
>> context: )
>>  }
>>  override func observeValue (forKeyPath keyPath: String?,  of object: 
>> Any?,  change: [NSKeyValueChangeKey : Any]?,  context: 
>> UnsafeMutableRawPointer?) {
>>  print ("observedValue for \(version)")
>>  }
>>  @IBAction func buttonClicked (_ sender: Any?) { // There’s a button in 
>> the UI hooked up to this
>>  version = version == "" ? "1" : "\(version)"
>>  }
>> }
> 
> This version of the code (with “dynamic” commented out) displays the observer 
> message once, as desired, and then not again, as desired. Uncommenting 
> “dynamic” causes the message to be displayed twice the first time, and then 
> once more every subsequent button click.
> 
> So, Charles’s approach *appears* to work, because the “version” property 
> isn’t participating in automatic swizzling. However, it’s subtly wrong 
> because there’s no way to prevent other source code from leading the compiler 
> to *deduce* that the method is dynamic. Once that happens, there’s an extra 
> unwanted notification every time the property is set.


Re: Translating KVO-ed property to Swift

2017-04-17 Thread Quincey Morris
On Apr 17, 2017, at 05:40 , Jean-Daniel  wrote:

> This is a good practice, but I don’t think this is required for computed 
> property, especially if you take care of willChange/didChange manually, as 
> the OP does.

Here is what the Swift interoperability documentation says 
(https://developer.apple.com/library/content/documentation/Swift/Conceptual/BuildingCocoaApps/AdoptingCocoaDesignPatterns.html):

> "You can use key-value observing with a Swift class, as long as the class 
> inherits from the NSObject class. You can use these three steps to implement 
> key-value observing in Swift.
> 
> "1. Add the dynamic modifier to any property you want to observe. […]”

Here is what the Swift language documentation says 
(https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/Declarations.html):

> “dynamic”
> 
> "Apply this modifier to any member of a class that can be represented by 
> Objective-C. When you mark a member declaration with the dynamic modifier, 
> access to that member is always dynamically dispatched using the Objective-C 
> runtime. Access to that member is never inlined or devirtualized by the 
> compiler.”


That is, unless you specify “dynamic” there’s no *guarantee* that invocations 
to the property accessors will use obj_msgSend, and since there’s no way in 
Swift to guarantee that obj_msgSend *won’t* be used for the property, the 
outcome for automatic KVO is unpredictable. 

On Apr 17, 2017, at 08:07 , Charles Srstka  wrote:
> 
> // Note that this doesn’t need to be dynamic, since we are not relying on 
> Cocoa’s built-in automatic swizzling,
> // which is only needed if we are not calling willChangeValue(forKey:) and 
> didChangeValue(forKey:) ourselves.
> @objc var version: String {
>willSet {
>// Send the willChange notification, if the value is different from 
> its old value.
>if newValue != self.version {
>self.willChangeValue(forKey: #keyPath(version))
>}
>}
>didSet {
>// Send the didChange notification, if the value is different from its 
> old value.
>if oldValue != self.version {
>self.didChangeValue(forKey: #keyPath(version))
>}
>}
> }

I tested what happens (in Swift 3.1, Xcode 8.3.1) using this code:

> private var versionContext = 0
> 
> class ViewController: NSViewController {
>   @objc /*dynamic*/ var version: String = “” {
>   willSet {
>   if newValue != self.version {
>   self.willChangeValue (forKey: 
> #keyPath(version)) }
>   }
>   didSet {
>   if oldValue != self.version {
>   self.didChangeValue (forKey: #keyPath(version)) 
> }
>   }
>   }
>   override func viewDidLoad () {
>   super.viewDidLoad ()
>   addObserver (self, forKeyPath: #keyPath(version), options: [], 
> context: )
>   }
>   override func observeValue (forKeyPath keyPath: String?,  of object: 
> Any?,  change: [NSKeyValueChangeKey : Any]?,  context: 
> UnsafeMutableRawPointer?) {
>   print ("observedValue for \(version)")
>   }
>   @IBAction func buttonClicked (_ sender: Any?) { // There’s a button in 
> the UI hooked up to this
>   version = version == "" ? "1" : "\(version)"
>   }
> }

This version of the code (with “dynamic” commented out) displays the observer 
message once, as desired, and then not again, as desired. Uncommenting 
“dynamic” causes the message to be displayed twice the first time, and then 
once more every subsequent button click.

So, Charles’s approach *appears* to work, because the “version” property isn’t 
participating in automatic swizzling. However, it’s subtly wrong because 
there’s no way to prevent other source code from leading the compiler to 
*deduce* that the method is dynamic. Once that happens, there’s an extra 
unwanted notification every time the property is set.

And again, in the converse scenario (automatic KVO, where you want 
notifications unconditionally) the “dynamic” keyword isn’t optional.

The correct solution, I claim, is to replace the declaration of “version” with 
this:

>   static func automaticallyNotifiesObserversOfVersion () -> Bool { return 
> false }
>   @objc dynamic var version: String = “” { … }

and then use either Charles’ or Jean-Daniel’s logic to generate the 
notifications manually as desired.

(BTW, the “@objc” is currently redundant, but will soon become required, via 
SE-0160 
.)


___

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 

Re: Translating KVO-ed property to Swift

2017-04-17 Thread Charles Srstka
> On Apr 17, 2017, at 3:24 AM, Rick Mann  wrote:
> 
> I have a number of properties in Objective-C written like this, 
> short-circuiting notifications when the value doesn't change:
> 
> -
> @synthesize version = mVersion
> 
> - (void)
> setVersion: (NSString *) inVersion
> {
>if (inVersion == nil && mVersion == nil)
>{
>return;
>}
>if ([inVersion isEqualToString: mVersion])
>{
>return;
>}
> 
>[self willChangeValueForKey: @"version"];
>mVersion = inVersion;
>[self didChangeValueForKey: @"version"];
> }
> -
> 
> Now I want to translate this method into Swift. Thing is, AFAIK you can't 
> name the ivar created for a property. Is there a way to translate this to 
> swift?

I’ve been converting a lot of KVO properties to Swift lately. Here’s how I’d do 
this:

// Only needed if the property will be accessed by Objective-C code, since 
Swift code won’t see the swizzled accessors anyway for a non-dynamic property.
// @objc annotation is needed on every method we write here, since otherwise 
it’ll quit working when @objc inference is removed in Swift 4 (SE-0160)
@objc private static let automaticallyNotifiesObserversOfVersion: Bool = false

// Our actual version property. If you want, you can create a private property 
named “mVersion” and it will function like an instance variable.
// But I’d probably just use willSet and didSet.
// Note that this doesn’t need to be dynamic, since we are not relying on 
Cocoa’s built-in automatic swizzling,
// which is only needed if we are not calling willChangeValue(forKey:) and 
didChangeValue(forKey:) ourselves.
@objc var version: String {
willSet {
// Send the willChange notification, if the value is different from its 
old value.
if newValue != self.version {
self.willChangeValue(forKey: #keyPath(version))
}
}
didSet {
// Send the didChange notification, if the value is different from its 
old value.
if oldValue != self.version {
self.didChangeValue(forKey: #keyPath(version))
}
}
}

Charles

___

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: Translating KVO-ed property to Swift

2017-04-17 Thread Jean-Daniel

> Le 17 avr. 2017 à 10:52, Quincey Morris  
> a écrit :
> 
> On Apr 17, 2017, at 01:43 , Jean-Daniel  > wrote:
>> 
>> var version: String? {
> 
> A slight correction: this declaration actually must be:
> 
>> dynamic var version: String? {
> 
> 
> otherwise KVO isn’t guaranteed to work in Swift.

This is a good practice, but I don’t think this is required for computed 
property, especially if you take care of willChange/didChange manually, as the 
OP does.


___

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: Translating KVO-ed property to Swift

2017-04-17 Thread Quincey Morris
On Apr 17, 2017, at 01:43 , Jean-Daniel  wrote:
> 
> var version: String? {

A slight correction: this declaration actually must be:

> dynamic var version: String? {


otherwise KVO isn’t guaranteed to work in Swift.

___

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: Translating KVO-ed property to Swift

2017-04-17 Thread Quincey Morris
On Apr 17, 2017, at 01:24 , Rick Mann  wrote:
> 
> I have a number of properties in Objective-C written like this, 
> short-circuiting notifications when the value doesn't change:

Not in this code you don’t, unless you have a 
“automaticallyNotifiesObserversOfVersion” method returning false elsewhere in 
the class. The notification doesn’t happen in the synthesized implementation of 
the setter, but via a swizzled replacement setter that is normally installed 
only when something starts observing the property. Anyway …

> Now I want to translate this method into Swift. Thing is, AFAIK you can't 
> name the ivar created for a property. Is there a way to translate this to 
> swift?

You do it in the “obvious” way — you declare a second, private property without 
a custom getter or setter, and you use this private property where you would 
have used the instance variable in Obj-C. The effect is the same, because the 
private property is optimized into just an instance variable, and the public 
property has no instance storage of its own (but you will have to provide a 
custom getter, too).

___

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: Translating KVO-ed property to Swift

2017-04-17 Thread Jean-Daniel
One way to solve that is to declare an explicit private stored property for the 
ivar, and a public computed property for the logic.

private var _version: String? = nil

var version: String? {
get { return _version }
set { your set version code }
}


> Le 17 avr. 2017 à 10:24, Rick Mann  a écrit :
> 
> I have a number of properties in Objective-C written like this, 
> short-circuiting notifications when the value doesn't change:
> 
> -
> @synthesize version = mVersion
> 
> - (void)
> setVersion: (NSString *) inVersion
> {
>if (inVersion == nil && mVersion == nil)
>{
>return;
>}
>if ([inVersion isEqualToString: mVersion])
>{
>return;
>}
> 
>[self willChangeValueForKey: @"version"];
>mVersion = inVersion;
>[self didChangeValueForKey: @"version"];
> }
> -
> 
> Now I want to translate this method into Swift. Thing is, AFAIK you can't 
> name the ivar created for a property. Is there a way to translate this to 
> swift?
> 
> TIA,
> 
> -- 
> Rick Mann
> rm...@latencyzero.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/mailing%40xenonium.com
> 
> This email sent to mail...@xenonium.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

Translating KVO-ed property to Swift

2017-04-17 Thread Rick Mann
I have a number of properties in Objective-C written like this, 
short-circuiting notifications when the value doesn't change:

-
@synthesize version = mVersion

- (void)
setVersion: (NSString *) inVersion
{
if (inVersion == nil && mVersion == nil)
{
return;
}
if ([inVersion isEqualToString: mVersion])
{
return;
}

[self willChangeValueForKey: @"version"];
mVersion = inVersion;
[self didChangeValueForKey: @"version"];
}
-

Now I want to translate this method into Swift. Thing is, AFAIK you can't name 
the ivar created for a property. Is there a way to translate this to swift?

TIA,

-- 
Rick Mann
rm...@latencyzero.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