Re: KVO - deallocation with observers attached
> On 1 Jun 2017, at 00:51, Ken Thomases <k...@codeweavers.com> wrote: > > On May 31, 2017, at 5:02 PM, Jonathan Mitchell <li...@mugginsoft.com> wrote: >> >> It is common for deallocating objects to abort if they have observers still >> registered. >> >> The Data_Test object is deallocated with non nil -observationInfo and yet it >> does not abort. >> Why does this occur? > > It's not clear to me that the KVO machinery is obligated to set > observationInfo to nil when an object is no longer being observed. Note that > observationInfo is *not* an object pointer. It's a pointer to void. Among > other things, that means that there's no memory management involved in the > setter. That is, it's not a strong reference or even a weak one. So, for > example, it's not necessary for KVO to nil it out to free memory. Thanks for the input. I wasn’t able to get to the bottom of this despite poking around with Hopper through the foundation framework. There is an NSKVODeallocate foundation function that can get called when an observed object gets deallocated. It raises the familiar KVO exception if -observationInfo is not nil. - observationInfo does return a void* but it dereferences to an NSKeyValueObservationInfo : NSObject instance. Its obviously private API though. I was able to track the comings and goings of NSKeyValueObservationInfo using the memory graph debugger and malloc stack logging but enlightenment did not strike. I was able to make my test project behave as I anticipated but my real world app doesn’t seem so compliant. I am just trying to eradicate the possibility of crashes that occur when the observing object deallocs and the observed object keeps pumping notifications to the old observers address. Thanks J ___ 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: KVO - deallocation with observers attached
On May 31, 2017, at 5:02 PM, Jonathan Mitchell <li...@mugginsoft.com> wrote: > > It is common for deallocating objects to abort if they have observers still > registered. > > However in some cases it seems that an object can get deallocated with > observers attached and not abort. > > I have instrumented my test case thoroughly and overridden > -setObservationInfo: to log the observation changes as below. > > The Data_Test object is deallocated with non nil -observationInfo and yet it > does not abort. > Why does this occur? It's not clear to me that the KVO machinery is obligated to set observationInfo to nil when an object is no longer being observed. Note that observationInfo is *not* an object pointer. It's a pointer to void. Among other things, that means that there's no memory management involved in the setter. That is, it's not a strong reference or even a weak one. So, for example, it's not necessary for KVO to nil it out to free memory. That also means that you should not be logging the observationInfo as though it were an object (using the "%@" format specifier or otherwise sending the -description message to it). As mentioned in the observationInfo docs, "Overrides of this property must not attempt to send messages to the stored data." By the way, does your override just log and call through to super? Or did you actually implement storage in an instance variable? If you did the latter, it's conceivable that you changed whether or not crashes are likely to follow deallocation with observers. That's because the observationInfo would not be stored in a global look-aside table such that it could get accidentally attached to an unrelated object that happened to be allocated at the same address. > I am sorting through some observer related crash reports just trying to > figure out possible causes. I would think you'd have better luck logging the addition and removal of observers looking for an imbalance. Regards, Ken ___ 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
KVO - deallocation with observers attached
It is common for deallocating objects to abort if they have observers still registered. However in some cases it seems that an object can get deallocated with observers attached and not abort. I have instrumented my test case thoroughly and overridden -setObservationInfo: to log the observation changes as below. The Data_Test object is deallocated with non nil -observationInfo and yet it does not abort. Why does this occur? I am sorting through some observer related crash reports just trying to figure out possible causes. The Data_Test object is heavily observed throughout its lifetime both by bindings and explicit observations. macOS 10.12 2017-05-31 22:49:01.616632+0100 MyApp Data_Test (0x11336d100) SetObservationInfo 2017-05-31 22:49:01.616656+0100 MyApp oldObservationInfo : ( Context: 0x10075a4b8, Property: 0x6144abc0> Context: 0x0, Property: 0x608000a51280> ) 2017-05-31 22:49:01.616692+0100 MyApp newObservationInfo : ( Context: 0x10075a4b8, Property: 0x6144abc0> ) 2017-05-31 22:49:04.188226+0100 MyApp Data_Test (0x11336d100) dealloc Thanks Jonathan ___ 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
> On Apr 24, 2017, at 1:17 PM, Quincey Morris > <quinceymor...@rivergatesoftware.com> wrote: > > On Apr 24, 2017, at 10:11 , Charles Srstka <cocoa...@charlessoft.com > <mailto:cocoa...@charlessoft.com>> 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
On Apr 24, 2017, at 10:11 , Charles Srstka <cocoa...@charlessoft.com> 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
> On Apr 24, 2017, at 10:07 AM, Richard Charles <rcharles...@gmail.com> wrote: > >> >> On Apr 23, 2017, at 11:27 AM, Charles Srstka <cocoa...@charlessoft.com >> <mailto:cocoa...@charlessoft.com>> wrote: >> >>> On Apr 20, 2017, at 3:06 PM, Quincey Morris >>> <quinceymor...@rivergatesoftware.com >>> <mailto:quinceymor...@rivergatesoftware.com>> 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
> On Apr 23, 2017, at 11:27 AM, Charles Srstka <cocoa...@charlessoft.com> wrote: > >> On Apr 20, 2017, at 3:06 PM, Quincey Morris >> <quinceymor...@rivergatesoftware.com> 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
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 > <quinceymor...@rivergatesoftware.com> wrote: > > On Apr 20, 2017, at 10:24 , Charles Srstka <cocoa...@charlessoft.com > <mailto:cocoa...@charlessoft.com>> 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
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 <quinceymor...@rivergatesoftware.com> > a écrit : > > On Apr 20, 2017, at 10:24 , Charles Srstka <cocoa...@charlessoft.com> 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
On Apr 20, 2017, at 10:24 , Charles Srstka <cocoa...@charlessoft.com> 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
> On Apr 19, 2017, at 9:12 PM, Quincey Morris > <quinceymor...@rivergatesoftware.com> wrote: > > 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. 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
Re: Translating KVO-ed property to Swift
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: 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 Subsc
Re: Translating KVO-ed property to Swift
> On Apr 19, 2017, at 4:50 PM, Quincey Morris > <quinceymor...@rivergatesoftware.com> 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
> On Apr 19, 2017, at 4:50 PM, Quincey Morris > <quinceymor...@rivergatesoftware.com> wrote: > > On Apr 19, 2017, at 10:56 , Charles Srstka <cocoa...@charlessoft.com> 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
On Apr 19, 2017, at 10:56 , Charles Srstka <cocoa...@charlessoft.com> 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 <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
> On Apr 17, 2017, at 7:40 AM, Jean-Daniel <mail...@xenonium.com> wrote: > >> Le 17 avr. 2017 à 10:52, Quincey Morris <quinceymor...@rivergatesoftware.com >> <mailto:quinceymor...@rivergatesoftware.com>> a écrit : >> >> On Apr 17, 2017, at 01:43 , Jean-Daniel <mail...@xenonium.com >> <mailto:mail...@xenonium.com> <mailto:mail...@xenonium.com >> <mailto:mail...@xenonium.com>>> 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
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 <cocoa...@charlessoft.com> wrote: > >> On Apr 17, 2017, at 3:24 AM, Rick Mann <rm...@latencyzero.com> 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
On Apr 17, 2017, at 12:03 , Charles Srstkawrote: > > 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
> On Apr 17, 2017, at 1:09 PM, Quincey Morris > <quinceymor...@rivergatesoftware.com> wrote: > > On Apr 17, 2017, at 05:40 , Jean-Daniel <mail...@xenonium.com> 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 <cocoa...@charlessoft.com> 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 des
Re: Translating KVO-ed property to Swift
On Apr 17, 2017, at 05:40 , Jean-Daniel <mail...@xenonium.com> 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 <cocoa...@charlessoft.com> 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 <https://github.com/apple/swift-evolution/blob/master/proposals/0160
Re: Translating KVO-ed property to Swift
> On Apr 17, 2017, at 3:24 AM, Rick Mann <rm...@latencyzero.com> 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
> Le 17 avr. 2017 à 10:52, Quincey Morris <quinceymor...@rivergatesoftware.com> > a écrit : > > On Apr 17, 2017, at 01:43 , Jean-Daniel <mail...@xenonium.com > <mailto:mail...@xenonium.com>> 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
On Apr 17, 2017, at 01:43 , Jean-Daniel <mail...@xenonium.com> 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
On Apr 17, 2017, at 01:24 , Rick Mannwrote: > > 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
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 Manna é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
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
Re: Can't access by data via KVC during KVO
On Mar 27, 2017, at 14:48 , Daryle Walkerwrote: > > The message observation points to the object controller’s “selection”, then a > specific property of my model (of type “String?”). >> Could not cast value of type '_NSStateMarker' (0x7fffa3003cf8) to 'NSString' >> (0x7fffa397df38). >> 2017-03-27 16:36:33.978709 XNW[39160:4830169] Could not cast value of type >> '_NSStateMarker' (0x7fffa3003cf8) to 'NSString' (0x7fffa397df38). > > What is this “NSStateMarker” class? And why does it prevent me from accessing > the data? In short, you shouldn’t be using the “selection” property as if it means something for an object controller. Yes, you *can* select an object in the object controller’s content as *the* selection, but it doesn’t help you with anything — it doesn’t represent anything in the UI.** By definition, the “selection” is a proxy for an object (NSObjectController) or an array of objects (NSArrayController, which is a *subclass* of NSObjectController), but it can also represent a marker value, indicating no selection or multiple selection or (IIRC) some other possibilities. I assume your crash occurred because at the time you referenced “selection” it was set to one of these markers, and hence not castable to a String. Programming (in the sense of writing actual code) against NS…Controller objects is a horrible and dangerous experience, because they’re black boxes and you’ll never know what they’re really doing internally. I strongly, strongly recommend that you program against the data model directly. There’s no value (that I know of) in referencing a NSObjectController as you have. NSArrayController is a bit less clear, because if you’re using it to fetch, sort and filter Core Data records, then you sort of think you need to use its arrangedObjects property. Still, you don’t have to go through a NSArrayController — there’s nothing wrong with fetching, sorting and filtering Core Data records yourself. ** I’ve never really understood for sure, but I think the point of having a selection is that (by default in IB) NSObjectController models a NSMutableDictionary, and it can distinguish between multiple keys “within” the “dictionary” that are in most cases just different properties of the content object. By binding to “selection” and switching the selection, you can switch which key supplies a value to a single UI field (like a primitive master-detail arrangement). In fact, what normally happens is that the keys just represent independent objects accessible via the content object, and each of them is bound directly to its own UI element. In this case, the selection basically has no meaning. ___ 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
Can't access by data via KVC during KVO
This is from my window controller class, which has a (optional) reference to my document subclass’s model data. Through Interface Builder, that data is connected to a NSObjectController, and a property of that data is connected to a NSArrayController. The window controller has outlets to both data controllers. The model data is Core Data-based, BTW. I have to watch the data as part of my scheme to create a character map to use for NSTextFinder. Instead of KVO-ing the model data, I do the two data controllers instead since those are the “truth” I need to track (in case they cache any editing changes). > headerController.addObserver(self, forKeyPath: > MessageWindowController.headerKeyPath, options: .initial, context: > ) > messageController.addObserver(self, forKeyPath: > MessageWindowController.bodyKeyPath, options: .initial, context: > ) The header observation points to the array controller’s “arrangedObjects”. The message observation points to the object controller’s “selection”, then a specific property of my model (of type “String?”). I try to test an incomplete version of the KVO function: > override func observeValue(forKeyPath keyPath: String?, of object: Any?, > change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) { > guard let keyPath2 = keyPath, let object2 = object, let change2 = > change, let context2 = context else { > return super.observeValue(forKeyPath: keyPath, of: object, > change: change, context: context) > } > > let changeKind = NSKeyValueChange(rawValue: change2[.kindKey] as! > UInt)! > switch context2 { > case : > precondition(keyPath2 == MessageWindowController.headerKeyPath) > precondition(object2 as AnyObject === headerController) > break > case : > precondition(keyPath2 == MessageWindowController.bodyKeyPath) > precondition(object2 as AnyObject === messageController) > assert(changeKind == .setting) > > let newString = (messageController.selection as! > NSObject).value(forKey: #keyPath(RawMessage.body)) as! String? > //messageController.value(forKeyPath: keyPath2) as! String? > let bodyTextRangeIndex = textRanges.index(before: > textRanges.endIndex) > let oldBodyTextRange = textRanges[bodyTextRangeIndex] > let newLength = (newString as NSString?)?.length ?? 0 > if oldBodyTextRange.length != newLength { > textRanges[bodyTextRangeIndex] = > NSMakeRange(oldBodyTextRange.location, newLength) > } > break > default: > super.observeValue(forKeyPath: keyPath2, of: object2, change: > change2, context: context2) > } > } And there’s a crash at the “newString” definition. (The current and commented-out versions get the same error. The current version was copied from my menu-item validation function, where it actually works.): > Could not cast value of type '_NSStateMarker' (0x7fffa3003cf8) to 'NSString' > (0x7fffa397df38). > 2017-03-27 16:36:33.978709 XNW[39160:4830169] Could not cast value of type > '_NSStateMarker' (0x7fffa3003cf8) to 'NSString' (0x7fffa397df38). What is this “NSStateMarker” class? And why does it prevent me from accessing the data? Do NSObjectController and/or NSArrayController do any caching of its editing data? If not, and we can’t directly solve this problem, I could read the data directly from the document’s model objects. Pre-Send Update: I took out the “.initial” from the observing setup call, and it works! Why is that? Now I have to hope that my concept of the initial text-range array is accurate, since I can’t confirm it with an initial pass (for now). Note that when the window controller goes through “windowDidLoad”, the reference to the model data is NIL. (The object and array controllers are still bound to it by then, though.) It doesn’t get set to an actual data tree until the document’s “makeWindowControllers” call. Pre-Send Update 2: I completed a first try for the other property: > let changeKind = NSKeyValueChange(rawValue: change2[.kindKey] as! > UInt)! > let bodyTextRangeIndex = textRanges.index(before: textRanges.endIndex) > switch context2 { > case : > precondition(keyPath2 == MessageWindowController.headerKeyPath) > precondition(object2 as AnyObject === headerController) > > let newArray = headerController.mutableArrayValue(forKeyPath: > keyPath2) as NSArray > switch changeKind { > case .insertion, .removal, .replacement: > fallthrough > case .setting: > var newFieldRanges = R
Re: MLMediaLibrary sometimes does not call my KVO
___ 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: MLMediaLibrary sometimes does not call my KVO
> It’s very hard for a sandboxed app to get access to the internals of Photos > without using MLMediaLibrary, though not too difficult for non-sandboxed. > MLMediaLibrary was added because of this need. I was wondering whether this API (Photos Framework aka PhotoKit) would be better suited : https://developer.apple.com/reference/photos?language=objc According to the doc, it should be available on macOS 10.11+ Best regards, Gabriel. ___ 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: MLMediaLibrary sometimes does not call my KVO
> On 22 Sep 2016, at 10:45 PM, Gabriel Zachmann <z...@tu-clausthal.de> wrote: > >> I’ve run into some unreliability in MLMediaLibrary. It appears to be a bug >> because it sometimes can be seen in places that use MLMediaLibrary within >> general standard components, such as NSOpenPanel (this adds a media browsing >> section if it is set up to allow image types, for example). > > Thanks a lot for your insights. > > I am wondering: how does Microsoft Word , for instance, do it? > I've never seen that application behave funny when it shows the image browser > (it faithfully shows all 10,000 images from my Photos library). > > Does it use a different API? It’s very hard for a sandboxed app to get access to the internals of Photos without using MLMediaLibrary, though not too difficult for non-sandboxed. MLMediaLibrary was added because of this need. There is a standard component - NSMediaLibraryBrowserController (https://developer.apple.com/reference/appkit/nsmedialibrarybrowsercontroller?language=objc) that gives you a standardised panel for browsing. Unfortunately it’s a standalone panel rather than a view that you can embed within a larger UI, but it’s sufficient for many needs, and is easy to use. You could look at that and see if its behaviour is more reliable than your own code. I have tried it and it isn’t for me - I get the same problems with it that I see in NSOpenPanel, or when using KVO on MLMediaLibrary elements, which is why the problem seems to be in the lower-level layers of MLMediaLibrary. —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: MLMediaLibrary sometimes does not call my KVO
> I’ve run into some unreliability in MLMediaLibrary. It appears to be a bug > because it sometimes can be seen in places that use MLMediaLibrary within > general standard components, such as NSOpenPanel (this adds a media browsing > section if it is set up to allow image types, for example). Thanks a lot for your insights. I am wondering: how does Microsoft Word , for instance, do it? I've never seen that application behave funny when it shows the image browser (it faithfully shows all 10,000 images from my Photos library). Does it use a different API? Best regards, Gabriel. ___ 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: MLMediaLibrary sometimes does not call my KVO
> On 22 Sep 2016, at 8:59 AM, Gabriel Zachmann <z...@tu-clausthal.de> wrote: > > I am a bit at a loss about the MLMediaLibrary API. > Maybe, I haven't quite understood it yet, maybe something else is wrong. > > I am writing a screen saver that accesses Photos' albums and the images > referenced by them. > (Code excerpts follow at the end of this email.) > > I create an array of the top level albums at startup time of the screensaver > , using the KVO. > At runtime, I occasionally extract the images referenced by one of those > albums. > Most of the time it works fine, except sometimes, my KVO never gets invoked, > at which point my screensaver hangs, > because I had to stop the animation during that phase. > > I have not found a pattern as to when this happens. > (it is not a deterministic album, nor a deterministic n-th time.) > > Any suggestions, hints, insights, and pointers will be highly appreciated. I’ve run into some unreliability in MLMediaLibrary. It appears to be a bug because it sometimes can be seen in places that use MLMediaLibrary within general standard components, such as NSOpenPanel (this adds a media browsing section if it is set up to allow image types, for example). Sometimes it only shows the top level of the library, and all of the subgroups are simply missing, and never show up no matter how long you wait. Opening the panel a second time will finally deliver the subgroups. My guess is that as it’s an asynchronous API, on the first pass the system has to build a lot of internal cached state, and it may fail for any reason. On the second pass, it has already primed much of that cache and the failure doesn’t occur. While this happens quite often, it’s not every time, so I haven’t spotted an absolute pattern. But I think your code needs to be designed in such a way that if the KVO it is expecting (for the contents of a given group, say) is never delivered, it doesn’t fail. I’m not sure that is really possible for a photos screensaver (in that case you have no photos to display), but there’s no reason it needs to hang. Hopefully 10.12 will fix the issue, but I haven’t had a chance to look into that yet. —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
MLMediaLibrary sometimes does not call my KVO
I am a bit at a loss about the MLMediaLibrary API. Maybe, I haven't quite understood it yet, maybe something else is wrong. I am writing a screen saver that accesses Photos' albums and the images referenced by them. (Code excerpts follow at the end of this email.) I create an array of the top level albums at startup time of the screensaver , using the KVO. At runtime, I occasionally extract the images referenced by one of those albums. Most of the time it works fine, except sometimes, my KVO never gets invoked, at which point my screensaver hangs, because I had to stop the animation during that phase. I have not found a pattern as to when this happens. (it is not a deterministic album, nor a deterministic n-th time.) Any suggestions, hints, insights, and pointers will be highly appreciated. Best regards, Gabriel. The code snippets. (variables ending with underscore are instance variables.) This is what I do at startup time (in -initwithFrame:isPreview:) albums_ = [[NSMutableArray alloc] init]; NSDictionary *options = @{ MLMediaLoadSourceTypesKey: @(MLMediaSourceTypeImage), MLMediaLoadIncludeSourcesKey: @[MLMediaSourcePhotosIdentifier] }; mediaLibrary_ = [[MLMediaLibrary alloc] initWithOptions: options]; [mediaLibrary_ addObserver: self forKeyPath: @"mediaSources" options: 0 context: (__bridge void *) @"mediaLibraryLoaded"]; [mediaLibrary_.mediaSources objectForKey: MLMediaSourcePhotosIdentifier ]; // starts asynchronous loading During runtime, this gets executed occasionally: album_ = albums_[album_id]; [album_ addObserver: self forKeyPath: @"mediaObjects" options: 0 context: @"mediaObjects"]; [album_ mediaObjects]; I have checked using log message that addObserver: does actually get executed. And this is my key value observer: - (void) observeValueForKeyPath: (NSString *) keyPath ofObject: (id) object change: (NSDictionary *) change context: (void *) context { MLMediaSource * mediaSource = [mediaLibrary_.mediaSources objectForKey: MLMediaSourcePhotosIdentifier]; if ( context == (__bridge void *) @"mediaLibraryLoaded" ) { [mediaSource addObserver: self forKeyPath: @"rootMediaGroup" options: 0 context: (__bridge void *) @"rootMediaGroupLoaded"]; [mediaSource rootMediaGroup]; // start next phase: load groups } else if ( context == (__bridge void *) @"rootMediaGroupLoaded" ) { MLMediaGroup *albums = [mediaSource mediaGroupForIdentifier: @"TopLevelAlbums"]; for ( MLMediaGroup * album in albums.childGroups ) { NSString * albumName = [album.attributes objectForKey: @"name"]; [self logMessage: [NSString stringWithFormat: @"album name = %@", albumName] asError: NO]; if ( albumName ) [albums_ addObject: album ]; } } else if ( context == (__bridge void *) @"mediaObjects" ) { NSArray * mediaObjects = album_.mediaObjects; for ( MLMediaObject * mediaObject in mediaObjects ) { if ( mediaObject.mediaType != MLMediaTypeImage ) // we still get movies as mediaObjects, which might be contained in a Photos album continue; NSURL * url = mediaObject.URL; [photoPaths_ addObject: url.path]; } } } Again, I checked with a log message that the KVO never gets invoked in the case when the screen saver hangs (i.e., I am positive the hanging is not caused by an infinite loop or similar in the KVO.) ___ 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: iOS - the joy of observers and NSInternalInconsistancyException for KVO
> On 20 May 2016, at 07:04, Roland Kingwrote: > > > Reading the original post he already has the warning about an object being > deallocated whilst still having observers attached to it. > > This is simply a case of putting a breakpoint on dealloc and working out why > the object is being deallocated before you’ve gone through the observation > removal code you have. .. and if you want a condition you can put on a conditional breakpoint inside dealloc (or swift equivalent), checking self.observationInfo != nil may help to get the right dealloc. And that object, even though it’s actually opaque and internal and not-to-be-used, when printed will reveal some hints about who is still observing you .. at least in objC, I’ve never got the right commands to make LLDB use the objC print to show it. Just for clarity - I’m not suggesting using observationInfo to ‘prevent dealloc’, which you can’t do anyway and even if you could would be somewhere just the other side of insane, just to help filter out during debugging which dealloc to break on. ___ 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: iOS - the joy of observers and NSInternalInconsistancyException for KVO
> On 20 May 2016, at 04:36, Jens Alfke <j...@mooseyard.com> wrote: > > >> On May 19, 2016, at 1:24 PM, Alex Zavatone <z...@mac.com> wrote: >> >> In this case, I'm trying to see what is causing this deallocation. In my >> code, I explicitly remove the observer before I nil the object, so I don't >> know where this is happening. > > If you’re observing an object, you should probably establish a strong > reference to it, like by assigning it to an ivar or adding it to an array or > something. Otherwise you can’t guarantee that it will stay alive. But since > say “nil the object”, which I guess means “nil a variable pointing to the > object”, then you should already have a strong reference, so the object > shouldn’t get dealloced unless you’ve got a ref-counting error somewhere. (Do > you use ARC?) > > There is a user default NSBindingDebugLogLevel on Mac OS that you can set to > 1, which will generate extra warnings about KVO and bindings. It might do > something useful in your case; I can’t remember exactly what it does, but it > may produce a warning when an object with observers gets dealloced. > > —Jens Reading the original post he already has the warning about an object being deallocated whilst still having observers attached to it. This is simply a case of putting a breakpoint on dealloc and working out why the object is being deallocated before you’ve gone through the observation removal code you have. ___ 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: iOS - the joy of observers and NSInternalInconsistancyException for KVO
> On May 19, 2016, at 1:24 PM, Alex Zavatone <z...@mac.com> wrote: > > In this case, I'm trying to see what is causing this deallocation. In my > code, I explicitly remove the observer before I nil the object, so I don't > know where this is happening. If you’re observing an object, you should probably establish a strong reference to it, like by assigning it to an ivar or adding it to an array or something. Otherwise you can’t guarantee that it will stay alive. But since say “nil the object”, which I guess means “nil a variable pointing to the object”, then you should already have a strong reference, so the object shouldn’t get dealloced unless you’ve got a ref-counting error somewhere. (Do you use ARC?) There is a user default NSBindingDebugLogLevel on Mac OS that you can set to 1, which will generate extra warnings about KVO and bindings. It might do something useful in your case; I can’t remember exactly what it does, but it may produce a warning when an object with observers gets dealloced. —Jens ___ 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: iOS - the joy of observers and NSInternalInconsistancyException for KVO
On May 19, 2016, at 2:10 PM, Jens Alfke wrote: > >> On May 19, 2016, at 9:54 AM, Alex Zavatone <z...@mac.com> wrote: >> >> OK, fair enough. Looks like I'll have build a little weak referenced dealy >> that subclasses dealloc and stops if it detects any observers. > > Holy crap, don’t do that. First, you can’t stop a dealloc. Instead you’d have > to override retain and release, which is very tricky and will break ARC. > Second, needing to do this is a sure sign that You’re Doing It Wrong — it’s > like one of those images captioned FAIL where someone’s done some crime > against nature using duct tape. I have no means to see why this is happening at this point. If I have sinned against nature or if nature is sinning against me, I can't tell yet; duct tape be damned. > What is the problem exactly? Who is observing what? In this case, I'm trying to see what is causing this deallocation. In my code, I explicitly remove the observer before I nil the object, so I don't know where this is happening. On iOS, part of my app downloads files over https using NSURLSession. Not a problem. In a manager class, I perform this operation "get the list of files from our web end point and then download everything one file at a time asynchronously". I thought it would be fun to use KVO to observe when the downloaded file is saved into its final path and then iterate to the next item in the list. However, when I switch to one of our pre release web end points, we use self signed certs and I haven't had the time to implement the challenge/response code yet. This causes the NSURLSession to clear itself somehow. Now that a failure case has reared its ugly head, I'd like to know why the object is removing itself before I am removing the observer. I want to catch the point where dealloc is being called and the object is still being observed, so I can see why this is happening on this failure case. > —Jens ___ 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: iOS - the joy of observers and NSInternalInconsistancyException for KVO
Yeah, I have strong references too, but some part of my NSURLSession code ends up causing this error when we have a failure (SSL challenge) on a file download. I'll have to implement the methods to handle the download failure cases, which I am currently not doing. On May 19, 2016, at 12:57 PM, Jonathan Mitchell wrote: > >> On 19 May 2016, at 17:55, Jonathan Mitchellwrote: >> >> That way the observed object can get deallocated before the observer. > Should say > That way the observed object cannot get deallocated before the observer. > > J > > ___ > > 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
Re: iOS - the joy of observers and NSInternalInconsistancyException for KVO
> On May 19, 2016, at 9:54 AM, Alex Zavatonewrote: > > OK, fair enough. Looks like I'll have build a little weak referenced dealy > that subclasses dealloc and stops if it detects any observers. Holy crap, don’t do that. First, you can’t stop a dealloc. Instead you’d have to override retain and release, which is very tricky and will break ARC. Second, needing to do this is a sure sign that You’re Doing It Wrong — it’s like one of those images captioned FAIL where someone’s done some crime against nature using duct tape. What is the problem exactly? Who is observing what? —Jens ___ 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: iOS - the joy of observers and NSInternalInconsistancyException for KVO
> On 19 May 2016, at 17:55, Jonathan Mitchellwrote: > > That way the observed object can get deallocated before the observer. Should say That way the observed object cannot get deallocated before the observer. J ___ 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: iOS - the joy of observers and NSInternalInconsistancyException for KVO
> > Is there any safer KVO technique to prevent or detect the dreaded "An > instance of xx was deallocated while key value observers were still > registered with it"? > I have a ton of observers in NSViewController subclasses. Generally when I use an observer I make 100% sure I have a strong property reference (held by the NSViewController instance) to the observed object. That way I know that the observed object will live as long as the NSViewController. That way the observed object can get deallocated before the observer. I then always make sure to remove my observers in NSViewController -dealloc. If you want the observer to stop observing on command then use a delegate pattern or a notification to explicitly request that. It is a futile task IMHO to dig into the KVO machinery and try and second guess it. Jonathan ___ 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: iOS - the joy of observers and NSInternalInconsistancyException for KVO
On May 19, 2016, at 12:41 PM, Jens Alfke wrote: > >> On May 19, 2016, at 7:51 AM, Alex Zavatonewrote: >> >> Is there a means to have an object know when it's being observed so that it >> will refuse to nuke itself in this condition? > > Nope. Remember, objects don’t “nuke” themselves; they are dealloced when no > other objects have references to them. It’s the observer’s responsibility to > retain a reference to the target object (observee?) for as long as it’s > observing that object. Or at least to have some means of detecting that the > target object is going to go away, and removing itself as an observer then. > > —Jens OK, fair enough. Looks like I'll have build a little weak referenced dealy that subclasses dealloc and stops if it detects any observers. Then for any object that I plan on being KVOable, it will have to be be a subclass of NSObject+bubblewrappedKVO, if dealloc is called while observers are still on the object. Thank you, sir. Alex Zavatone ___ 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: iOS - the joy of observers and NSInternalInconsistancyException for KVO
> On May 19, 2016, at 7:51 AM, Alex Zavatonewrote: > > Is there a means to have an object know when it's being observed so that it > will refuse to nuke itself in this condition? Nope. Remember, objects don’t “nuke” themselves; they are dealloced when no other objects have references to them. It’s the observer’s responsibility to retain a reference to the target object (observee?) for as long as it’s observing that object. Or at least to have some means of detecting that the target object is going to go away, and removing itself as an observer then. —Jens ___ 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
iOS - the joy of observers and NSInternalInconsistancyException for KVO
I'm having fun with async NSURLSession downloads but running into objects deleting themselves in error cases while still being observed, resulting in the lovely NSInternalInconsistancyException. Is there a means to have an object know when it's being observed so that it will refuse to nuke itself in this condition? Sure, I can set a breakpoint on dealloc to see when this is happening, but I'm sure you lots of people have already run into this condition and have already figured out how to handle it. Is there any safer KVO technique to prevent or detect the dreaded "An instance of xx was deallocated while key value observers were still registered with it"? Thanks in advance, Alex Zavatone ___ 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: KVO question
One possible issues is that `self.thingy=x;` will trigger two change notifications for `thingy`: one for `self.dictionaryOfThings = temp;` (due to keyPathsForValuesAffectingThingy), and one when the setter exits. Depending one what your observer does this may have unforeseen side effects. A possible workaround would be to replace `self.dictionaryOfThings = temp;` with `_dictionaryOfThings = temp;`. Gerd > > On Nov 17, 2015, at 19:18, Graham Cox <graham@bigpond.com> wrote: > > I’m using KVO to observe a bunch of properties. > > Most of these properties are split out into simple things that set a single > value, but internal to my object, some end up setting a common dictionary of > attributes, which is also a property. > > I KVO observe both the simple properties and the common dictionary property. > Mostly this is working, but when code directly sets the dictionary property, > the other properties don’t trigger their observers, even though I’m > implementing the +keyPathsForValuesAffecting, which I believe > should cause the additional triggering. Have I understood that right? > > Here’s the kind of code I have: > > > @property (retain) id thingy; > @property (retain) NSDicitonary* dictionaryOfThings; > > @implementation > > - (void) setThingy:(is thing > { > NSMutableDictionary* temp = [self.dictionaryOfThings mutableCopy]; > [temp setObject:thing forKey:kThingKey]; > self.dictionaryOfThings = temp; > } > > - (id) thingy > { > return [self.dictionaryOfThings objectForKey:kThingKey]; > } > > > + (NSSet*) keyPathsForValuesAffectingThingy > { > return [NSSet setWithObject:@“dictionaryOfThings”]; > } > > > So what I want (expect?) is that is code sets -dictionaryOfThings directly, > an observer of ‘thingy’ will be triggered. Is that right? > > > —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/gerti-cocoadev%40bitart.com > > This email sent to gerti-cocoa...@bitart.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: KVO question
On Nov 17, 2015, at 7:18 PM, Graham Cox <graham@bigpond.com> wrote: > > I’m using KVO to observe a bunch of properties. > > Most of these properties are split out into simple things that set a single > value, but internal to my object, some end up setting a common dictionary of > attributes, which is also a property. > > I KVO observe both the simple properties and the common dictionary property. > Mostly this is working, but when code directly sets the dictionary property, > the other properties don’t trigger their observers, even though I’m > implementing the +keyPathsForValuesAffecting, which I believe > should cause the additional triggering. Have I understood that right? If by "code directly sets the dictionary property", you mean always in a KVO-compliant manner, then yes. > @property (retain) id thingy; > @property (retain) NSDicitonary* dictionaryOfThings; It's not clear if this is a public or private property. If it's public, and probably even if it's private, this should be a "copy" property, not just "retain". If it's just "retain", you're not protected against somebody setting it to a mutable dictionary and then subsequently mutating the dictionary, thereby effectively mutating your property in a non-KVO-compliant manner. All of that said, I agree with Quincey. You should just use either normal properties backed by (compiler-synthesized) instance variables, or you can use a secondary object with such properties. Using a dictionary may seem like a quick-and-dirty solution, but invites problems in the long run. Regards, Ken ___ 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: KVO question
Are you implying that one KVO is blocking the others? Sent from my iPhone > On Nov 17, 2015, at 8:18 PM, Graham Cox <graham@bigpond.com> wrote: > > I’m using KVO to observe a bunch of properties. > > Most of these properties are split out into simple things that set a single > value, but internal to my object, some end up setting a common dictionary of > attributes, which is also a property. > > I KVO observe both the simple properties and the common dictionary property. > Mostly this is working, but when code directly sets the dictionary property, > the other properties don’t trigger their observers, even though I’m > implementing the +keyPathsForValuesAffecting, which I believe > should cause the additional triggering. Have I understood that right? > > Here’s the kind of code I have: > > > @property (retain) id thingy; > @property (retain) NSDicitonary* dictionaryOfThings; > > @implementation > > - (void) setThingy:(is thing > { >NSMutableDictionary* temp = [self.dictionaryOfThings mutableCopy]; >[temp setObject:thing forKey:kThingKey]; >self.dictionaryOfThings = temp; > } > > - (id) thingy > { >return [self.dictionaryOfThings objectForKey:kThingKey]; > } > > > + (NSSet*) keyPathsForValuesAffectingThingy > { >return [NSSet setWithObject:@“dictionaryOfThings”]; > } > > > So what I want (expect?) is that is code sets -dictionaryOfThings directly, > an observer of ‘thingy’ will be triggered. Is that right? > > > —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/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
Re: KVO question
On Nov 18, 2015, at 16:29 , Roland King <r...@rols.org> wrote: > > I didn’t read his original question as saying that I could easily have got it wrong, but I believe what he was saying was that much of his system was working. The part that doesn’t work is when (e.g.) the Font Manager updates the dictionary directly, by which I mean it changes values in the dictionary, but does not replace the entire dictionary in the model object (it can’t do that, it doesn’t know where to find the model object, or what the property name of the dictionary in the model object is). In this kind of update, Graham is expecting a KVO notification “for the dictionary”, in order to trigger ___ 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: KVO question
> On 19 Nov 2015, at 08:38, Quincey Morris > <quinceymor...@rivergatesoftware.com> wrote: > > (sorry, posted the incomplete message by accident) > > On Nov 18, 2015, at 16:29 , Roland King <r...@rols.org > <mailto:r...@rols.org>> wrote: >> >> I didn’t read his original question as saying that > > I could easily have got it wrong, but I believe what he was saying was that > much of his system was working. The part that doesn’t work is when (e.g.) the > Font Manager updates the dictionary directly, by which I mean it changes > values in the dictionary, but does not replace the entire dictionary in the > model object (it can’t do that, it doesn’t know where to find the model > object, or what the property name of the dictionary in the model object is). > > In this kind of update, Graham is expecting a KVO notification “for the > dictionary”, in order to trigger keyPathsForValuesAffectingThingy. I’m saying > that can’t possibly happen. > > I agree that if what he’s doing is changing values in the dictionary then he’s not going to get a change notification for the dictionary. I just read his message again and I can’t read it as saying anything else than the entire dictionary is being replaced, perhaps it’s just how I read it. I think we need some clarification here about what’s really getting changed. ___ 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: KVO question
> On 19 Nov 2015, at 08:15, Quincey Morris > <quinceymor...@rivergatesoftware.com> wrote: > > On Nov 18, 2015, at 14:35 , Graham Cox <graham@bigpond.com> wrote: >> >> it’s just that if other code changes the attributes dictionary (such as the >> Font Manager) then I need these split out properties to trigger their >> notifications so that the UI shows the change > > I think I understand, finally. No, what you’re doing won’t work. > > The problem is that if (say) the Font Manager has a pointer to your > NSMutableDictionary object, and mutates it — sets a new value for a key — > there *will* be a KVO notification** — I believe we know that the standard > NSMutableDictionary class issues KVO notifications for value changes, though > I’m not sure whether it’s documented — but it won’t be a notification for the > dictionary***, it will be a notification for the individual key. > I didn’t read his original question as saying that however, that he was mutating an individual element of a mutable dictionary property. Grabbing what was written > So what I want (expect?) is that is code sets -dictionaryOfThings directly, > an observer of ‘thingy’ will be triggered. Is that right? which when you look at it doesn’t quite make sense, -dictionaryOfThings is a method so you can’t set it so I assumed it meant replacing the whole dictionary like so myObject.dictionaryOfThings = newDictionaryOfNewThings; or calling [ myObject setDictionaryOfThings:newDictionaryOfNewThings ]; then the original dependent KVO code as-written should fire, for every property which has dictionaryOfThings as a dependent key. A bit of clarification about what was meant by ‘code setting -dictionaryOfThings directly’ might help. ___ 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: KVO question
(sorry, posted the incomplete message by accident) On Nov 18, 2015, at 16:29 , Roland King <r...@rols.org <mailto:r...@rols.org>> wrote: > > I didn’t read his original question as saying that I could easily have got it wrong, but I believe what he was saying was that much of his system was working. The part that doesn’t work is when (e.g.) the Font Manager updates the dictionary directly, by which I mean it changes values in the dictionary, but does not replace the entire dictionary in the model object (it can’t do that, it doesn’t know where to find the model object, or what the property name of the dictionary in the model object is). In this kind of update, Graham is expecting a KVO notification “for the dictionary”, in order to trigger keyPathsForValuesAffectingThingy. I’m saying that can’t possibly happen. ___ 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: KVO question
Hi guys, thanks for your replies - sorry took a while to get back to this, was in a long meeting. Anyway, Quincey, I’m not trying to get notified for mutations to the dictionary. The dictionary is being replaced as a single entity wholesale. The way the font manager works is that for a given attribute change, it asks the first responder to send it the dictionary of attributes for the selected text. (-changeAttributes:) It then mutates a copy of that dictionary (-convertAttributes:) and returns the entire mutated copy. The text view then applies that as a single object to the selected text run. In my case I’ve actually wrapped the text (attributed string) in another object that splits out specific text-related properties separately, which makes it much easier to bind these properties to particular bits of UI, for example changing the Font. That all works - if I set my -font property, internally it changes the font attribute in the -textAttributes property, I get notifications on both -font and -textAttributes. If I change the text selection, the attributes applying to that run trigger notifications for the font property in my UI. If some other object (e.g. Font Manager) changes the font using its normal mechanism, which updates the -textAttributes property directly, I need notifications to be triggered for the -font property. In fact, they are, because I have +keyPathsForValuesAffectingFont returning textAttributes. However this was not working consistently for all properties. I was trying to boil it down to generalities hence my dictionaryOfThings and thingy terminology, just to clarify that my understanding of KVO was correct. Seems it was. So my problem must be something specific in my code because in fact this is working for nearly everything, just not all. So if my understanding of KVO is correct, I now know where to look for these few missing pieces. —Graham > On 19 Nov 2015, at 11:38 AM, Quincey Morris > <quinceymor...@rivergatesoftware.com> wrote: > > (sorry, posted the incomplete message by accident) > > On Nov 18, 2015, at 16:29 , Roland King <r...@rols.org> wrote: >> >> I didn’t read his original question as saying that > > I could easily have got it wrong, but I believe what he was saying was that > much of his system was working. The part that doesn’t work is when (e.g.) the > Font Manager updates the dictionary directly, by which I mean it changes > values in the dictionary, but does not replace the entire dictionary in the > model object (it can’t do that, it doesn’t know where to find the model > object, or what the property name of the dictionary in the model object is). > > In this kind of update, Graham is expecting a KVO notification “for the > dictionary”, in order to trigger keyPathsForValuesAffectingThingy. I’m saying > that can’t possibly happen. > > ___ 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: KVO question
On Nov 18, 2015, at 14:35 , Graham Cox <graham@bigpond.com> wrote: > > it’s just that if other code changes the attributes dictionary (such as the > Font Manager) then I need these split out properties to trigger their > notifications so that the UI shows the change I think I understand, finally. No, what you’re doing won’t work. The problem is that if (say) the Font Manager has a pointer to your NSMutableDictionary object, and mutates it — sets a new value for a key — there *will* be a KVO notification** — I believe we know that the standard NSMutableDictionary class issues KVO notifications for value changes, though I’m not sure whether it’s documented — but it won’t be a notification for the dictionary***, it will be a notification for the individual key. This will have no effect (assuming I’m still on track) because nothing is observing the key path that’s getting the notification. Your UI observers are watching yourModel.thingy instead, and your keyPathsForValuesAffectingThingy doesn’t fire for the reason given above. What will work (assuming I’m still on track) is to bind your UI elements to yourModel.dictionaryOfThings.thingy instead of yourModel.thingy. In that case, a Font Manager update to the dictionary will trigger an update that reaches the UI. The hard part comes if you something is observing the dictionary itself (for example, to tell the text system to update when the dictionary changes externally). A UI element update will trigger a KVC notification on path yourModel.dictionaryOfThings.thingy, but *not* on path yourModel.dictionaryOfThings, so the dictionary observer won’t fire. But there’s nothing in your existing sample code to suggest that anything is observing the dictionary like this, except to trigger the model updates on the duplicate properties, which aren’t needed in the scheme I’m suggesting. It’s a while since we’ve discussed KVO vs. NSMutableDictionary on this list, so I may be misremembering how this all works. (Ken can probably straighten that out.) Even if it doesn’t work this way, if you are in charge of creating the NSMutableDictionary initially, you could write a subclass and give it whatever KVO notification behavior you want. Otherwise, you might be able to achieve your goal by adding another set of observers to the dictionary keys themselves. ** Maybe that should be “would”, not “will”, since you have no observers of this. There are no notifications for regular properties unless something is observing them. I’m not sure whether NSMutableDictionary issues notifications unconditionally or knows what keys are being observed. ***There can’t be a notification for the dictionary itself, because the code that’s mutating it doesn’t know what key to use. ___ 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: KVO question
> On 18 Nov 2015, at 6:43 PM, Quincey Morris > <quinceymor...@rivergatesoftware.com> wrote: > > As a matter of principle, I always think using a dictionary as an API to > properties is a terrible idea. You’re much better off defining an object that > actually has the properties, even if there are a lot of them. That would > solve your difficulty here, since you wouldn’t need two ways of getting to > the properties. Also, you’d avoid the danger inherent in exposing your > mutable backing store (the NSMutableDictionary) to the outside world, always > a prescription for trouble. > I completely agree, but in this case the dictionary in question is the attributes of NSAttributedString (in a NSTextView), so I don’t have the choice. I have split out numerous individual properties from this so that they are easy to bind to specific UI, such as a menu for Font, a menu for font face, a text field for font size, etc, etc. But ultimately they have to change the attributes dictionary. That all works, it’s just that if other code changes the attributes dictionary (such as the Font Manager) then I need these split out properties to trigger their notifications so that the UI shows the change. The dictionary is being changed in a KVO compliant way, because the entire dictionary is updated and replaced as a whole - the settings within the dictionary are not mutated individually. —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: KVO question
It seems like it *should* work. Are you sure you don’t have a typo in your addObserver: method? Considering that you’re using the dictionary’s property setter, keyPathsForValuesAffecting shouldn’t even be necessary. When I apply KVO, I try to mitigate the potential unsafely of key paths strings by using NSStringFromSelector() whenever possible. [self.foo addObserver:self forKeyPath:NSStringFromSelector(@selector(bar)) options:NSKeyValueObservingOptionNew context:NULL]; Dan On Nov 17, 2015, at 5:18 PM, Graham Cox <graham@bigpond.com<mailto:graham@bigpond.com>> wrote: I’m using KVO to observe a bunch of properties. Most of these properties are split out into simple things that set a single value, but internal to my object, some end up setting a common dictionary of attributes, which is also a property. I KVO observe both the simple properties and the common dictionary property. Mostly this is working, but when code directly sets the dictionary property, the other properties don’t trigger their observers, even though I’m implementing the +keyPathsForValuesAffecting, which I believe should cause the additional triggering. Have I understood that right? Here’s the kind of code I have: @property (retain) id thingy; @property (retain) NSDicitonary* dictionaryOfThings; @implementation - (void) setThingy:(is thing { NSMutableDictionary* temp = [self.dictionaryOfThings mutableCopy]; [temp setObject:thing forKey:kThingKey]; self.dictionaryOfThings = temp; } - (id) thingy { return [self.dictionaryOfThings objectForKey:kThingKey]; } + (NSSet*) keyPathsForValuesAffectingThingy { return [NSSet setWithObject:@“dictionaryOfThings”]; } So what I want (expect?) is that is code sets -dictionaryOfThings directly, an observer of ‘thingy’ will be triggered. Is that right? —Graham ___ Cocoa-dev mailing list (Cocoa-dev@lists.apple.com<mailto: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<http://lists.apple.com> Help/Unsubscribe/Update your Subscription: https://lists.apple.com/mailman/options/cocoa-dev/dstenmark%40opentable.com This email sent to dstenm...@opentable.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
KVO question
I’m using KVO to observe a bunch of properties. Most of these properties are split out into simple things that set a single value, but internal to my object, some end up setting a common dictionary of attributes, which is also a property. I KVO observe both the simple properties and the common dictionary property. Mostly this is working, but when code directly sets the dictionary property, the other properties don’t trigger their observers, even though I’m implementing the +keyPathsForValuesAffecting, which I believe should cause the additional triggering. Have I understood that right? Here’s the kind of code I have: @property (retain) id thingy; @property (retain) NSDicitonary* dictionaryOfThings; @implementation - (void) setThingy:(is thing { NSMutableDictionary* temp = [self.dictionaryOfThings mutableCopy]; [temp setObject:thing forKey:kThingKey]; self.dictionaryOfThings = temp; } - (id) thingy { return [self.dictionaryOfThings objectForKey:kThingKey]; } + (NSSet*) keyPathsForValuesAffectingThingy { return [NSSet setWithObject:@“dictionaryOfThings”]; } So what I want (expect?) is that is code sets -dictionaryOfThings directly, an observer of ‘thingy’ will be triggered. Is that right? —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: KVO question
On Nov 17, 2015, at 17:18 , Graham Cox <graham@bigpond.com> wrote: > > Mostly this is working, but when code directly sets the dictionary property, > the other properties don’t trigger their observers, even though I’m > implementing the +keyPathsForValuesAffecting, which I believe > should cause the additional triggering. Have I understood that right? It’s not clear. I can’t think of a compelling reason why the other observers shouldn’t trigger, but you are doing something a bit weird. I wonder, also, if you’re always setting the ‘dictionaryOfThings’ property KVO-compliantly? In particular, is the instance variable perhaps changed initially from nil to an empty dictionary after there are already observers on the dictionary path? As a matter of principle, I always think using a dictionary as an API to properties is a terrible idea. You’re much better off defining an object that actually has the properties, even if there are a lot of them. That would solve your difficulty here, since you wouldn’t need two ways of getting to the properties. Also, you’d avoid the danger inherent in exposing your mutable backing store (the NSMutableDictionary) to the outside world, always a prescription for trouble. FWIW. ___ 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
KVO detection of changes to selection in NSOpenPanel
I’ve just noticed a glitch where my custom file preview box in an NSOpenPanel works fine on OS X 10.9.5 but does not get updated on 10.8.5. Specifically, I declare a dependency of my property on panel.filenames, panel.URL and panel.directoryURL (just to see if ANY of them fire), and none of them are getting prodded when the user changes the selected file/directory. Does anybody know if this is expected behaviour? I did notice somewhere buried in here: https://developer.apple.com/library/mac/releasenotes/AppKit/RN-AppKitOlderNotes/#X10_9Notes that it says (for OS X 10.9) Key Value Observation compliance was dramatically increased for public and some private properties of actual, non sandboxed NSOpen and Save panels, including keys affecting other values. For example, if the directory value changes on a save panel, this will cause a KVO notification to be emitted for the URL value as well as the directory value. Sandboxed NSOpen and Save Panels do not have the same level of KVO compliance. This does make me wonder if I should perhaps not be surprised that my use of keyPathsAffectingValueForKey is not going well, although nothing in that statement seems to specifically preclude what I am doing from working on 10.8. Does anyone know if there’s any hope of my KVO approach working? The alternative seems to be to implement a delegate method for panelSelectionDidChange. Would that be the sensible way to deal with this, or is there a third and better way I should be using? Cheers Jonny ___ 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: KVO detection of changes to selection in NSOpenPanel
On Mon, Jul 20, 2015, at 11:13 AM, Jonathan Taylor wrote: This does make me wonder if I should perhaps not be surprised that my use of keyPathsAffectingValueForKey is not going well, although nothing in that statement seems to specifically preclude what I am doing from working on 10.8. Does anyone know if there’s any hope of my KVO approach working? No. If a property is not explicitly documented to be KVO-compliant, you must assume that it isn't. The alternative seems to be to implement a delegate method for panelSelectionDidChange. Would that be the sensible way to deal with this, or is there a third and better way I should be using? It seems pretty straightforward to just implement the delegate method regardless of OS version. --Kyle Sluder ___ 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
Assuring KVO compliance.
I've read Apple's docs on assuring KVO/KVC compliance, but in this particular situation, I'd appreciate someone explaining what I'm not getting here if it's anything obvious. I think what I'm asking is how to convert code that has a state exposed as a (nonatomic, readwrite) property of a typedef-ed enum so that it can be observed by KVO. The code that I've inherited has an enum (not an NSEnum) that represents the app's connected state, 0, 1 or 2. This enum is then typedef-ed and then exposed as a property through @property (nonatomic, readwrite) This property is within the AppDelegate and is referred to and set throughout the app. enum APP_State { APP_State_Normal = 0, APP_State_Expired = 1, APP_State_Waiting = 2 }; typedef enum APP_State APP_State; @property (nonatomic, readwrite) APP_State app_idle_state; So, I want to set up an approach to monitor this state and set a readout graphic based upon the state's value. I had assumed that KVO would be the path of least overhead and allow a rather self contained little class to handle this without any nasty polling. Within a new class, I added an observer to the APP_State property on the appDelegate and this operates as expected, but adding the KVO will trigger an EXC_BAD_ACCESS when attempting to change the app_idle_state enum property within another class that accesses that property in the delegate. Specifically, this: delegate.app_idle_state = APP_State_Waiting; Results in this: Thread1: EXC_BAD_ACCESS (code=1,address = 0x003f8f3) First of all, I've never seen enum being attempted to be exposed like this (would making this an NS_ENUM help?). Also, I certainly was expecting *something* to go wrong here, but not causing bad access exceptions elsewhere when code in another class attempts to set the value of the property (since its property was set to readwrite). Changing the property declaration to atomic seems to be more correct in that we don't want any other operation to happen on it, but that doesn't doesn't affect whether or not an EXC_BAD_ACCESS. Or I could be walking down the wrong path entirely and should just poll for the value or have a notification of a state change be sent to the monitoring class. Thoughts? Thanks in advance, Alex Zavatone ___ 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: Assuring KVO compliance.
On Apr 7, 2015, at 09:05 , Alex Zavatone z...@mac.com wrote: Gremlins, I think. No, something, but not that. Enums are a C thing, not even Obj-C. They are, for all intents and purposes, an int of some size and signedness chosen by the compiler. So, the enum part of this is a red herring. The reason that changing the enum definition made a difference is, presumably, that it changed the way things were arranged in memory, and that by chance caused your actual problem to do something harmless instead of harmful. Your actual error was this: delegate.app_idle_state = APP_State_Waiting; Thread1: EXC_BAD_ACCESS (code=1,address = 0x003f8f3) and you were mislead by the word “access” to think this had something to do with accessing the property. Actually, EXC_BAD_ACCESS means an invalid pointer to memory. You can’t tell which pointer, exactly, without looking at the backtrace to see exactly where execution was at the time of the exception. If it’s in the line of code that assigns the app state, the exception probably means that ‘delegate’ is invalid, not the attempt to change the property. So, you need to try to make the EXC_BAD_ACCESS happen again, and take a harder look at what’s going on at that point, ideally using the debugger at a breakpoint on the exception. You may have a memory management error relating to the delegate object — delegate object references are often kept unretained, which is prone to errors — or a thread safety issue. ___ 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: Assuring KVO compliance.
On 7 Apr 2015, at 23:12, Alex Zavatone z...@mac.com wrote: To answer my own question, changing the enum to an NSInteger backed NS_Enum resulted in no more bad access exceptions from other chunks of code attempting to change the APP_State property. typedef NS_ENUM(NSInteger, APP_State) { APP_State_Normal = 0, APP_State_Expired = 1, APP_State_Waiting = 2 }; Changing the atomicity of the exposed property had no effect on whether the exception was issued or not. Hope this helps someone. Alex Zavatone I was just looking at some of my own code because I’m pretty sure I use enums all the time in properties which are KVO and observe them and update them, and I’ve never once had to mess around with NS_ENUM to make them work. And indeed I found 4 examples quite quickly, all of which look very much like your original code, a typedef’ed enum used as a property. So I really don’t know where your bad accesses were coming from. This was all ObjC right ? ___ 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: Assuring KVO compliance.
To answer my own question, changing the enum to an NSInteger backed NS_Enum resulted in no more bad access exceptions from other chunks of code attempting to change the APP_State property. typedef NS_ENUM(NSInteger, APP_State) { APP_State_Normal = 0, APP_State_Expired = 1, APP_State_Waiting = 2 }; Changing the atomicity of the exposed property had no effect on whether the exception was issued or not. Hope this helps someone. Alex Zavatone On Apr 7, 2015, at 10:04 AM, Alex Zavatone wrote: I've read Apple's docs on assuring KVO/KVC compliance, but in this particular situation, I'd appreciate someone explaining what I'm not getting here if it's anything obvious. I think what I'm asking is how to convert code that has a state exposed as a (nonatomic, readwrite) property of a typedef-ed enum so that it can be observed by KVO. The code that I've inherited has an enum (not an NSEnum) that represents the app's connected state, 0, 1 or 2. This enum is then typedef-ed and then exposed as a property through @property (nonatomic, readwrite) This property is within the AppDelegate and is referred to and set throughout the app. enum APP_State { APP_State_Normal = 0, APP_State_Expired = 1, APP_State_Waiting = 2 }; typedef enum APP_State APP_State; @property (nonatomic, readwrite) APP_State app_idle_state; So, I want to set up an approach to monitor this state and set a readout graphic based upon the state's value. I had assumed that KVO would be the path of least overhead and allow a rather self contained little class to handle this without any nasty polling. Within a new class, I added an observer to the APP_State property on the appDelegate and this operates as expected, but adding the KVO will trigger an EXC_BAD_ACCESS when attempting to change the app_idle_state enum property within another class that accesses that property in the delegate. Specifically, this: delegate.app_idle_state = APP_State_Waiting; Results in this: Thread1: EXC_BAD_ACCESS (code=1,address = 0x003f8f3) First of all, I've never seen enum being attempted to be exposed like this (would making this an NS_ENUM help?). Also, I certainly was expecting *something* to go wrong here, but not causing bad access exceptions elsewhere when code in another class attempts to set the value of the property (since its property was set to readwrite). Changing the property declaration to atomic seems to be more correct in that we don't want any other operation to happen on it, but that doesn't doesn't affect whether or not an EXC_BAD_ACCESS. Or I could be walking down the wrong path entirely and should just poll for the value or have a notification of a state change be sent to the monitoring class. Thoughts? Thanks in advance, Alex Zavatone ___ 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
Re: Assuring KVO compliance.
Thanks Roland. Yeah, me neither, but this is inherited code where the previous guys obviously come from a java background and have done things in a manner I'm not accustomed to. In this project, refactoring properties and methods in many classes actually causes Xcode to tell me I'd be better off handling it manually. Never seen that before. What doesn't sit right on this BAD_ACCESS problem is why did adding an observer cause other code to cause an exception and OK, the exception is gone, but do I really understand why it's gone and should this change have actually fixed it? I'm assuming that the bad access is on the setting of the property within another class. I'm assuming that the way the enum is declared and exposed is where the problem is and that is causing the exception. Where its value is being set is where the debugger stops and tells me the exception is coming from. What felt really odd to me was that simply adding an observer to a property in one class caused other code which set the property to trigger the exception to be thrown. However… all of the classes in this iOS project have their ivars defined in their interfaces and then properties created for all of them and occasionally synthesizing the properties manually. I think we all stopped doing this in 2012 and I'm not going to address all of this until I know the product better. What this leads to though is a case of OK, I'm going to believe the debugger and try to make sure I address KVO/KVC compliance on the observed and make sure that the property is about to be observed and changed by multiple sources. So, I tried what I thought would be good practices. Make sure the enum is backed by modern and KVC compliant approaches even though properties exposed through @synthesize should be KVO compliant, in case the way this property is exposed isn't. For example, due to the way the code is set up, what if the property being changed isn't the property I think it is, but the ivar instead? I didn't change the way the property is @synthesized (still manually), I did change the property's atomicity to atomic without affecting the error, the only changes I did make were to use NS_Enum and declare the enum type as NSInteger. In fact, a quick test changing the type of the NS_ENUM from NSInteger back to int doesn't cause the BAD_ACCESS to reappear. I hate to mark something this core as I don't know why but it works, but I don't know but it works. Gremlins, I think. Thanks for taking the time to eyeball this. Alex Zavatone On Apr 7, 2015, at 11:32 AM, Roland King wrote: On 7 Apr 2015, at 23:12, Alex Zavatone z...@mac.com wrote: To answer my own question, changing the enum to an NSInteger backed NS_Enum resulted in no more bad access exceptions from other chunks of code attempting to change the APP_State property. typedef NS_ENUM(NSInteger, APP_State) { APP_State_Normal = 0, APP_State_Expired = 1, APP_State_Waiting = 2 }; Changing the atomicity of the exposed property had no effect on whether the exception was issued or not. Hope this helps someone. Alex Zavatone I was just looking at some of my own code because I’m pretty sure I use enums all the time in properties which are KVO and observe them and update them, and I’ve never once had to mess around with NS_ENUM to make them work. And indeed I found 4 examples quite quickly, all of which look very much like your original code, a typedef’ed enum used as a property. So I really don’t know where your bad accesses were coming from. This was all ObjC right ? ___ 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: Assuring KVO compliance.
On Apr 7, 2015, at 7:04 AM, Alex Zavatone z...@mac.com wrote: The code that I've inherited has an enum (not an NSEnum) that represents the app's connected state, 0, 1 or 2. There’s no difference. NS_ENUM is just a macro that defines a C enum, but uses some newer (C99?) syntax to specify the integer size that the enum should use. (Without that, if you just define a plain enum its size will be sizeof(int), IIRC.) Results in this: Thread1: EXC_BAD_ACCESS (code=1,address = 0x003f8f3) That’s not a useful crash report. All it says is “something accessed an invalid memory address. At a bare minimum you should show the top few lines of the stack down to your application code. I wouldn’t expect any sort of problem with a property that’s an enumerated type. I’ve done it often, and there are a lot of properties like that in UIKit, for example. But without a backtrace there’s no way of knowing why this failed. To answer my own question, changing the enum to an NSInteger backed NS_Enum resulted in no more bad access exceptions from other chunks of code attempting to change the APP_State property. So, all you did was change the integer size of the value and the crash went away. This smells rather like there’s a bug lurking elsewhere in the app code that just happened to go away because of some slight change in the alignment of the value or the code being generated. If I were you I’d back out that change and debug what the actual crash is coming from. —Jens ___ 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: Assuring KVO compliance.
On Apr 7, 2015, at 3:13 PM, Jens Alfke wrote: On Apr 7, 2015, at 7:04 AM, Alex Zavatone z...@mac.com wrote: The code that I've inherited has an enum (not an NSEnum) that represents the app's connected state, 0, 1 or 2. There’s no difference. NS_ENUM is just a macro that defines a C enum, but uses some newer (C99?) syntax to specify the integer size that the enum should use. (Without that, if you just define a plain enum its size will be sizeof(int), IIRC.) Results in this: Thread1: EXC_BAD_ACCESS (code=1,address = 0x003f8f3) That’s not a useful crash report. All it says is “something accessed an invalid memory address. At a bare minimum you should show the top few lines of the stack down to your application code. I wouldn’t expect any sort of problem with a property that’s an enumerated type. I’ve done it often, and there are a lot of properties like that in UIKit, for example. But without a backtrace there’s no way of knowing why this failed. Thanks. I didn't want to flood the list with extra data, but it appears I should have in this case. To answer my own question, changing the enum to an NSInteger backed NS_Enum resulted in no more bad access exceptions from other chunks of code attempting to change the APP_State property. So, all you did was change the integer size of the value and the crash went away. This smells rather like there’s a bug lurking elsewhere in the app code that just happened to go away because of some slight change in the alignment of the value or the code being generated. Thanks. That's what I was afraid of. If I were you I’d back out that change and debug what the actual crash is coming from. With over 100 cases of @catch (NSException *exception) in this project, I think you're many times more right than you know. We've got LOADS of cases of using the appDelegate as a hold-all for most everything and the appDelegate is referred to many times in many methods in many classes. Lots of 2011 style interface and @property definition as well where the ivar is declared in the interface and then the @property is and then @synthesized. Basically, with all that's obviously out of the ordinary here, I'm looking for a good strategy to find the most salient path to identifying the issue here and refactoring/modernizing as I go along. The first step, I guess, is recreating the exception in a fresh copy of the project. Thanks much to you and Quincey. I hope to get more on this to indicate an appropriate culprit and path. Alex Zavatone ___ 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
Core Data To-Many Relationship KVO
I have a Core Data in-memory store. There is a managed object which uses KVO on a to-many relationship property of itself. When an object at the other end of the relationship is deleted using [managedObjectContext deleteObject:object] the KVO change notification is not sent right away. What triggers or will trigger the KVO change notification? 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: Core Data To-Many Relationship KVO
On 12 Feb 2015, at 07:27, Richard Charles rcharles...@gmail.com wrote: I have a Core Data in-memory store. There is a managed object which uses KVO on a to-many relationship property of itself. When an object at the other end of the relationship is deleted using [managedObjectContext deleteObject:object] the KVO change notification is not sent right away. What triggers or will trigger the KVO change notification? Richard Charles committing the core data changes removes them from all the relationships and fires KVO changes. see propagatesDeletesAtEndOfEvent: and commitPendingChanges. In AppKit usually deletes are propagated once around the event loop, in other places they won’t propagate until there’s a save or commitPendingChanges: is called. ___ 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: Core Data To-Many Relationship KVO
On Feb 11, 2015, at 4:51 PM, Roland King r...@rols.org wrote: committing the core data changes removes them from all the relationships and fires KVO changes. see propagatesDeletesAtEndOfEvent: and commitPendingChanges. In AppKit usually deletes are propagated once around the event loop, in other places they won’t propagate until there’s a save or commitPendingChanges: is called. What “event” does propagatesDeletesAtEndOfEvent refer to? An event loop, some type of Core Data event? The documentation as I read it is unclear. Also commitPendingChanges: does not appear to be in any method of the Cocoa frameworks. 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: Core Data To-Many Relationship KVO
On 12 Feb 2015, at 08:27, Richard Charles rcharles...@gmail.com wrote: On Feb 11, 2015, at 4:51 PM, Roland King r...@rols.org wrote: committing the core data changes removes them from all the relationships and fires KVO changes. see propagatesDeletesAtEndOfEvent: and commitPendingChanges. In AppKit usually deletes are propagated once around the event loop, in other places they won’t propagate until there’s a save or commitPendingChanges: is called. What “event” does propagatesDeletesAtEndOfEvent refer to? An event loop, some type of Core Data event? The documentation as I read it is unclear. No idea - why don’t you put a breakpoint in your KVO handler and see where it’s being called from, my guess would be the end of the event loop. If you want it earlier try calling the method to process pending changes, or remove it from the relationship yourself as well as deleting it. Also commitPendingChanges: does not appear to be in any method of the Cocoa frameworks. processPendingChanges:, it’s on NSManagedObjectContext 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: Core Data To-Many Relationship KVO
On Feb 11, 2015, at 5:36 PM, Roland King r...@rols.org wrote: processPendingChanges:, it’s on NSManagedObjectContext That’s what I was looking for. Thanks for your help. 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
OS X 10.10 KVO default behaviour change when observers not removed
Jens mentioned in a previous thread that he was not quite sure whether to always remove observations or not. This was bugging me. I always did it, though more out of habit than absolute conviction. The code below confirms that not removing the observation prior to deallocating the observing object really is toxic. As shown if linked on OS X 10.9 the code below may run to completion or may terminate with an access violation (YMMV). If the code completes a warning is logged stating that the observed object still has registered observers. When we mutate the observed key path the deallocated instance gets messaged, which may or may not be terminal. If linked on OS X 10.10 then the code never completes. Either it terminates due to an access violation or it aborts as the previous console warning is now a NSInternalInconsistencyException and the thread aborts. This issue can lurk in code without causing problems if the observed and observing objects tend to get deallocated together. One can easily see how refactoring could cause the observed object to outlive its observer and produce instability. #import Foundation/Foundation.h @interface MGSObservedObject : NSObject @property (strong) NSString *name; @end @interface MGSObservingObject : NSObject @end int main(int argc, const char * argv[]) { @autoreleasepool { MGSObservedObject *observedObject = [MGSObservedObject new]; MGSObservingObject *observingObject = [MGSObservingObject new]; [observedObject addObserver:observingObject forKeyPath:@name options:0 context:NULL]; observedObject.name = @Laura Palmer; BOOL removeObservation = NO; if (removeObservation) { [observedObject removeObserver:observingObject forKeyPath:@name context:NULL]; } BOOL deallocObservingObject = YES; if (deallocObservingObject) { observingObject = nil; } BOOL pokeObservedObject = YES; if (pokeObservedObject) { observedObject.name = @Ronette Pulaski; // on 10.9 observer may still register change or we may crash, who knows! } } return 0; } @implementation MGSObservingObject - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context { NSLog(@observed : %@, [object valueForKeyPath:keyPath]); } @end @implementation MGSObservedObject @end ___ 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
Self KVO...
I’m not sure I am having a hard time figuring this out and I am just not finding anything via Google. I am writing a NSTextFieldCell subclass and I want to recalculate the size whenever the string value changes via a binding. What I can’t seem to figure out is how to observe the change. I could register each instance with itself for change notifications, but that just seems like an odd way to go about it. Seems like it should be possible to just override setValue:forKeyPath:, but that never seems to be called. Any suggestions would be welcome. ___ 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: Self KVO...
On Oct 9, 2014, at 10:56 PM, Randy Widell randy.wid...@gmail.com wrote: I’m not sure I am having a hard time figuring this out and I am just not finding anything via Google. I am writing a NSTextFieldCell subclass and I want to recalculate the size whenever the string value changes via a binding. What I can’t seem to figure out is how to observe the change. I could register each instance with itself for change notifications, but that just seems like an odd way to go about it. Seems like it should be possible to just override setValue:forKeyPath:, but that never seems to be called. I would expect that the control will call -setObjectValue: on the cell when it (the control) receives a new value via the binding. It may not be the case that the control ever gets -setValue:forKey: when the property to which it is bound changes. That's one possible way for the implementation to work, but as least as likely is for the control to have -observeValueForKeyPath:… to be called on it because it was using KVO to observe the property to which it is bound. In any case, the cell should be entirely insulated from the way in which the control received its new value. When implementing a cell, you should not need to care about bindings or whatever. Regards, Ken ___ 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: Self KVO...
On Oct 9, 2014, at 21:13, Ken Thomases k...@codeweavers.com wrote: On Oct 9, 2014, at 10:56 PM, Randy Widell randy.wid...@gmail.com wrote: I’m not sure I am having a hard time figuring this out and I am just not finding anything via Google. I am writing a NSTextFieldCell subclass and I want to recalculate the size whenever the string value changes via a binding. What I can’t seem to figure out is how to observe the change. I could register each instance with itself for change notifications, but that just seems like an odd way to go about it. Seems like it should be possible to just override setValue:forKeyPath:, but that never seems to be called. I would expect that the control will call -setObjectValue: on the cell when it (the control) receives a new value via the binding. It may not be the case that the control ever gets -setValue:forKey: when the property to which it is bound changes. That's one possible way for the implementation to work, but as least as likely is for the control to have -observeValueForKeyPath:… to be called on it because it was using KVO to observe the property to which it is bound. In any case, the cell should be entirely insulated from the way in which the control received its new value. When implementing a cell, you should not need to care about bindings or whatever. Regards, Ken Oh, man, thanks. I knew it had to be something straightforward. Yeah, the whole KVO route seemed like a weird way to go about it. Went down the wrong rabbit hole. Thanks! ___ 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: Extending KVO to scalar struct types?
On 29 Aug 2014, at 3:56 pm, Graham Cox graham@bigpond.com wrote: You might wonder if I already know the type why this is even useful. Having given this a lot more thought, I think it's simpler just to break down the compound properties into singular ones on the target object. These can be derived from the compound ones and using +keyPathsForValuesAffectingKey, it's easy to trigger notifications off of these derived properties. Since I only have a few of these compound properties, it's not too much work to add derived singular properties and design my UI controller around those. I think the takeaway from the exercise for me is don't use properties returning points, sizes or rects if you want to eventually hook these up to a UI. --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
Extending KVO to scalar struct types?
Hi all, I had an idea that could simplify quite a bit of tedious glue code, but I'm not sure if it's feasible. -[NSObject setValue: forKeyPath:] can take a key path for any property, but not for fields of that property if it's a scalar struct type, e.g. @myObject.location.x isn't allowed if the 'location' property is NSPoint for example, because NSPoint isn't an object. I was wondering if I could figure out a way to make this work as a pre-processing step prior to setting the value. So for example, knowing that I want to set a field of a struct property, I could call a special method that strips off the last part of the key path, uses the remainder to get the current scalar value, and then use the last part of the path to mutate the relevant struct field prior to setting it back, again just using the remainder of the keyPath. The problem here is being able to get to the struct's field at runtime given its name as a string. Is that even possible? If it is my scheme should work, otherwise it's back to the drawing board. Incidentally am I right in thinking that bindings is able to do this? --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: Extending KVO to scalar struct types?
On Aug 28, 2014, at 8:25 PM, Graham Cox graham@bigpond.com wrote: The problem here is being able to get to the struct's field at runtime given its name as a string. Is that even possible? Not in C. The closest you can get is the @encode(…) directive, which at compile-time evaluates to the type-encoding string of the argument. But that only tells you the types of the struct fields, not the names. You might be able to do this with RTTI in C++; I've never used that. —Jens ___ 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: Extending KVO to scalar struct types?
On Aug 28, 2014, at 10:25 PM, Graham Cox graham@bigpond.com wrote: I had an idea that could simplify quite a bit of tedious glue code, but I'm not sure if it's feasible. -[NSObject setValue: forKeyPath:] can take a key path for any property, but not for fields of that property if it's a scalar struct type, e.g. @myObject.location.x isn't allowed if the 'location' property is NSPoint for example, because NSPoint isn't an object. I was wondering if I could figure out a way to make this work as a pre-processing step prior to setting the value. So for example, knowing that I want to set a field of a struct property, I could call a special method that strips off the last part of the key path, uses the remainder to get the current scalar value, and then use the last part of the path to mutate the relevant struct field prior to setting it back, again just using the remainder of the keyPath. The problem here is being able to get to the struct's field at runtime given its name as a string. Is that even possible? If it is my scheme should work, otherwise it's back to the drawing board. Incidentally am I right in thinking that bindings is able to do this? Bindings it not able to do this in most cases. In case you're not aware, certain Core Animation classes have support for this sort of thing: Core Animation Programming Guide: Key-Value Coding Extensions – Key Path Support for Structures. https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/CoreAnimation_guide/Key-ValueCodingExtensions/Key-ValueCodingExtensions.html#//apple_ref/doc/uid/TP40004514-CH12-SW8 I suspect they use type encoding to interrogate the type of the property (via its getter or setter signature, as appropriate) and then support field access for certain specific structure types they understand. I don't know if there's a general way to do it. Regards, Ken ___ 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: Extending KVO to scalar struct types?
On 29 Aug 2014, at 1:52 pm, Ken Thomases k...@codeweavers.com wrote: In case you're not aware, certain Core Animation classes have support for this sort of thing: Core Animation Programming Guide: Key-Value Coding Extensions – Key Path Support for Structures. https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/CoreAnimation_guide/Key-ValueCodingExtensions/Key-ValueCodingExtensions.html#//apple_ref/doc/uid/TP40004514-CH12-SW8 Ah, that's where I saw it (not bindings) I suspect they use type encoding to interrogate the type of the property (via its getter or setter signature, as appropriate) and then support field access for certain specific structure types they understand. Actually that will work for me. I only need to support size, points and rects at the moment, so it's easy enough to use the -objCType to see which one I have and then just change the field according to which specific string I pass. A category on NSValue will wrap that up neatly enough. Thanks! --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: Extending KVO to scalar struct types?
On Aug 28, 2014, at 21:09 , Graham Cox graham@bigpond.com wrote: Actually that will work for me. I only need to support size, points and rects at the moment, so it's easy enough to use the -objCType to see which one I have and then just change the field according to which specific string I pass. A category on NSValue will wrap that up neatly enough. You can get the information you need out of the Obj-C runtime. In the case where a key represents an @property (which is the only case I actually use) the code looks like this (omitting error checking): objc_property_t classProperty = class_getProperty (owningClass, classPropertyName); NSString* attributes = @(property_getAttributes (classProperty)); NSArray* components = [attributes componentsSeparatedByString: @,”]; Now you have an array of strings representing property attributes, the first character of which is the attribute type. The property type is attribute type “T”, and the rest of the string for a struct type has this form: {struct-tag-name=… which you can use to figure out what you need. ___ 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: Extending KVO to scalar struct types?
On 29 Aug 2014, at 3:20 pm, Quincey Morris quinceymor...@rivergatesoftware.com wrote: {struct-tag-name=… which you can use to figure out what you need. This is much what I'm doing, but it's a bit simpler - I don't need to introspect the property details of the target object, since I know that -valueForKey: will return scalar types wrapped in an NSValue. NSValue has -objCType, which for a struct returns {name=...}, e.g. {CGSize=dd}. I already know that a given property of a given object is a CGSize (say), so for those properties I set through my 'unwrapper' method which uses the following code in a category on NSValue to do the work: const char* typ = [self objCType]; NSString* typeString = [NSString stringWithCString:typ encoding:NSASCIIStringEncoding]; // split out point, size and rect structs (others not supported at present) if([typeString rangeOfString:@{CGPoint].location == 0) { // it's a point NSPoint p = [self pointValue]; if([fieldName isEqualToString:@x]) p.x = v; else if([fieldName isEqualToString:@y]) p.y = v; return [NSValue valueWithPoint:p]; } else if([typeString rangeOfString:@{CGSize].location == 0) { // it's a size NSSize s = [self sizeValue]; if([fieldName isEqualToString:@width]) s.width = v; else if ([fieldName isEqualToString:@height]) s.height = v; return [NSValue valueWithSize:s]; } else if([typeString rangeOfString:@{CGRect].location == 0) { ... more This isn't general, but it covers the common cases of Points, Sizes and Rects, which is all I need at present. The higher level unwrapper splits up the keypath name so that the last component is the struct field name, which it passes into this code. The NSValue itself is returned by -valueForKeypath: on the target object using the rest of the path (i.e. the last component is removed). For specific objects this could be done in an override of -setValueForKeyPath, but I'm actually implementing this in the controller rather than try and subvert the more general KVC mechanics - seems a bit safer that way. Works nicely for my use case :) --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: Extending KVO to scalar struct types?
On 29 Aug 2014, at 3:48 pm, Graham Cox graham@bigpond.com wrote: I already know that a given property of a given object is a CGSize (say) You might wonder if I already know the type why this is even useful. In a UI, different controls might set values independenty such as the x and y of a point. Each control is actually setting the same property (a point), but driving separate parts of it (the x and y). The UI controller is simplified if it can treat compound properties as if they were a single value, e.g. location.x, location.y, otherwise every time I set x, I have to go and fetch y as well and set both together (in reality that's still what I'm doing, but the very high level code that responds to the control doesn't need to know about it - it can just call my unwrapper with a keypath extended to include the field). Since I have hundreds of properties driven by UI this way (including multiple values across an array of objects), it's a big saving to genericise it. --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
null value in KVO change dictionary ?
Hello, I'm puzzled by a problem that I am seeing with key value observing an arraycontroller and I'm hoping that someone here could shed some light. Here's the situation: I have a nib with a panel that contains a collectionview and an arraycontroller. It's like some Tool panel in a drawing app. The arraycontroller content binding is bound to a method in the windowcontroller (file's owner) that returns an array of custom objects. The collectionview content and selectionIndexes bindings are bound to the arraycontroller. This all seems to play nicely together. Next, the windowcontroller's document is observing the 'selection' property of the arraycontroller. The purpose is to get hold of whatever object is selected in the collectionview and link that to a 'tool' property of the document. Now, when I change the selection in the collectionview, the document is indeed notified, but what's puzzling me is that the value for the 'new' key in the change dictionary is 'null'. I've tried observing other arraycontroller properties, such as 'selectionIndexes' or 'selectedObjects', and the document gets all the notifications, but 'new' as well as 'old' value in the change dictionary are always 'null', even though I can get a hold of the selected object using '[object selectedObjects]'. So why is this object not in the change dictionary? Thanks for any help. -- Luc Van Bogaert smime.p7s Description: S/MIME cryptographic signature ___ 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: null value in KVO change dictionary ?
On Aug 22, 2014, at 4:31 PM, Luc Van Bogaert luc.van.boga...@me.com wrote: I'm puzzled by a problem that I am seeing with key value observing an arraycontroller and I'm hoping that someone here could shed some light. I've tried observing other arraycontroller properties, such as 'selectionIndexes' or 'selectedObjects', and the document gets all the notifications, but 'new' as well as 'old' value in the change dictionary are always 'null', even though I can get a hold of the selected object using '[object selectedObjects]'. So why is this object not in the change dictionary? This is a long-standing issue with array controllers. The KVO change notifications never include the new or old values, regardless of the KVO options to request them. You just have to query the object via the key path to get the new value. If you request NSKeyValueObservingOptionPrior, you can get the old value at the time that fires. Regards, Ken ___ 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
How can an instance KVO its own and super's attributes, especially with overrides?
I’m writing an NSOperation subclass. Instances are dumped into the main queue, but I hope I stop them from executing right away by overriding -isReady. But the docs say I have to keep the override KVO-compliant. And my formula for the new -isReady uses the old one. Can I observe on super? Without causing infinite recursion if I override an attribute I’m watching? Here’s my header: @interface PrBulkFileOperation : NSOperation +(instancetype)openFiles:(NSArray *)paths application:(NSApplication *)app; @property (readonly) NSArray *files; // Elements are NSURL* @property (readonly) NSApplication * application; @end And the applicable source: @interface PrBulkFileOperation () { NSArray * _files; NSApplication * _app; NSMutableSet *_cancelledFiles, *_failedFiles, *_successfulFiles; NSMutableDictionary * _fileFromBrowser; } @property (readonly) NSSet *cancelledFiles, *failedFiles, *successfulFiles; @property (readonly) NSMutableSet *mutableCancelledFiles, *mutableFailedFiles, *mutableSuccessfulFiles; @property NSMutableDictionary * fileFromBrowser; - (instancetype)initWithFiles:(NSArray *)paths application:(NSApplication *)app; @end @implementation PrBulkFileOperation #pragma mark Property getters setters @synthesize files; @synthesize application = _app; @synthesize cancelledFiles = _cancelledFiles; @synthesize failedFiles = _failedFiles; @synthesize successfulFiles = _successfulFiles; @synthesize fileFromBrowser = _fileFromBrowser; - (void)addCancelledFilesObject:(NSURL *)file { [_cancelledFiles addObject:file]; } - (void)removeCancelledFilesObject:(NSURL *)file { [_cancelledFiles removeObject:file]; } - (NSMutableSet *)mutableCancelledFiles { return [self mutableSetValueForKey:@cancelledFiles]; } - (void)addFailedFilesObject:(NSURL *)file { [_failedFiles addObject:file]; } - (void)removeFailedFilesObject:(NSURL *)file { [_failedFiles removeObject:file]; } - (NSMutableSet *)mutableFailedFiles { return [self mutableSetValueForKey:@failedFiles]; } - (void)addSuccessfulFilesObject:(NSURL *)file { [_successfulFiles addObject:file]; } - (void)removeSuccessfulFilesObject:(NSURL *)file { [_successfulFiles removeObject:file]; } - (NSMutableSet *)mutableSuccessfulFiles { return [self mutableSetValueForKey:@successfulFiles]; } #pragma mark KVO management + (NSSet *)keyPathsForValuesAffectingIsReady { return [NSSet setWithObjects:@super.isReady, @cancelledFiles, @failedFiles, @successfulFiles, nil]; } #pragma mark Conventional overrides - (BOOL)isReady { return [super isReady] (self.cancelledFiles.count + self.failedFiles.count + self.successfulFiles.count = files.count); } @end Are my key paths for my own attributes correct? Can I point to an attribute from super with “super.whatever”? Can I really trigger my ready flag with just indirect observations on the four attributes I need? — Daryle Walker Mac, Internet, and Video Game Junkie darylew AT mac DOT 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: How can an instance KVO its own and super's attributes, especially with overrides?
On Aug 20, 2014, at 11:02 PM, Daryle Walker dary...@mac.com wrote: I’m writing an NSOperation subclass. Instances are dumped into the main queue, but I hope I stop them from executing right away by overriding -isReady. But the docs say I have to keep the override KVO-compliant. And my formula for the new -isReady uses the old one. Can I observe on super? super refers to the same object as self. There's no separate thing to observe. super is not a pointer to an object, actually. It's only valid as a receiver of a message invocation and the only thing it does is modify the dispatch of that message. It modifies how the runtime searches for a method implementation for that message. In particular, the search starts with the methods implemented by the superclass of the code into which the super keyword was compiled, skipping over any methods supplied by the current class and any subclasses. (More specifically, a message to super translates into a call to one of the objc_msgSendSuper*() functions rather than objc_msgSend*(). But the specified receiver is the same exact pointer. For objc_msgSendSuper*(), the receiver is passed indirectly in a struct, but, still, it's the same object pointer.) It follows that super doesn't have separate attributes from self. If the superclass modifies one of its attributes, it's modifying the object's attributes, period. If it does so in a KVO-compliant manner, it will emit KVO change notifications. This is indistinguishable to observers from when your subclass modifies them. + (NSSet *)keyPathsForValuesAffectingIsReady { return [NSSet setWithObjects:@super.isReady, @cancelledFiles, @failedFiles, @successfulFiles, nil]; } super is not a key – it doesn't name a property – so it has no place in a key path. It also makes no sense. This is saying the isReady property depends on the isReady property. (Remember, there's no separate object. super is just a reference to self.) So, you need to drop the super.isReady pseudo-key-path. However, there's a problem with your method. If a superclass implements +keyPathsForValuesAffectingIsReady or +keyPathsForValuesAffectingValueForKey: which checks for @isReady, then you would mask that and break stuff. You might be tempted to fix that by invoking [super keyPathsForValuesAffectingIsReady], but you can't be sure that the superclass used that form of the method. Then, you might be tempted to invoke [super keyPathsForValuesAffectingValueForKey:@isReady]. The problem there is that a superclass may have implemented +keyPathsForValuesAffectingIsReady. In that case, it will be relying on the NSObject implementation of +keyPathsForValuesAffectingValueForKey: turning around and invoking +keyPathsForValuesAffectingIsReady for that key. But how would NSObject's implementation invoke that? It will send it to self (the class object, since these are class methods). But that will invoke your implementation again. You'll get infinite recursion. So, I think the only safe approach when you're overriding a property is to override +keyPathsForValuesAffectingValueForKey: and not +keyPathsForValuesAffectingIsReady. In your override, you pass through to super. Then, you check if the key is @isReady and, if it is, add your key paths. - (BOOL)isReady { return [super isReady] (self.cancelledFiles.count + self.failedFiles.count + self.successfulFiles.count = files.count); } Are my key paths for my own attributes correct? Yes. Can I point to an attribute from super with “super.whatever”? No and it's not necessary. If the superclass changes what its implementation of -isReady returns, then it must emit KVO change notifications since it promised in its design contract that that property is KVO-compliant. Those change notifications reach the same observers and have the same meaning as ones you would emit yourself. Can I really trigger my ready flag with just indirect observations on the four attributes I need? Yes. You don't show any mutation of the files property. I'm assuming it is set during initialization and never changes after that. If that's correct, then it's KVO-compliant and you're good. Regards, Ken ___ 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
When would I use this (im)mutable property pair setup? (Misunderstanding advanced KVO)
As I’m stripping out the NSDocument stuff, I realize that I need some sort of global object to hold each window(-controller) as I create them, otherwise ARC will purge them soon after creation. The application delegate seems like a good option, as it’s my only other custom class and Apple uses it to store the window in sample projects with a single window. I read a neat technique at http://eschatologist.net/blog/?p=189, and I’m wondering if I would ever need it and should switch to something easier. //==In the header file=== @interface PrairieAppDelegate : NSObject NSApplicationDelegate, NSOpenSavePanelDelegate // unrelated declarations... @property (nonatomic, copy) NSSet * windowControllers; @property (nonatomic, readonly) NSMutableSet * mutableWindowControllers; @end //= I put the implementation methods in the source file: //==In the implementation file=== #pragma mark Private interface @interface PrairieAppDelegate () { NSMutableSet * _windowControllers; } @end @implementation PrairieAppDelegate #pragma mark Initialization - (id)init { if (self = [super init]) { _windowControllers = [[NSMutableSet alloc] init]; } return self; } // No explicit dealloc. #pragma mark Property getters setters // trim unrelated property accessors... - (NSSet *)windowControllers { return [NSSet setWithSet:_windowControllers]; } - (void)setWindowControllers:(NSSet *)windowControllers { [_windowControllers setSet:windowControllers]; } - (void)addWindowControllersObject:(PrBrowserController *)controller { [_windowControllers addObject:controller]; } - (void)addWindowControllers:(NSSet *)controllers { [_windowControllers unionSet:controllers]; } - (void)removeWindowControllersObject:(PrBrowserController *)controller { [_windowControllers removeObject:controller]; } - (void)removeWindowControllers:(NSSet *)controllers { [_windowControllers minusSet:controllers]; } - (void)intersectWindowControllers:(NSSet *)controllers { [_windowControllers intersectSet:controllers]; } @synthesize mutableWindowControllers = _windowControllers; #pragma mark NSApplicationDelegate overrides //… //= My window-controller class instances put themselves in the set on “init” and remove themselves on “dealloc”. I originally had “mutableWindowControllers private to the implementation file, but the window-controller instances couldn’t insert themselves with only “windowControllers public. That makes sense if I had an actual NSSet; but then what are these mutator methods actually supposed to do? When would they ever be called? Do I have to move them to the header file? Should I get rid of them and stick to just a mutable-set property? (Delete the current “windowControllers” and rename the mutable variant.) But the text seemed like that would mess up KVO in a different way. — Daryle Walker Mac, Internet, and Video Game Junkie darylew AT mac DOT 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: When would I use this (im)mutable property pair setup? (Misunderstanding advanced KVO)
(reposted for formatting) On Aug 15, 2014, at 16:24 , Daryle Walker dary...@mac.com wrote: As I’m stripping out the NSDocument stuff, I realize that I need some sort of global object to hold each window(-controller) as I create them, otherwise ARC will purge them soon after creation. The application delegate seems like a good option, as it’s my only other custom class and Apple uses it to store the window in sample projects with a single window. I read a neat technique at http://eschatologist.net/blog/?p=189, and I’m wondering if I would ever need it and should switch to something easier. It’s the right idea, but the wrong implementation. @property (nonatomic, copy) NSSet * windowControllers; @property (nonatomic, readonly) NSMutableSet * mutableWindowControllers; Make the “windowControllers” property ‘readonly’ too. Although it’s feasible to allow the entire set to be changed via the setter, there are other ways to do this (e.g. removeAll + add), and you’re unlikely to need to do that anyway. The ‘copy’ property “pretends” that the implementation is something other than it is. - (NSSet *)windowControllers { return [NSSet setWithSet:_windowControllers]; } It’s simpler to ‘return _windowControllers;’. Or, better, use ‘@synthesize windowControllers = _mutableWindowControllers;' Since the return value is type ‘NSSet*’, the client can’t use the pointer to mutate the collection. (You can typically assume the client won’t do something hacky, like cast the pointer back to a NSMutableSet*. If you can’t assume that, you’ve got bigger problems.) - (void)setWindowControllers:(NSSet *)windowControllers { [_windowControllers setSet:windowControllers]; } You don’t need this, if you make the “windowControllers” property ‘readonly’, as I recommended above. - (void)addWindowControllersObject:(PrBrowserController *)controller { [_windowControllers addObject:controller]; } - (void)addWindowControllers:(NSSet *)controllers { [_windowControllers unionSet:controllers]; } - (void)removeWindowControllersObject:(PrBrowserController *)controller { [_windowControllers removeObject:controller]; } - (void)removeWindowControllers:(NSSet *)controllers { [_windowControllers minusSet:controllers]; } These are correct, though you only need one of the ‘add…’ and one of the ‘remove…’ methods. Although it’s not wrong to implement both of each, it’s overkill for a set that’s not going to be very large. It’s typical to implement only the 1st and 3rd of these. (Keep in mind, you’re unlikely to want to add a *set* of window controllers at once.) Note that these are the KVC “mutable unordered accessors” described here: https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/KeyValueCoding/Articles/AccessorConventions.html This means it’s safe to expose these methods publicly. Or you can keep them private, and let clients use “mutableWindowControllers” for all their mutation needs. This is a matter of taste only. - (void)intersectWindowControllers:(NSSet *)controllers { [_windowControllers intersectSet:controllers]; } No, you don’t need this, or any other accessors. If you do everything else right, any client invocation of (say) ‘[myAppDelegate.mutableWindowControllers intersectSet: controllers];’ will get automatically translated into a combination of ‘add…’ and ‘remove…’ methods *and will be KVO-compliant*. Your code isn’t KVO compliant. @synthesize mutableWindowControllers = _windowControllers; No, this is wrong and dangerous. You’re handing out a mutable reference to your private ivar, thus allowing clients to run rampant on your property’s integrity. Instead, you should implement it like this: - (NSMutableSet*) mutableWindowControllers { return [self mutableSetValueForKey: “windowControllers”]; } This returns a proxy object, so your underlying set stays private, and any mutation that a client applies to the proxy is actually applied to your underlying data via your accessors (the ‘add…’ and ‘remove…’ methods) *and* is KVO compliant. Finally, my preference is to use a NSArray metaphor for this sort of thing, rather than a NSSet metaphor. Yes, the collection of window controllers is unordered, but NSSet uses ‘isEqual:’ equality rather than pointer equality to distinguish between members. By default, it’s the same thing, but the reliance on *not* having a customized ‘isEqual:’ for your window controller classes is a hidden fragility in your implementation. Again, because you’re not going to have a very big collection of window controllers, performance and efficiency of the underlying (set vs array) representation is not a significant issue. ___ 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
Re: KVO query
On 13 Aug 2014, at 23:41, Quincey Morris quinceymor...@rivergatesoftware.com wrote: On Aug 13, 2014, at 14:53 , Jonathan Mitchell jonat...@mugginsoft.com wrote: At one point i need to invoke a manual KVO notification like so: [submission willChangeValueForKey:@“status”]; [submission didChangeValueForKey:@“status”]; This raises like so: Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Cannot update for observer NSKeyValueObservance 0x608000ac21b0 for the key path status.name from Submission 0x6080003aa800, most likely because the value for the key status has changed without an appropriate KVO notification being sent. Check the KVO-compliance of the Submission class.’ This is one of those infuriating errors that is hard to make sense of. Try thinking about it literally. Because you’re observing the “status.name” path from ‘submission’, the observer is *also* observing the “name” path from ‘submission.status’**. In your scenario, the originally observed ‘status’ instance (call it X) is no longer the current ‘status’ instance at willChange time (it’s now Y, say), and in general it might not be the same as that at didChange time (Z, say). Even if Y == Z, there’s been a non-KVO-compliant change in ‘status’ prior to the notification being sent. Now, we do this quite often, without problems, but I’d suggest that’s only in cases where the “temporarily non KVO compliant” change is for the *last* key of the path — in which case the last object isn’t being observed, just because it’s the last key. This is where I am getting caught out. As you say it works fine for the last key of the path. It does for me too. I am effectively propagating a C# PropertyChanged event. This approach by itself will never be KVO compliant and will fail when mutating non last components in an observed key path. So, in the case of a non-KVO-compliant change to the value of a non-terminal key path object, the non-KVO-compliance may not be tolerated by the frameworks. Hence this error message. What I suggest you try is to make two properties: “currentStatus” and “observableStatus”. The second of these would be updated KVO compliantly (i.e. via its setter) when you know that the first has changed and the change should be propagated (i.e. in the places where you now trigger the willChange/didChange notification manually). Code in the ‘submission’ class can use ‘self.currentStatus’ to get or set the most recent status object; observers would observe “observableStatus”, of course. Using a proxy property sounds like it might be doable. Thanks Jonathan ___ 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: KVO query
On 13 Aug 2014, at 23:40, Ken Thomases k...@codeweavers.com wrote: You have to issue the -willChange… _before_ the property has changed. That's because that's KVO's only opportunity to get the value that's about to become old and remove its observations for the properties of that old object. So, that pattern of issuing -willChange… followed immediately by -didChange… with nothing actually changing in between is a sure sign of a problem. The solution is annoying but relatively simple. You need to hold a strong reference to the old object in a property of your own. So, you need a property status that is _not_ just a pass-through to some other API. It needs to be backed by an instance variable (e.g. _status) that is a strong reference to the object. Then, when you receive the notification from the underlying API that something has changed, you fetch the new object from that API and assign it to self.status. That assignment is KVO-compliant. You can/should then eliminate your manual -will/didChange… invocations. That all makes sense. I am effectively just propagating the C# PropertyChanged event. This is fundamentally not KVO compliant. C# also provides a PropertyChanging event, though it is not so commonly implemented. For managed event changes to be KVO compliant in managed code I will have to ensure that the managed layer events are sent in a may that is KVO compliant when they emerge in unmanaged code. Thanks Jonathan ___ 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
KVO query
I have a key path like so which is observed: submission.status.name At one point i need to invoke a manual KVO notification like so: [submission willChangeValueForKey:@“status”]; [submission didChangeValueForKey:@“status”]; This raises like so: Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Cannot update for observer NSKeyValueObservance 0x608000ac21b0 for the key path status.name from Submission 0x6080003aa800, most likely because the value for the key status has changed without an appropriate KVO notification being sent. Check the KVO-compliance of the Submission class.’ I am using manual KVO because my submission object is a wrapper around a Mono managed class. I receive a callback that the managed status object has changed and want to propagate that via KVO. The true situation is generic : i receive a callback that a managed property P has changed and want to raise manual KVO notifications in a compliant manner. Is there a way for me to programatically determine what sequence of manual KVO notifications I will require to maintain KVO compliance? I imagine that the framework code uses - observationInfo to achieve this but that is opaque to client code. I am trying to avoid having lots of explicit +keyPathsForValuesAffectingValueForKey: methods. Thanks Jonathan ___ 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: KVO query
Have you implemented +automaticallyNotifiesObserversForKey: and returned NO for “status” ? On Aug 13, 2014, at 2:53 PM, Jonathan Mitchell jonat...@mugginsoft.com wrote: I have a key path like so which is observed: submission.status.name At one point i need to invoke a manual KVO notification like so: [submission willChangeValueForKey:@“status”]; [submission didChangeValueForKey:@“status”]; This raises like so: Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Cannot update for observer NSKeyValueObservance 0x608000ac21b0 for the key path status.name from Submission 0x6080003aa800, most likely because the value for the key status has changed without an appropriate KVO notification being sent. Check the KVO-compliance of the Submission class.’ I am using manual KVO because my submission object is a wrapper around a Mono managed class. I receive a callback that the managed status object has changed and want to propagate that via KVO. The true situation is generic : i receive a callback that a managed property P has changed and want to raise manual KVO notifications in a compliant manner. Is there a way for me to programatically determine what sequence of manual KVO notifications I will require to maintain KVO compliance? I imagine that the framework code uses - observationInfo to achieve this but that is opaque to client code. I am trying to avoid having lots of explicit +keyPathsForValuesAffectingValueForKey: methods. Thanks Jonathan ___ 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: KVO query
On Aug 13, 2014, at 4:53 PM, Jonathan Mitchell jonat...@mugginsoft.com wrote: I have a key path like so which is observed: submission.status.name At one point i need to invoke a manual KVO notification like so: [submission willChangeValueForKey:@“status”]; [submission didChangeValueForKey:@“status”]; This raises like so: Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Cannot update for observer NSKeyValueObservance 0x608000ac21b0 for the key path status.name from Submission 0x6080003aa800, most likely because the value for the key status has changed without an appropriate KVO notification being sent. Check the KVO-compliance of the Submission class.’ I am using manual KVO because my submission object is a wrapper around a Mono managed class. I receive a callback that the managed status object has changed and want to propagate that via KVO. The true situation is generic : i receive a callback that a managed property P has changed and want to raise manual KVO notifications in a compliant manner. Is there a way for me to programatically determine what sequence of manual KVO notifications I will require to maintain KVO compliance? You have to issue the -willChange… _before_ the property has changed. That's because that's KVO's only opportunity to get the value that's about to become old and remove its observations for the properties of that old object. So, that pattern of issuing -willChange… followed immediately by -didChange… with nothing actually changing in between is a sure sign of a problem. The solution is annoying but relatively simple. You need to hold a strong reference to the old object in a property of your own. So, you need a property status that is _not_ just a pass-through to some other API. It needs to be backed by an instance variable (e.g. _status) that is a strong reference to the object. Then, when you receive the notification from the underlying API that something has changed, you fetch the new object from that API and assign it to self.status. That assignment is KVO-compliant. You can/should then eliminate your manual -will/didChange… invocations. Regards, Ken ___ 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: KVO query
On Aug 13, 2014, at 14:53 , Jonathan Mitchell jonat...@mugginsoft.com wrote: At one point i need to invoke a manual KVO notification like so: [submission willChangeValueForKey:@“status”]; [submission didChangeValueForKey:@“status”]; This raises like so: Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Cannot update for observer NSKeyValueObservance 0x608000ac21b0 for the key path status.name from Submission 0x6080003aa800, most likely because the value for the key status has changed without an appropriate KVO notification being sent. Check the KVO-compliance of the Submission class.’ This is one of those infuriating errors that is hard to make sense of. Try thinking about it literally. Because you’re observing the “status.name” path from ‘submission’, the observer is *also* observing the “name” path from ‘submission.status’**. In your scenario, the originally observed ‘status’ instance (call it X) is no longer the current ‘status’ instance at willChange time (it’s now Y, say), and in general it might not be the same as that at didChange time (Z, say). Even if Y == Z, there’s been a non-KVO-compliant change in ‘status’ prior to the notification being sent. Now, we do this quite often, without problems, but I’d suggest that’s only in cases where the “temporarily non KVO compliant” change is for the *last* key of the path — in which case the last object isn’t being observed, just because it’s the last key. So, in the case of a non-KVO-compliant change to the value of a non-terminal key path object, the non-KVO-compliance may not be tolerated by the frameworks. Hence this error message. What I suggest you try is to make two properties: “currentStatus” and “observableStatus”. The second of these would be updated KVO compliantly (i.e. via its setter) when you know that the first has changed and the change should be propagated (i.e. in the places where you now trigger the willChange/didChange notification manually). Code in the ‘submission’ class can use ‘self.currentStatus’ to get or set the most recent status object; observers would observe “observableStatus”, of course. ** Because there’re “really” no such thing as a key path observation. It’s “really” a chain of object/key observations. ___ 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
viewDidLoad and KVO
I often have a view controller that displays a view associated with a model object. So, I'll have a foo property on that VC, and in the prepareForSegue call that presents the VC, I'll setFoo on it. In my -setFoo: method, I set up KVO on the properties of the foo that I'm interested in displaying. In the -observe... method, I update the various bits of UI as properties change. This generally works very well, except when I get to the VC via a segue. -prepareForSegue gets called before -viewDidLoad, so none of the IBOutlets exist yet. I can solve this by doing an explicit UI update step in -viewDidLoad, but that ends up effectively duplicating the UI update code. I can load the view in -setFoo: by referencing self.view, but this seems like a hack. What are other people doing to address this? Any best practice you guys like? -- Rick ___ 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: viewDidLoad and KVO
In my -setFoo: method, I set up KVO on the properties of the foo that I'm interested in displaying. In the -observe... method, I update the various bits of UI as properties change. If you're doing something like this: - (void)setFoo: (Foo *)aFoo { [foo removeObserver:self forKeyPath:@whatever...]; foo = aFoo; [foo addObserver:self forKeyPath:@whatever...; } we used that pattern for a while but were constantly getting bit by observers on objects being dealloced or KVO firing and triggering unwanted side effects if we called setFoo: in dealloc. So we did a complete switch over to doing [self addObserver:self forKeyPath:@foo.whatever... in init, and removeObserver in dealloc, because you can remove an observer on yourself in dealloc without the observers still registered warning. Since it's on self, you can set it before foo exists, and setFoo: triggers it. Plus we could use synthesized setters. - Original Message - From: Rick Mann rm...@latencyzero.com To: Cocoa Developers cocoa-dev@lists.apple.com Sent: Wednesday, June 4, 2014 10:03:20 PM Subject: viewDidLoad and KVO I often have a view controller that displays a view associated with a model object. So, I'll have a foo property on that VC, and in the prepareForSegue call that presents the VC, I'll setFoo on it. In my -setFoo: method, I set up KVO on the properties of the foo that I'm interested in displaying. In the -observe... method, I update the various bits of UI as properties change. This generally works very well, except when I get to the VC via a segue. -prepareForSegue gets called before -viewDidLoad, so none of the IBOutlets exist yet. I can solve this by doing an explicit UI update step in -viewDidLoad, but that ends up effectively duplicating the UI update code. I can load the view in -setFoo: by referencing self.view, but this seems like a hack. What are other people doing to address this? Any best practice you guys like? -- Rick ___ 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://urldefense.proofpoint.com/v1/url?u=https://lists.apple.com/mailman/options/cocoa-dev/lrucker%2540vmware.comk=oIvRg1%2BdGAgOoM1BIlLLqw%3D%3D%0Ar=yJFJhaNnTZDfFSSz1U9TSNMmxGyib3KjZGuKfIhHLxA%3D%0Am=qYOnOaiiYwn8zuydsyBcZuhg6AnT0QTIlKRcBpdwfnM%3D%0As=a80229e6e590ffa9a96606cdc929d245804adff0b0a29bb275a85110c02b83bb 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: viewDidLoad and KVO
On Jun 5, 2014, at 00:26 , Lee Ann Rucker lruc...@vmware.com wrote: If you're doing something like this: - (void)setFoo: (Foo *)aFoo { [foo removeObserver:self forKeyPath:@whatever...]; foo = aFoo; [foo addObserver:self forKeyPath:@whatever...; } we used that pattern for a while but were constantly getting bit by observers on objects being dealloced or KVO firing and triggering unwanted side effects if we called setFoo: in dealloc. So we did a complete switch over to doing [self addObserver:self forKeyPath:@foo.whatever... in init, and removeObserver in dealloc, because you can remove an observer on yourself in dealloc without the observers still registered warning. Since it's on self, you can set it before foo exists, and setFoo: triggers it. Plus we could use synthesized setters. I collect the removeObserver calls into an ignoreFoo method, and similarly the addObserver in an observeFoo method. Then in -dealloc I call -ignoreFoo. I've never run into the (annoying) registration mismatch errors. Your suggestion is a good one, but I don't think it solves the problem I have of -setFoo: being called before -viewDidLoad (before the IBOutlets are non-nil). -- Rick ___ 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: viewDidLoad and KVO
Why don't you use viewWillAppear and viewDidDisappear, to register and unregister observers to your foo property object? If you don't use ARC, be carefull to unregister on dealloc too! El 05/06/2014, a las 09:30, Rick Mann rm...@latencyzero.com escribió: On Jun 5, 2014, at 00:26 , Lee Ann Rucker lruc...@vmware.com wrote: If you're doing something like this: - (void)setFoo: (Foo *)aFoo { [foo removeObserver:self forKeyPath:@whatever...]; foo = aFoo; [foo addObserver:self forKeyPath:@whatever...; } we used that pattern for a while but were constantly getting bit by observers on objects being dealloced or KVO firing and triggering unwanted side effects if we called setFoo: in dealloc. So we did a complete switch over to doing [self addObserver:self forKeyPath:@foo.whatever... in init, and removeObserver in dealloc, because you can remove an observer on yourself in dealloc without the observers still registered warning. Since it's on self, you can set it before foo exists, and setFoo: triggers it. Plus we could use synthesized setters. I collect the removeObserver calls into an ignoreFoo method, and similarly the addObserver in an observeFoo method. Then in -dealloc I call -ignoreFoo. I've never run into the (annoying) registration mismatch errors. Your suggestion is a good one, but I don't think it solves the problem I have of -setFoo: being called before -viewDidLoad (before the IBOutlets are non-nil). -- Rick ___ 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/alejandro.visiedo%40gmail.com This email sent to alejandro.visi...@gmail.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