On Apr 19, 2017, at 15:49 , Charles Srstka <cocoa...@charlessoft.com> 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: 0x000000010000190b 
TestKVO`ViewController.version.willset(newValue="1", self=0x0000618000100900) 
at ViewController.swift:16
    frame #1: 0x0000000100001877 
TestKVO`ViewController.version.setter(newValue="1", self=0x0000618000100900) at 
ViewController.swift:0
    frame #2: 0x00000001000017d8 TestKVO`@objc ViewController.version.setter at 
ViewController.swift:0
    frame #3: 0x00007fff91d6c897 
Foundation`-[NSObject(NSKeyValueObservingPrivate) 
_changeValueForKeys:count:maybeOldValuesDict:usingBlock:] + 848
    frame #4: 0x00007fff91bf1c7d 
Foundation`-[NSObject(NSKeyValueObservingPrivate) 
_changeValueForKey:key:key:usingBlock:] + 60
    frame #5: 0x00007fff91c5a55b Foundation`_NSSetObjectValueAndNotify + 261
    frame #6: 0x000000010000310f 
TestKVO`ViewController.buttonClicked(sender=some, self=0x0000618000100900) -> 
() at ViewController.swift:57
    frame #7: 0x0000000100003200 TestKVO`@objc 
ViewController.buttonClicked(Any?) -> () at ViewController.swift:0
    frame #8: 0x00007fffa5b903a7 
libsystem_trace.dylib`_os_activity_initiate_impl + 53
    frame #9: 0x00007fff8e475791 AppKit`-[NSApplication(NSResponder) 
sendAction:to:from:] + 456

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

    0x1000030f2 <+434>: movq   0x3ebf(%rip), %rsi        ; "setVersion:"
    0x1000030f9 <+441>: movq   %rax, %rcx
    0x1000030fc <+444>: movq   -0x20(%rbp), %rdx
    0x100003100 <+448>: movq   %rdx, %rdi
    0x100003103 <+451>: movq   %rcx, %rdx
    0x100003106 <+454>: movq   %rax, -0x80(%rbp)
    0x10000310a <+458>: callq  0x1000047d2               ; 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 to arch...@mail-archive.com

Reply via email to