Changing a view's initialization based on properties - cocoa-touch

I am trying to build an approach to initialize a view dynamically with different components. Hence, I need to do this on the fly at initialization time. I was thinking of having a struct with default values, and if at any given time the BOOL property of enabling changes, I can reload the input views.
Hence I can loop through the BOOL properties and check if something have changed. Is there a better way of doing this, or does that sound about right?
The architecture:
UIView -> Buttons 1 to 10 laid equally in distance. Based on users preference, the button can be turned on/off, however by default they are all on.

You can use key value coding observer to identify when a value has changed. This could be your trigger to do the necessary update. Polling a boolean value for changes is an unnecessary step and might cause your app to become unresponsive. Also, evaluate if the action that causes the necessity to update/change the view is an action, then you can just implement the changes inside the proper action. For more information, check the Key-Value Observing Programming Guide : http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/KeyValueObserving/KeyValueObserving.html

Related

foreach delegate in QML TreeView

Similar to Foreach delegate in QML view I'm having trouble finding a list of current delegates in a QML TreeView.
However, the actual problem I'm trying to solve is this: I have a C++ class that inherits from QAbstractItemModel that provides several different roles. One of them is Qt::CheckStateRole which functions as an indicator for whether a particular item in the TreeView is selected for display elsewhere in the GUI.
Using Edit QStandardItemModel via TableView with Custom Delegate as a general guide (but adapted to TreeView, hint: use mapToItem() instead of mapFromGlobal()) I'm able to service user clicks to the checkbox that appears in that particular column (role). However, I need to programmatically alter the state of other checkboxes as well (different than the one that got clicked).
Strangely, dataChanged() signals (got them working for all of the other roles) do not affect the state of the checkbox (this is Qt 5.12.2, Ubuntu 20.04). I know what state I want to impose on the checkbox, and of course I should only need to do that for the currently existing delegates. However, it seems like it ought to be extremely convoluted -- the way there's a separate delegate for each role -- on top of the hierarchal nature of the data.
So, is there a way to access the set of currently existing delegates for a particular role that is operative in a QML TreeView?
Instead of trying to iterate over delegates I found that instead I could just create a Connections component within the delegate that connects a global youNeedToUpdateYourValue() signal to the delegate, which reassesses the current state of the checkbox. As the connection will disappear when the delegate is pruned, this seems to be a very elegant way to impose an action upon all existing delegates.

State Change Monitoring

I would like to know if there are any apple Xcode APIs for monitoring state changes before I attempt to build my own. The app I work on changes out several View Controllers. Each controller can have a couple smaller custom views plus the usual check boxes, text fields etc.
The main app needs to know if a view controller or anything on it is edited from its previous state when it is pulled up before it is saved again. We only need to know if the state has changed. The caveat is this: if a user checks a checkbox , that is considered a change of state, but if the user also unchecks the check box, then the state is not changed.
I was looking at the NSUndoManager but I'm nor sure if it will work.
Any suggestions appreciated
There are a couple of approaches:
Implement a centralized "model" object. In this scenario, view controllers would just update properties of this main model object and there's little else you have to do. View controllers would then, in viewDidAppear, check the state of this model object and see if anything changed and act accordingly.
Another approach would be to implement a delegate-protocol pattern, by which the various controllers might have some delegate property that would indicate what object must be informed of data changes. This object that would be the data delegate would be defined to conform to some well defined protocol that indicate how to inform it of the changes.
If, though, you (a) have multiple objects that need to be informed of changes; and/or (b) these changes might happen asynchronously while a view is presented, you need some mechanism to do this notification. The two common approaches would be either with key-value-observing of that model object or by posting a custom notification to the NSNotificationCenter.
To advise you better, we'd need a better sense of the nature of your model object, whether updates are happening asynchronously in the background, etc.

Does setNeedsDisplay:NO have any use at all?

In Cocoa, when we want to redraw a view, we would send the view a setNeedsDisplay: message telling the view to redraw itself with a parameter of YES. I was wondering if there are any circumstances where you would want to send a view setNeedsDisplay:NO, such as multithreading environments, and if sending a view a setNeedsDisplay:YES, then setting it again immediately after with setNeedsDisplay:NO would make the view redraw itself. If there are no reasons to call setNeedsDisplay:NO, then why create such a tedious method, where they could instead implement something like [view redrawView]
setNeedsDisplay:NO may be used in case you want to discard previously called setNeedsDisplay:YES. E.g. sometimes it is easier to mark all subviews as needing display and then run an algorithm to unmark some of them.
As you perhaps know, the display update is automatic (if necessary) at each pass through the normal event loop. You call setNeedsDisplay: in order to force a display update in between if it is necessary.
From the documentation of NSView:
Discussion
Whenever the data or state used for drawing a view object changes, the view should be sent a setNeedsDisplay: message. NSView objects marked as needing display are automatically redisplayed on each pass through the application’s event loop. (View objects that need to redisplay before the event loop comes around can of course immediately be sent the appropriate display... method.)
The boolean parameter to this function simply specifies if the entire bounds of the view in question is affected or not, not if some property "needsDisplay" is set to true or false. Thus, setNeedsDisplay: does indeed work pretty much like a "redrawView", only with the additional parameter.
Edit
The above was inspired from the same documentation:
flag
If YES, marks the receiver’s entire bounds as needing display; if NO, marks it as not needing display.

Using NSManagedObjectContextObjectsDidChangeNotification

In many of my UIViewControllers, I update certain controls based on the state of my data. For example, I might have an edit button on a UITableViewController that should only be enabled when there is one or more items. Or perhaps I want to limit the number of items that can be added, and disable the 'add' button otherwise.
Every time I add or delete an item (or take any other action that can add/remove items), I have to remember to update any controls that might need enabling/disabling. This is trivial for the most part, but doesn't feel comfortable - there is a lot of repetition, and I have to remember to add the calls to updateControlEnabled (or whatever) whenever I add new functionality that might affect the data.
And then I noticed NSManagedObjectContextObjectsDidChangeNotification. Reading the docs, it looks like I can receive a notification whenever something changes in my managed object context. This seems ideal, but I have a few questions:
Is this an appropriate use of
NSManagedObjectContextObjectsDidChangeNotification?
Should I anticipate any performance impact if a controller
subscribes to these and parses each one to see if it needs to update
the UI? I will be checking the userInfo for every change, instead of
only those that I know I will care about.
Where should I subscribe to the notifications? My UIViewController has a
reference to the context, which helps, but I don't know where to
subscribe (loadView? viewDidLoad? init?) such that the view
controller will always have one and only one subscription.
The view controller will continue to receive and process notifications
when it's offscreen - enabling and disabling controls as the
data model is affected from elsewhere. Is this ok?
I guess I'm mostly just wondering if anyone else uses this approach and if so, what their experience is.
Q) Is this an appropriate use of NSManagedObjectContextObjectsDidChangeNotification?
A) Yes - I used it on OSX for a similar purpose.
Q) Should I anticipate any performance impact if a controller subscribes to these and parses each one to see if it needs to update the UI? I will be checking the userInfo for every change, instead of only those that I know I will care about.
A) NO - it will normally be a very small set of objects - ones that were directly changed.
Q) Where should I subscribe to the notifications? My UIViewController has a reference to the context, which helps, but I don't know where to subscribe (loadView? viewDidLoad? init?) such that the view controller will always have one and only one subscription.
A) Well, you cannot affect the UI til the view shows - so probably viewDidLoad or viewWillAppear. The problem with the later is you may get it a few times depending on push/pops, so maybe I'd do it in viewDidLoad.
Q) The view controller will continue to receive and process notifications when it's offscreen - enabling and disabling controls as the data model is affected from elsewhere. Is this ok?
A) Sure - when the view reappears all the elements will be setup correctly.
What you want to do is a classical use of that notification. Just check the thread it comes in on - if its not the mainThread then you want to make all your changes in a block posted to the mainThread.

UIPickerView "preemptive" messages?

I have a situation where my UIPickerView is getting "starved" by a computation task; in other words, the UIPickerView is never updated -- and hence, never sends messages -- because a very heavy compute task is happening. The picker controls aspects of the computation, so the two have to play nice.
I thought of running the computation in a separate thread. Seems like that would leave the picker free to update. However, it'd be a massive undertaking to make my computation multithread-able, so I'd like to find another solution.
Is it possible for a picker (or other UI controls) to "preempt" the execution of a block of code? The computation is in a loop; the number of iterations is what makes it heavy. If the picker could even set a flag somewhere, the loop could break itself, which would work with the flow of the program.
If the loop could poll the picker, that would also work. But, I haven't found a way to do that.
Ideas?
(ps. I posted a similar question yesterday, but didn't really ask it correctly -- didn't quite know what the problem was at that time!)
I assume you mean by flag that if the picker is moved, set a flag. If so you can do this - look at the picker delegates, and when any or all of them get called, set a flag. If your computation is done by another class or classes, then create a new property on those classes "cancelled", the picker can set it, and when set the computation ends.
Before you start another computation you would clear that cancel flag, then kick off the computation.
You can also put a simple toolbar above the picker (common practice) where you have controls that could start the computation, show progress, and cancel it.
EDIT: if the issue is the picker is stuttering when the user is trying to manipulate it, then subclass UIPicker, intercept touch events, and while the picker is being touched, cancel all computations. The only complication is that if the user "spins" the picker, you'd want to wait til it settles, but you would not know how long to wait. Depending on the last touch message, you would have to use a heuristic to wait for didSelectRow: or a timeout before restarting the computation.