cocoa - Subtle difference between -removeObserver:forKeyPath: and -removeObserver:forKeyPath:context:? - objective-c

Short version:
What use is -removeObserver:forKeyPath:?
Why not always use -removeObserver:forKeyPath:context:?
Long version
While working on a Cocoa program, I discovered that using -removeObserver:forKeyPath: could (but would not always) lead to an error like:
Cannot remove an observer <ObservedClass 0x1001301d0> for the key path "exampleKeyPath" from <__NSCFConstantString 0x100009138> because it is not registered as an observer.
while using -removeObserver:forKeyPath:context: instead would work just fine.
Since it is required that a context be specified when setting up observation (with -observeValueForKeyPath:ofObject:change:context:), I'm puzzled at why the context:-less removal method exists.
Based on my reading of the NSKeyValueObserving Protocol, I supposed that the removal might apply to the specified observer and specified key path in all contexts, but the failure of -removeObserver:forKeyPath: (with no context) to work as a replacement for -removeObserver:forKeyPath:context: (with a context of NULL) seems to shoot down that idea.
So: why might I have that error? What does -removeObserver:forKeyPath: do with contexts? How's it differ from its context:-equipped younger sibling?
Code example
Problematic code:
-(void) invalidate {
[(id)observedObject removeObserver:self
forKeyPath:#"exampleKeyPath"];
}
Non-Problematic code:
-(void) invalidate {
[(id)observedObject removeObserver:self
forKeyPath:#"exampleKeyPath"
context:NULL];
}

Short version: -removeObserver:forKeyPath:context: was only introduced in 10.7, hence both.
Long version: Why might you have the error? Looks like a bug, either in your code or the system (I've never seen the error and use the shorter version a lot). The descriptions of the two methods do not suggest there should be any difference. If nobody else comes up with an explanation, and you can't find anything in your code, then report a bug to Apple.

The documentation has an excellent discussion as to the use of the new method:
Examining the value in context you are able to determine precisely which addObserver:forKeyPath:options:context: invocation was used to create the observation relationship. When the same observer is registered for the same key-path multiple times, but with different context pointers, an application can determine specifically which object to stop observing
It's just a way to be more specific about just which binding you want to remove from the object. For example, I might bind to a keypath twice, but with the memory locations of different static variables, a little like how dispatch_once() works. The context-free subscription method was the only way of binding to an object until 10.7 rolled around and filled in that gap.
As for your KVO troubles, the problem can occur in many different cases. The most common being that you've subscribed on one thread, then very soon after, removed a subscription from a different thread. Occasionally it can occur because the object you tried to observe was just about to deallocate, meaning you would subscribe to some bogus memory location that happened to fill what you needed to, then removing the subscription from this garbage pointer would be impossible. Either way, make sure to monitor the methods you're utilizing bindings in, as they can be a little unstable if used in the wrong way.

Related

Diffable data source for TableView error on iOS 13: Inconsistent associations for moves

I'm updating my current UITableview to diffable datasource provided by iOS 13 UITableViewDiffableDataSource.
I have an array with a custom object (implementing isEqual: method). On viewWillAppear I load the data from disk and call apply for snapshot.
-(void)updateTableViewAnimated:(BOOL)animated API_AVAILABLE(ios(13.0)){
NSDiffableDataSourceSnapshot *snapshot = [[NSDiffableDataSourceSnapshot alloc]init];
[snapshot appendSectionsWithIdentifiers:#[#"sectionTitle"]];
[snapshot appendItemsWithIdentifiers:self.playlists];
[self.diffDataSource applySnapshot:snapshot animatingDifferences:animated];
}
And everything loads. But when a try to delete an item from the array and call again updateTableViewAnimated:, I get an exception.
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Inconsistent associations for moves'
What does it mean?
How can I solve?
Updated Answer
I was fortunate enough to get a response to the bug I raised regarding this. It turns out that my model object was had incorrect Hashing and Equality checks.
My swift structs conformed to Hashable, but provided a custom implementation of Equatable, whereby I only compared the ID property to determine equality. This meant that it was possible for two objects to be considered equal, but have differing hashes, which confuses the diffing algorithm.
To solve it, I simply removed my custom implementation of Equatable, and used the synthesised version.
You state in your question that you implement isEqual, the ObjC, analog to Swift's ==, but you're probably not providing a hash implementation that agrees with your isEqual implementation in all cases.
Original Answer (Possibly incorrect for this case, but may still useful if queues are the problem)
I don't know if this is the same problem you're having, but in my case it was caused by the applySnapshot method being called from different queues.
The Advanced Data Sources WWDC session mentioned that applySnapshot must be exclusively called on a background queue OR the main queue, but don't call from both. Advanced Data Sources WWDC 2019 - 32:00
In my case I'm using a Combine publisher to react to changes on my data source, and that publisher was sometimes sending values on the main thread or a background thread. To solve my issue I added .receive(on: RunLoop.Main) to the chain.
In your case, maybe you can wrap anything that makes a call to updateTableViewAnimated: in a dispatch_async call using the queue you want it to run on (be that main or background).
Adding to Jasarien informative answer,
you need to keep in mind that UICollectionViewDiffableDataSource use hashable to differentiate between items in your datasource
if your model is a struct, and there're two items in your datasource model which happens to have the exact same values, Hashable protocol will produce the same hashValue for them.
also Equatable protocol will return true! , which will confuse
UICollectionViewDiffableDataSource
Solutions
Make sure that your Datasource Doesn't have any duplicates
if you can't avoid Duplicates, and you don't mind braking Equatable, you might want to add random Value in your datasource, but it's not recommended since the values generated might be equal at any coincidence, as stated in Documentions
*low probability, but it might happen *
Depending on the size and span of range, some concrete values may be represented more frequently than others.

View Key value observations

How do I know what items my object is key-value observing?
The only way I've been able to find out if I'm already observing is to try to remove the observation. If an exception is thrown, then I wasn't observing.
for (AVPlayerItem *item in itemsToRemove) {
#try{
[item removeObserver:self forKeyPath:#"status" context:(__bridge void *)(foo)];
}#catch(id anException){
//wasn't observing
}
}
EDIT: I'm considering using my own dictionary to track observation but that seems redundant since a KVO Dictionary does exist somewhere. Unfortunately there is no API access.
It seems there is no other option than catching the exception, even NSHipster recommends to do so. However, at least in my case, it was hardly ever needed to do the check. After all, you are the one who controls the observers.
You can use a wrapper (like FBKVOController) which adds more sanity to the raw KVO (and makes observing a lot easier, allowing to use blocks). Among other features, it doesn't crash when trying to remove a nonexistent observer:
#discussion If not observing object key path, or unobserving nil, this method results in no operation.
*/
- (void)unobserve:(id)object keyPath:(NSString *)keyPath;
There is no way to know that until you add some boolean flag to your controller and use it to mark and check if your registered for KVO. Normally you should balance out registration and unregistration from KVO observation.
Using exception under ARC is bad and may lead to memory leaks until you use -fobjc-arc-exceptions.
Long story short: Exceptions are expensive, that's why ARC does not properly handle them until you explicitly ask. There is an explanation to that: https://stackoverflow.com/a/4649234/351305

Thread safe hooking of DirectX Device

I successfully hooked BeginScene/EndScene methods of DirectX9's DeviceEx, in order to override regions on the screen of a graphics application. I did it by overriding the first 'line' of the function pointed by the appropriate vtable entry (42 for EndScene) with an x86 jump command.
The problem is that when I would like to call the original EndScene method, I have to write the original code overriden by the jump. This operation is not thread safe, and the application has two devices used by two threads.
I tried overriding the vtable entry or copying it and override the COM interface pointer to the vtable, neither ways worked. I guess the original function pointer is cached somewhere or was optimized in the compilation.
I thought about copying the whole original method body to another memory block, but two problems I'm afraid of: (1) (the easy one I think) I don't know how to discover the length of the method and (2) I don't know if the function body stores offsets which are relative to the location where the function is in memory.
I'm trying to hook WPF's device, if it can help somehow.
Do anyone know a thread safe way for such hooking?
Answering my own question: It seems that for my purpose (performing another method before or instead of the original one within my own process), 'trampoline' is the answer. Generally it means I need to make another code segment that makes exactly what the overriden assembly commands did.
Because it is not an easy task, using an external library is recommended.
A discussion about this topic:
How to create a trampoline function for hook

When to use NSNotificationCenter

I want to have multiple observers on multiple events of a single object (1-to-N relationship).
A mechanism to achieve this task is provided by the NSNotificationCenter. The mechanism looks pretty overkill when used for my problem.
How I would do it manually without the use of NSNotificationCenter:
- (void)addDelegate:(id<DelegateProtocol>)delegate;
- (void)removeDelegate:(id<DelegateProtocol>)delegate;
to add and remove observers from my object.
- (void)someEventFired:(NSObject<NSCopying> *)eventData
{
for (id delegate in delegates) {
NSObject *data = [eventData copy];
[delegate someEventFired:data];
}
}
This mechanism is straight-forward and simple to implement without the objects having to share additional strings.
Is there an official pattern for 1-to-N delegates (like C# events) in an iOS framework besides the NSNotificationCenter?
When should the NSNotificationCenter be used and when not?
When should an implementation like the one I am suggesting here be used and when not?
By convention, delegates should probably only be used for 1:1 relationships. If you really need 1:N relationships for this type of functionality, you have two options:
As you mentioned, NSNotificationCenter.
Key-Value Observing (also known as KVO).
KVO is appropriate if you only care about when a particular property of an object changes. Otherwise, you should really just consider using NSNotificationCenter. You can even be notified only when a specific object posts that notification by passing that object into the addObserver:selector:name:object: method.
Apple uses NSNotification in similar scenarios (like the notifications defined for UITextField, including UITextFieldTextDidBeginEditingNotification, UITextFieldTextDidChangeNotification, and UITextFieldTextDidEndEditingNotification).
using notifications is broadcasting: 1 sender just sends an information and who ever tuned in, receives it. Petty much like a radio station, there is no channel back (lets for the moment forget about telephones)
delegation is something different. Th object, that asks a deleagte to do something, usually needs a result of that request, there fore delegation is a 1-to-1 communication, that is always initiated by the object, not the delegate (while the object can have methods that can be called to inform the object to initiate the communication, ie [tableView reloadData]).
So if the sender needs to get data back, it is delegation. If the sender doesn't care about anything after broadcasting, go with notifications.
If you run into the situation, that you need delegation, but several objects should implement the protocol. you should have 1 delegate, that hold references to the other objects and calls the methods on the senders behalf — or you could go with blocks.
NSNotificationCenter is not overkill for what you are suggesting, it is exactly the right solution. It prevents the observed object having to know or care about its observers, making your code more loosely coupled and cleaner.
Sharing strings for notification names is trivial and they can be defined in either a shared constants file or in the header of the observed object, if your observers need to import this header to do their jobs.
Your proposed solution is neither simpler than using NSNotificationCenter nor is it thread safe.
To make your solution thread safe, you would need to provide a mechanism to prevent the delegates array from changing while the event dispatch for loop is running.
Your solution also requires that you maintain the delegates array in your class. With the NotificationCenter you can simply use the default center and you don't need to implement the add/remove methods in your class. Instead, instances can register themselves to receive notifications as they see best fit (selector/block, queue, source). Your source class doesn't have to worry about those details. It only needs to register itself as a source of notifications of a specified type. Using blocks to handle notifications is really convenient.
An alternative to the notification center is to use Key-Value-Observing if that meets the needs of your use case.
Ultimately, the mechanism you decide to use depends on how best it applies to your specific use case.
A 1-to-N delegate relationship doesn't make sense. Have a look at
- (NSView *)tableView:(NSTableView *)tableView viewForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row
for example. What if this object really had n delegates? How should it decide which of the n views it gets back from all its delegates should be used? Delegates are exactly this 1-to-1 principle.
The NSNotificationCenter is the right approach. Simply use
addObserver:selector:name:object:
respectively
postNotification:
This is definitely not too much code. And it's very easy for you as the center handles all calls.
You don't want to use NSNotificationCenter for anything other than system-wide events (e.g. the appearance of the keyboard or some similar event). The reason is that it is completely not type-safe, can make everything dependent on everything and that you get no compile time checks or usage search results anymore.
KVO in my opinion should not be used to observe changes outside of the object you're listening to since it has similar down sides (no compile time checks, crashes if you don't remove listeners properly or register them twice).
The addDelegate/removeDelegate pattern that you pose is completely the right path in my opinion since that has the advantage of maintaining type-safety and compiler checks and makes dependencies explicit. The only problem is that Apple doesn't supply an out-of-the-box solution for this pattern, since you need a collection type that weakly retains its elements to avoid retain cycles.
However, see code from my BMCommons framework which solves this problem neatly using BMNullableArray and macros. See the BMCore.h header for a definition of those macros:
BM_LISTENER_METHOD_DECLARATION(protocol)
BM_LISTENER_METHOD_IMPLEMENTATION(protocol)
The implementation ensures that the same listener will never be added twice and also that listeners are weakly retained, not causing any crash even if they forget to deregister themselves upon deallocation (although I prefer to catch this condition with an assert since it is a programming mistake).
I say NSNotificationCenter should ALWAYS be used, over the delegate model, except in situations where you query a delegate on information (e.g. -webView:shouldLoadRequest:). It is more stable, easier to implement, and results in cleaner code then trying to use a delegate. The other alternative is blocks, which can be good, but they can be a pain when it comes to memory-managment.
In the end, it's up to you, but I think that NSNotificationCenter is the best way to go in almost any situation, if only for the multiple observer functionality.

Your opinion of this alternative to notifications and delegates: Signals?

SO is telling me this question is subjective and likely to be closed. It is indeed subjective, because I'm asking for the opinion of experienced Objective-C developers. Should I post this somewhere else? Please advise.
Fairly new to Objective-C, though fairly confident in the concept of writing OOP code, I've been struggling with the NSNotification vs Delegate dilemma from the start. I've posted a few questions about that subject alone. I do get the gist, I think. Notifications are broadcasted globally, so shouldn't be used for notifying closely related objects. Delegates exist to hand over tasks to other object, that act on behalf of the delegated object. While this can be used for closely related objects, I find the workflow to be verbose (new class, new protocol, etc), and the word "delegation" alone makes me think of armies and bosses and in general makes me feel uneasy.
Where I come from (AS3) there are things called Events. They're halfway between delegates and NSNotifications and pretty much ruled the world of flash notifying, until fairly recently, a Mr. Robert Penner came along and expressed his dissatisfaction with events. He therefore wrote a library that is now widely used in the AS3 community, called Signals. Inspired by C# events and Signals/Slots in Qt, these signals are actually properties of objects, that you access from the outside and add listeners to. There's much more you can do with a signal, but at it's core, that's it.
Because the concept is so humble, I gave it a go and wrote my own signal class in Objective-C. I've gisted Signal.h/.m here.
A way to use this for notifying class A of an event in class B could look like this:
// In class b, assign a Signal instance to a retained property:
self.awesomeThingHappened = [[[Signal alloc] init] autorelease];
// In class a, owner of class b, listen to the signal:
[b.awesomeThingHappened add:self withSelector:#selector(reactToAwesomeThing)];
// And when something actually happens, you dispatch the signal in class b:
[self.awesomeThingHappened dispatch];
// You might even pass along a userInfo dictionary, your selector should match:
[self.awesomeThingHappened dispatchWithUserInfo:userInfo];
I hope it adheres to the right memory management rules, but when the signal deallocs, it should automatically remove all listeners and pass away silently. A signal like this isn't supposed to be a generic replacement of notification and delegation, but there are lot's of close counter situations where I feel a Signal is cleaner than the other two.
My question for stackoverflow is what do you think of a solution like this? Would you instantly erase this from your project if one of your interns puts it in? Would you fire your employee if he already finished his internship? Or is there maybe already something similar yet much grander out there that you'd use instead?
Thanks for your time, EP.
EDIT: Let me give a concrete example of how I used this in an iOS project.
Consider this scenario of four object types with nested ownership. There's a view controller owning a window manager, owning several windows, each owning a view with controls, among which a close button. There's probably a design flaw in here, but that's not the point of the example :P
Now when the close button is tapped, a gesture recognizer fires the first selector in the window object. This needs to notify the window manager that it's closing. The window manager may then decide whether another window appears, or whether the windows stay hidden alltogether, at which point the view controller needs to get a bump to enable scrolling on the main view.
The notifications from window to window manager, and from window manager to view controller are the ones I've now implemented with Signals. This might have been a case of delegation, but for just a 'close' action, it seemed so verbose to create two delegate protocols. On the other hand, because the coupling of these objects is very well defined, it also didn't seem like a case for NSNotifications. There's also not really a value change that I could observe with KVO, because it's just a button tap. Listening to some kind of 'hidden' state would only make me have to reset that flag when reopening a window, which makes it harder to understand and a little error prone.
Alright, after marinating the answers and comments for a bit, I think I have come to a conclusion that the Signal class I borrowed from AS3, has very little reason for existence in Objective-C/Cocoa. There are several patterns in Cocoa that cover the ranges of use that I was thinking of covering with the Signal class. This might seem very trivial to more experienced Cocoa developers, but it for me it was hard to get the spectrum complete.
I've tried to put it down fairly concisely, but please correct me if I have them wrong.
Target-Action
Used only for notifying your application of user interaction (touches, mostly). From what I've seen and read, there's no way to 'borrow' the target-action system for your own use
KVO (key value observing)
Very useful for receiving notifications when values change in accessible objects. Not so useful for notifying specific events that have no value attached to them, like timer events or interface followup events.
NSNotification
Very useful for receiving notifications when values change or other events happen in less-accessible objects. Due to the broadcast nature of the notification center, this is less suitable for cases where objects have a direct reference to another.
Delegation
Takes the most lines of code compared to the other three, but is also most suitable when the other three are not. Use this one when one object should be notified of specific events in the other. Delegates should not be abused for just accessing methods of the owner object. Stick to methods like 'should', 'will' and 'did'.
Signal
It was a fun experiment, but I mostly used this for classic delegation situations. I also used it to circumvent linked delegates (c delegate of b, b delegate of a, where a starts the event that should make it to c) without wanting to resort to NSNotification.
I still think there should be a more elegant solution for this edge case, but for now I'll
just stick to the existing frameworks. If anyone has a correction or another notification concept, please let me know. Thanks for your help!
It's an interesting idea, but I guess I don't see what makes it dramatically different from Cocoa's notification center. Compare and contrast:
self.awesomeThingHappened = [[[Signal alloc] init] autorelease]; // Your signals library
// Cocoa notifications (no equivalent code)
[b.awesomeThingHappened add:self withSelector:#selector(reactToAwesomeThing)]; // Your signals library
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(reactToAwesomeThing:)
name:#"AwesomeThingHappened"
object:n]; // Cocoa notifications
[self.awesomeThingHappened dispatch]; // Your signals library
[[NSNotificationCenter defaultCenter] postNotificationName:#"AwesomeThingHappened"
object:self]; // Cocoa notifications
[self.awesomeThingHappened dispatchWithUserInfo:userInfo]; // Your signals library
[[NSNotificationCenter defaultCenter] postNotificationName:#"AwesomeThingHappened"
object:self
userInfo:userInfo]; // Cocoa notifications
So, okay. I don't think you're trying to say that, line-for-line, a Signals library for Cocoa is different; rather, the argument goes that it terms of coupling, it isn't as tight as delegates, but not as loose as notifications. To that end, I guess I wonder how necessary it is? I guess I can see somewhat of a need to say "this object 'A' relies heavily on 'B', but doesn't need to be coupled all that closely", but to be honest, that seems like somewhat rare situation.
At any rate, NSNotificationCenter and its ilk, as well as delegates, are pretty standard in Cocoa apps. I always use the rule of thumb that if you deviate from a standard, even a de facto standard, you should have a good reason. If you have a good reason for using neither NSNotificationCenter nor delegates, then you might have a good reason to use this Signals setup. (And as an aside, I'm hesitant to associate notifications and delegates -- they each have a role and exist for different reasons.)
It's hard to say more without a specific use case. I'm inclined to say, "Hey, it looks cool in a geeky way, but it looks like it fills a role already served by notifications." Do you have any specific use cases you could cite?
What do you think of a solution like this?
I don't really see what the benefit is. To me, it seems like a combination of target/action+notifications (you can have multiple target/actions for a single notification event, but the t/a pair is registered with the object itself as opposed to a global notification center). In fact, it's more like key-value-observing that way, except that KVO is limited to observable properties.
Would you instantly erase this from your project if one of your interns puts it in?
No. It's not bad code. In fact, it seems kinda neat. But I just don't see an obvious benefit to it.
Would you fire your employee if he already finished his internship?
Of course not. You don't fire people for writing good code.
Is there maybe already something similar yet much grander out there that you'd use instead?
If you really wanted to make this neat, change the API to use blocks instead. Then you could do:
[object dispatchOnAwesomeThingHappened:^{
NSLog(#"holy cow, something awesome just happened!");
}];
Again, however, you'd be limited to reacting to stuff that the objects explicitly "dispatch". It would be much neater if you could attach stuff to immediately before and/or after any arbitrary method call. If you're interested in that, then I'd check out Aspect Objective-C on github.
I think that there is a gap between NSNotifications and Delegates. And KVO has the worst API in all of Cocoa.
As for NSNotificationCenter here are some of its problems:
it's prone to typos
it's hard to track observers of a given object, therefore hard to debug
it's very verbose
you can only pass notification data in a dictionary, which means you can't use weak references, or structs unless you wrap them. (see: very verbose)
doesn't play nice with GCD: limited support for queues (only blocks)
So there is definitely a need for something better.
I created my own observable class which I use on every project. Another alternative is to use ReactiveCocoa's RACSignal.