Does setting a ViewModel property have thread affinity in Xamarin Forms? - mvvm

The other day, in a code review, I saw some questions about the safety of setting a property from a worker thread. A coworker made the comment, "This property is bound to the UI, and data binding is thread-safe."
I've been using XF for a while, but always assumed this wasn't true: that if I wanted to update ViewModel properties bound to the UI I'd have to make those changes on the UI thread. I just spent a few minutes poking around the documentation, and I don't see an obvious answer other than that directly manipulating BindableProperties has thread affinity. It also matters to me if that's a blocking UI thread execution or not.
I could make a project to test it out myself, but these kind of issues always seem to be intermittent so I'd like to know I'm just missing the right documentation.
(It's relevant to investigating a crash we're seeing that happen within mainly Xamarin call stacks. We raise an event from a worker thread, a VM handles that event and updates some properties. If that's being scheduled for the UI thread, there could be some interleaving issues we didn't prepare for and I'm that much closer to addressing the crash. If it's not being scheduled for the UI thread... I'm surprised it's worked this long.)

I've been using XF for a while, but always assumed this wasn't true: that if I wanted to update ViewModel properties bound to the UI I'd have to make those changes on the UI thread.
You're right. 100% right. You can use Device.InvokeOnMainThread() for this.
To be complete, there is one case where it doesn't matter: PropertyChanged
https://github.com/xamarin/Xamarin.Forms/blob/b645064/Xamarin.Forms.Core/BindingExpression.cs#L542
In that case, the Binding is applied on the main (UI) thread.

Assumptions
We interact with the UI exclusively via binding. So only setters and getters are playing.
Getters
The code referred to in github by #Stephane, only means, that your bound getter(s) will be called in the UI thread. No more no less.
Btw, I would not rely on the source code (I mean: implementation), instead the specification what matters. Implementation can change anytime, and if the specification does not requires this, then unit tests will not check this, so there will be a big surprise...
Setters
However it is still not clear, if can you call your setter(s) in a background thread. Regardless the answer is yes or no, it implies further tasks to solve.
a) If you can call setters in any thread: This means, that your viewmodel internal data is exposed to race conditions, because will be called from the UI thread, and you will access them in a background thread. Conclusion: You must guard the data with the usual concurrency patterns, or use thread safe classes, plus: your getter and setter must be atomic.
b) If it turns out you can not call setters in any thread: Then you must use Device.InvokeOnMainThread(). But this is only the half of the story. In methods of your background thread, you are modifying say a List instance. This will be accessed in the UI thread by the getter, and you are modifying it in a background thread concurrently when you say populate it. Theoretically it is possible the user interacts with the UI during the population period, what let the binding evaluated, getter is called.
Conclusions:
If there are multiple threads accessing to the very same data, you must always lock you data.
Regardless what the current source code implies the safest way to marshall the getter and setter to the UI thread. This will not cause significant overhead: If the executions is already in the UI thread, marshall will do nothing.
Note: Even you marshall both you getters and setter to the UI thread, you will access the data in background threads so guard against race conditions or using thread safe classes are essential.

Related

How to find and cancel background Thread in Swift

I am calling a monitoring task via thread using the following code which is called from the viewDidLoad() in a ViewController:
let myDaemon = Thread(target: self.myMonitor, selector:#selector(self.myMonitor), object: nil)
myDaemon.start()
I have been unable to find a way to find and cancel that thread without closing the app. Is there maybe an alternate way to launch the thread so I can cancel it if needed?
I thought about creating an observer so I could cancel it from another VC but since the Daemon is initialized in the viewDidLoad, I can't access it outside of that block.
I'm using Swift 5. Any suggestions are appreciated.
Thanks,
First, you should almost never use Thread in Swift. Directly accessing threads has been discouraged in Cocoa since longer than Swift has been a language. You should generally be using, in order of preference for the kinds of problems threads are usually used for, async/await (possibly plus an AsyncChannel), OperationQueues, or DispatchQueues. That said, it's a fine question, and there are still very rare cases where a Thread would be appropriate, or at least useful.
To cancel a thread, you will either need to keep track of it (the returned value) so you can call .cancel(), or you need to have a way to communicate with the thread (a Pipe for example) so that you can send a custom "stop" message. That means storing that returned value (or the communication mechanism) somewhere outside the VC.
A ViewController should not own a global object like a Thread. ViewControllers come and go. You should move your thread management (if you're going to do thread management, which you generally shouldn't) into a model object that the VCs share.
Note that canceling a thread does not cause a thread to stop running. The only thing it does is set the isCancelled flag. If is still up to your thread to periodically check itself for cancellation and stop. (You may already know this, but it's a very common confusion, so I want to make sure anyone reading this later is aware.)
There is no list of all existing threads for you to search (and that would be pretty obnoxious since the frameworks generate quite a lot of threads you would need to crawl through). If you want to keep track of a thread, you need to store it somewhere.

Advice on where and when to use ObservableCollection in MvvmCross

In an MvvmCross solution I have a singleton Service class which gets items from a web service and updates a public ObservableCollection. It does this every five seconds and items may be added or removed or their properties changed.
I also have a ViewModel which has a public property which is set to the Service's ObservableCollection. The View is bound to the ObservableCollection so that when items are added, removed or changed the view should update to show this.
However, as expected, I am getting a threading exception because the ObservableCollection is being updated by a thread other than the Main/UI one and the binding therefore cannot update the UI.
Within the Service I do not have the InvokeOnMainThread call readily available so there is no obvious cross platform way to get back on to the main thread when updating the ObservableCollection. Also, doing this just seems wrong - a Service shouldn't be concerning itself with UI matters (whereas a ViewModel can).
Also I am a bit nervous about exposing events from a Service in case this causes ViewModels to not be Garbage Collected. I note that in #slodge's N+1 series http://mvvmcross.wordpress.com/ he is using a messenging service presumably to avoid just this.
So a possible solution may be to publish a message with the latest list of items, and for the ViewModel to subscribe to the message and update its own ObservableCollection on the UI thread by comparing the message contents to it. But this seems a little clunky.
Any suggestions on the best way to implement this would be appreciated - thanks.
The original requirement that INotifyCollectionChanged must be called on the UI thread really comes from the synchronous way that the Windows controls update based upon the Added/Removed/Moved/Replaced/Reset notifications.
This synchronous update is, of course, entirely sensible - it would be very hard to update the UI display while another thread is actively changing it.
There are 'new' changes in .Net 4.5 which may mean the future is nicer... but overall these look quite complicated to me - see https://stackoverflow.com/a/14602121/373321
The ways I know of to handle this are essentially the same as those outlined in your post:
A. keep the ObservableCollection in the Service/Model layer and marshal all events there onto the UI thread - this is possible using any class which inherits from MvxMainThreadDispatchingObject - or can be done by calling MvxMainThreadDispatcher.Instance.RequestMainThreadAction(action)
Whilst it's unfortunate that this means your Service/Model does have some threading knowledge, this approach can work well for the overall App experience.
B. make a duplicate copy of the collection in the ViewModel - updating it by some weak reference type mechanism
e.g. by sending it Messages which tell it what has been Added, Removed, Replaced or Moved (or completely Reset) - note that for this to work, then it's important that the Messages arrive in the correct order!
or e.g. allowing snapshots to be sent across from the Service/Model layer
Which of these to choose depends on:
the frequency, type and size of the collection changes - e.g. whether you are only getting occasional single line updates, whether you are getting frequent large bursts of changes, or whether you are mainly seeing complex groups of changes (which essentially are Resets as far as the UI is concerned)
the animation level required in the UI - e.g. should added/deleted items animate in/out? If no animation is required then it can sometimes be easier just to replace the entire list with a new snapshot rather than to work out the incremental changes.
the size of the collection itself - obviously duplicating a large collection can cause out-of-memory issues
the persistence required on the collection - if persistence is required, then ObservableCollection itself may not be appropriate and you may need to use a custom INotifyCollectionChanged implementation (like the MyCustomList samples)
I personally generally choose the (A) approach in apps - but it does depend on the situation and on the characteristics of the collection and its changes.
Note that while this is most definitely an mvvm issue, the underlying problem is one independent of databinding - how do you update an on-screen display of a list while the list itself is changing on a background thread?

What happens when you try to save managedObjectContext from a different thread?

So I know that NSManagedObjects are not thread safe and managedObjectIDs are, and we need a separate managedObjectContext per thread. But recently I had an issue when I was doing some core data changes in the background (had a separate runloop thread for this) and performSelectorOnThread: method sometimes was simply not invoked on this runloop thread. It turned out that the reason was that I was doing
[someObject.managedObjectContext save:&error]
on this runloop thread and "someObject" was created on the main thread. But it would only "hung" runloop thread once in a while. So the question is what really happens if you try to save context in a different thread. I'm just looking for a deeper understanding, thanks.
From https://developer.apple.com/library/mac/#documentation/Cocoa/Reference/CoreDataFramework/Classes/NSManagedObjectContext_Class/NSManagedObjectContext.html :
Core Data uses thread (or serialized queue) confinement to protect
managed objects and managed object contexts (see “Concurrency with
Core Data”). A consequence of this is that a context assumes the
default owner is the thread or queue that allocated it—this is
determined by the thread that calls its init method. You should not,
therefore, initialize a context on one thread then pass it to a
different thread. Instead, you should pass a reference to a persistent
store coordinator and have the receiving thread/queue create a new
context derived from that.
You will crash. Maybe it will work sometimes and you won't see a crash while debugging, but you should never do this. Object contexts and the managed objects in them should only be used on the thread on which they were created. Apple's documentation is very clear about this and gives many examples of how to handle situations where you may have long running operations (slow fetches or async saves). You should read the docs that talk about threading with Core Data for more info.

iPhone programming - Background saving with core data

I am trying to save data into core data in the background thread, as it takes quite some time to save.
I did:
[self performSelectorInBackGround:#selector(insertRecord:) withObject:data];
When all works fine until the line in insertRecord Method hits contextsave:&error. Program received signal : "SIGABRT"
Am I doing anything wrong? it works ok when its in main thread, I just move the codes to another method and run it in background and it doesn't work anymore.
According to the "Concurrency with Core Data" section of Core Data Programming Guide:
The pattern recommended for concurrent programming with Core Data is
thread confinement: each thread must have its own entirely private
managed object context.
and
Using thread confinement, you should not pass managed objects or
managed object contexts between threads.
It looks like you're passing a managed object to the background thread, which is forbidden. I don't know if you're also trying to share your managed object context between threads.
That document describes a couple of workarounds for passing managed objects to other threads. You'll need to implement one of them.
The problem here is that managed object contexts aren't thread-safe. If your -insertRecord: method uses the main thread's managed object context, you're asking for trouble.
The blog Cocoa Is My Girlfriend has an article, Core Data and Threads, Without the Headache on this very topic and suggests some strategies for saving in the background. The basic idea is to make changes on a context that belongs to a background thread, and then merge the changes into the main thread's context. That gives you an up-to-date context that you can save in the background while still keeping the main thread's context current.

KVO rocks. Now how do I use it asynchronously?

I am sold on KVO but if used in the obvious way it is synchronous. I would like to use it in a situation where I am firing off many KVO messages in rapid succession and it is causing my app to grind to a halt as the KVO messages are handled. Can someone suggest an approach - perhaps using NSOperation or NSThread - that will work here?
My goal is to retain the decoupled, flexibility of KVO if possible.
KVO is inherently single threaded in that the KVO notifications will be delivered on the same thread as the change.
Of course, UIKit and Cocoa both really only want you to be diddling UI elements on the main thread.
Thus, if you are doing asynchronous operations, you are most likely using threads and, if so, already have a synchronization issue in that you need to get the notifs from some thread to the main thread.
And therein lies the key. Instead of blindly forwarding each change notification as it comes in, you can coalesce the change notifications before passing them on to the main thread.
There are a variety of means via which you can do this. The specific solution is going to be quite unique to your application, most likely.
Personally, I try to avoid coalesce-and-forward of fine grained operations. I find it far simpler to tell the main thread that a particular sub-graph of objects have changed. More likely than not, the drawing code that will then make the changes visible to the user is going to need to redraw related state and, thus, related changes will be automatically reflected.
The key, as you have surmised, is to throttle the notifications so you don't bog down app responsiveness (or destroy the devices battery life).
Use the Receptionist Pattern as recommended by Apple https://developer.apple.com/library/ios/documentation/general/conceptual/CocoaEncyclopedia/ReceptionistPattern/ReceptionistPattern.html
Check out NSNotification. It's not quite the same thing, but you can fire off notifications on background threads (with a little bit of research and work). You can maintain the nice decoupling and fire-and-forget behavior.