I'm caching Views in XAML in order to improve performance (don't need to load the controls again). Does this make sense / improve performance of loading controls?
Problem is, although I'm caching / loading the same thing, it seems when I use the Cached View, it has a different appearance. I think it's not using the ItemTemplateSelector properly.
var stringKey = GetMIVMString(mivm);
if (_MyCachedView.ContainsKey(stringKey))
{
MainView.Content = _MyCachedView[stringKey];
}
else
{
var view = new MyInnerView() { DataContext = mivm };
MainView.Content = view;
var itemToCache = MainView.Content as MyInnerView;
if (itemToCache != null)
{
_MyCachedView.Add(stringKey, itemToCache);
}
}
Thanks!
Does this make sense / improve performance of loading controls?
Yes, it does make sense, however there are a few things to consider with this.
Probably the most important thing is memory management. You need to consider how much memory you will be using when caching your views.
Picture the scene:
You have a Window, where the DataContext is a View Model which has loaded 1000 records from a database.
Now, when you cache this view, those records will still be in memory, even though they are not being used, eating up resources that would otherwise be used somewhere else. This isn't a massive problem, as computers these days have plenty of memory. However, you must think about how you are going to handle this problem.
My suggestion would be to free up any resources when you close the view. Effectively do a Dispose, without actually disposing the view model entirely. Once the view is relevant again, perform the setup (load the data) on the view model.
it has a different appearance. I think it's not using the ItemTemplateSelector properly.
Consider looking at Sheridan's View Navigation Approach to define a DataTemplate for your View Models.
Related
I want to add a button that when pressed will lock two sliders together such that the values for the two sliders will always be the same.
I have a solution for this using code, but I'm wondering if there is a way to do this with interface builder alone.
I am worried that the code based solution that one slider may lag behind the other in high CPU utilization environments.
No, there is no way to do this with Interface Builder alone.
Actually everything becomes code in the end, as far as I understand, Interface Builder was built to improve the development time, not necessarily to improve performance, I found this interesting quote on Apple's site about NIBs:
Xcode works in conjunction with these frameworks to help you connect
the controls of your user interface to the objects in your project
that respond to those controls.
Taking into account that, everything will become code (of some level). About NIB files.
At runtime, these descriptions are used to recreate the objects and
their configuration inside your application. When you load a nib file
at runtime, you get an exact replica of the objects that were in your
Xcode document. The nib-loading code instantiates the objects,
configures them, and reestablishes any inter-object connections that
you created in your nib file.
If you would really want to avoid such behavior probably the best you would be able to do is create the widget from scratch, but that would be a totally different question.
Just curious, why wouldn't you want to use code?
Locking the two sliders together in IB is easy. And I've never seen lag. Having that lock dependent on the press of a button is another story, that would have to be done in code, but it would not be too complicated. Assuming you have outlets connected in IB and declared in the controller
-(IBAction)lockSliders:(id)sender {
[slider1 setContinuous:YES];
[slider1 takeIntegerValueFrom:slider2]; // or takeFloatValueFrom or takeDoubleValueFrom
[slider2 setContinuous:YES];
[slider2 takeIntegerValueFrom:slider1];
}
In MVC the View shouldn't hold it's data. However I know in Objective-c you do: [textField setString:#"hello"];, that string is then retained by the text field. The same applies for the textField's font and text colour, etc.
However a UITableView uses a datasource to ask a controller for it's data, it's then up to the controller to reload the table view. But it also stores some data itself, like background colour.
I can understand a reason as to why a UITextView doesn't use a data source the code would become much more lengthy, if every property had to be a method. But why use a data source in some cases and not others, why not just set an array of UITableViewCells (I know that this means cells could not be reused and so it would use more memory, but what other design reason is there), for the UITableView to display?
And when creating you own objects how do you know when to just store a small amount of generic data (e.g. the string a textview displays can only be a string, but any the string itself can be anything)in a view, or use a datasource?
MVC is a pattern, not an edict. Let the view do the work. Some coupling is just going to happen. Follow the guidelines of the pattern, and bend it to the style and desires of your developers and organization.
I'm not familiar with objective-c's mvc framework, but I think I understand the question.
Basically, you don't want the view doing anything with the datasource backend, that is, anything having to do with the plumbing of accessing the DB.
But its ok for the view to have access and use the data itself. That is the M part of MVC. The model gets passed around. The view knows how to display it. The controller knows how to do the business logic to it (including interacting with backend systems like the data access layer).
In the case of data grid, it has to hit the backend to get the data, so it has to rely on the controller.
Ideally, the view knows only about display related information (like the background color). The whole idea being separation of concerns. You want the view to handle just its part of things, like-wise the controller. Then you can modify them independently of each-other.
As for the specifics of the datasource (versus an array), grids tend to be complex. Maybe that is handling paging or other niceties. In this case, I don't think its so much the separation of layers (since an array could just as easily be the model), but handling more functionality.
I'm not sure what you mean re 'storing' small amounts of data in the view. The view should tend to deal with 'view stuff'.
In my app, I have an NSOutlineView that gets its data from a NSTreeController -- which in turn gets it from the Core Data model.
What I would like to do now is to add group headings and maybe some additional rows to the outline view -- obviously things that should exist outside of the model and be part of the view. But, as much as I scratch my head over this, I can't think of any way to make the outline view display these things without modifying the underlying model, which is obviously a big no-no.
Your help is very appreciated. I feel like I am missing something obvious here...
What you would do here is to write a custom NSTreeController subclass. Here is why this is the perfect place for the changes you want to do:
It's not in the model, as you said.
Has nothing to do with the view -- completely transparent.
Basically what you want is to create displayed data out of saved data <- this is a controller's task.
Luckily, the Controller classes in Cocoa are very powerful and very simple at the same this. For you it should be enough to override the -arrangedObjects method. Re-use the default implementation, as it does a lot of useful things like applying predicates or sorting. Here's how this could look like:
- (id)arrangedObjects {
id root = [super arrangedObjects];
// "root" is something like a NSTreeNode but not quite yet
NSTreeNode *newRoot = [NSTreeNode treeNodeWithRepresentedObject: nil];
[[newRoot mutableChildNodes] setArray: [root childNodes]];
// Do your customizations here
return newRoot;
}
The returned object is of the class NSTreeNode - see the documentation on how to do modifications.
I have a subclassed NSTextView that I am manipulating in a separate thread (using performSelectorOnMainThread:withObject:waitUntilDone:) using selectors replaceCharactersInRange:withString:, setSelectedRange:, and insertText:. I'm experiencing flickering of text, and poor performance as the NSTextView updates the display for each and every operation.
Any suggestions on how to control when the display is updated, so I can update it only when actually needed? I tried using various combinations setNeedsDisplay:NO (from both the main and background threads, before and after my updates) which seems to be ignored.
Thanks in advance to anyone who can provide some insight.
I think you should be manipulating the underlying NSTextStorage for the text view, rather than invoking the view's event-related methods directly. This is a pretty classic example of a Model-View-Controller architecture: the NSTextView is the view and the NSTextStorage is the model. Whenever possible, you want to manipulate the model directly and let the controller/view layers deal with updating the view as they see fit.
I have a large number of UIViews that are created in the app delegate applicationDidFinishLaunching and added to an NSMutableArray. The user pages through these views using a page control and scroll view. I created the UIView and its child components in IB. They are wired to a controller. To create 170 views on the iPhone takes about 30 seconds. Eventually, I'll have over 1000 views. Besides being slow, it will also kill the app because of memory use. How much faster and memory efficient is creating everything programmatically without views? How might some of the 6000 fact type apps be doing it?
Is there a better approach instead of creating everything at once? The user may access a view in slot # 400 and begin scrolling from there. Any suggestions are appreciated.
UIViewControllers are lazy. They only load when requested, and automatically unload when memory is tight (and it's easy to unload them manually by calling self.view=nil).
"Load" here means "read a NIB," or "build programmatically." ViewControllers don't really care. Building programmatically can be a little faster since you don't have to hit the disk, but this is seldom the bottleneck, since you only display one view controller at a time.
As to which way to go, it's more style than performance (with the exception of UITableViewCells, which there are reasons you need to build programatically in most cases).
Start by studying the View Controller Programming Guide. It'll show you how iPhone intends you to do this.
To eJames' comment about NIBs being XML files, this may be slightly misleading. NIBs are binary files generated by compiling XIB files which are XML. I'd do actually profiling on the phone before assuming that NIB load time is actually a problem. Much as I am by nature inclined to programatic layout, I've found in practice that NIBs greatly simplify many UI issues in practice, and I always come back to them for large projects.
It is difficult to suggest an answer without knowing a little bit more about your specific problem, but I would venture to say that if you expect to display 1000 different things, creating 1000 individual views in IB is not the way to go.
If your pages share a common layout, you can use a UITableView to display the content of each page, and store only the data for each page in your NSMutableArray.
An excellent tutorial on how to use UITableView can be found here.
If they do not share a common layout, laying things out programmatically will be the way to go. This should be no more memory or processor intensive than doing it using IB, and in fact it will probably be faster, since it removes the need to read and parse an XML file (which is what .NIB files actually are).