NSCell vs NSView: when many controls are needed - objective-c

I am aware that Apple is deprecating the use of NSCell in favour of NSView (see AppKit 10.10 release notes). It was previously recommended that NSCell be used for performance reasons when many controls were needed.
I have spent considerable time implementing a custom control that required many subViews and the performance using NSView-type subViews was not good. See related stackoverflow discussion What are the practical limits in terms of number of NSView-type instances you can have in a window? I was struggling with 1000-2000 in-memory objects (which doesn't seem a lot). What is the actual reason for this limitation?
One thing that confuses me on the above is View-based Cocoa NSTableViews. You can create tableViews with more than 1000-2000 cells and they don't seem to have poor loading and scrolling performance? If each of the cells is an NSView then how is this achieved?
If there are practical limits, then what are Apple thinking when they say they are deprecating usage of NSCell's? I am sure they are aware that some controls need a large number of subViews.
Further, an (probably outdated) Apple Developer Guide give the following explanation for the difference between NSView & NSCell which I need explained further:
"Because cells are lighter-weight than controls, in terms of inherited data and behavior, it is more efficient to use a multi-cell control rather than multiple controls."
Inherited data: this would surely only cause "bloat" if the data was being used => and it would only be used it you needed it?
Inherited behavior: methods that you don't use in a class/object surely can't cause any overhead ?
What is the real difference between the lightweight NSCell versus the heavyweight NSView other than that it just seems to be conventionally accepted?
(I would really like to know.)

A brief and incomplete answer:
NSCells are about drawing state, and not much else. NSViews must draw, but also must maintain and update all kinds of other information, such as their layout, responding to user input events, etc.
Consider the amount of calculation that must happen if you resize a view that contains many hundreds of subviews: every single subview position and size must be maintained according to the existing constraints for the view layout. That alone is quickly a very large amount of processing.
NSCells, in contrast, don't exist in a layout in that way. Their only job is to draw information in a given rectangle whenever asked to do so.

One thing that confuses me on the above is View-based Cocoa NSTableViews. You can create tableViews with more than 1000-2000 cells and they don't seem to have poor loading and scrolling performance? If each of the cells is an NSView then how is this achieved?
NSTableViews re-use views. The only views actually generated are those that are visible, plus maybe a row of views above and a row below the visible area. When scrolling the table, the object value associated with a given row of views is changed to that the views in the row will display different content

Related

When to use NSView's canDrawSubviewsIntoLayer (layer squashing)?

The benefits of setting canDrawSubviewsIntoLayer = true seem to mainly relate to a reduction in memory usage (reference: Apple 2013 WWDC talk 215).
I would think that this would be mainly beneficial for subviews that are more "static" in nature as opposed to subviews whose frames are effectively moving around a lot. I am trying to get clarity on this.
In particular: if you have a grid-like parent view (like NSTableView or NSCollectionView) where each of the child cells (custom NSView instances) is being moved around a lot (queued/dequeued/reused) to allow for scrolling, would it be a good idea to have these cells drawn into the parent layer OR should they be treated as their own individual layers?
[Just to be clear, the main consideration is scrolling performance.]

Is it better to layout subviews in layout/layoutSubviews method?

This question is for both cocoa and cocoa touch. But I'll write an example just for cocoa.
As I understood, I can setNeedsLayout to YES multiple times in a cycle and -layout will be called just once. But are there any other benefits of laying out subviews in -layout method?
Explanation / example: At the moment I'm laying out my subviews in custom viewController (that has default NSView) every time I call custom redraw method. And I call redraw method only when user changes some properties so I really want to relayout subviews.
There are plenty of external circumstances not under your direct control that might cause the system to want to lay out your views. For example, device rotation or incoming calls on iOS, or window resizing on OS X. If you have your layout logic in the standard places, then your code accommodates these without any additional effort, and in the places your internal state changes, you can request such a layout explicitly.
To turn your question around: is there a significant benefit to not doing your layout in the standard way? Do you believe that this will be a performance issue? Have you measured it to see whether it is actually a performance issue?

Best practices when using drawRect

I have recently started creating my own controls and I seem to have a bit of trouble understanding how I should use drawRect.
Basically I have 3 Questions.
Is it a good idea to have conditional drawRect's? ie. different drawing code based on properties or instance variables.
What is the best method for animating changes to the drawRect's drawing? For example, a fuel gauge control with animated fill and un-fill.
And, finally, the examples I have seen for animating with drawRect tend to use timers, is that really a good method in practice? It seems like the heavier apps would have issues with that method.
I guess a 4th would be, is there, perhaps, a better place to do this kind of stuff?
Is it a good idea to have conditional drawRect's? ie. different drawing code based on properties or instance variables.
Sure, why not? If your drawRect: method becomes unwieldy, you could split it into multiple methods that you then call from drawRect: depending on the properties of your view. E.g. you could have methods like drawBackground, drawTitle, etc.
What is the best method for animating changes to the drawRect's drawing? For example, a fuel gauge control with animated fill and un-fill.
That depends. For very small views, you could call setNeedsDisplay from a timer, but for larger views, you'll often run into performance issues with this approach.
Animating changes is often better done by compositing your view out of multiple subviews or layers that can be animated with Core Animation (or the simplified UIView animation methods).

Looking for good guidelines on how to manage code for large UIViewController classes

I've been working on my first XCode/iOS project and so far it's been an enjoyable experience. Currently, I am working on a Nib file that acts as a primary display for other views. Within this Nib file, I have a primary UIView and next to it I am designing a series of seven other views. At runtime I swap these seven views in and out when necessary, within a container UIVie, located on my primary UIView.
Across my 8 total views that I'm designing in IB, I have a large amount of buttons, images and other objects that need to be linked to IBOutlets. As this project is getting bigger, it would helpful if I could split my class across multiple code files.
Using categories is the solution, however, I've hit an annoyance-- when I tried to create an IBOutlet in one of my category headers, the XCode compiler keeps giving me errors and warnings about ivars and outlets. In my Nib I have a large number of objects that need outlets and I'd prefer to not have to define all of them in one, huge code file if that's possible.
However, I understand that I have to work within my limitations, so my question is a bit different than asking how to add an IBOutlet to a category. Instead, I'd like to know what are the best practices for splitting up a large UIViewController class across multiple code files? What are the limitations of objective-c and what is the best way to structure your code when working with interface design?
My code is not quite yet unwieldy, but I'd really like to start restructuring it so that it will be much more manageable when it consists of 100's of methods and 1,000's of lines of code.
Any pointers would be helpful. Thank you!
You can create one NIB that contains several controller objects, each managing the relevant views, and that will help to keep your code more manageable. The downside is that your memory footprint is larger loading a large NIB.
To achieve this, define the controllers in separate classes with relevant IBOutlets, and then drag the NSObject from the objects tray (where the UILabel, UIButton etc... are) into IB. Then for each object, define its class to the the correct controller, and you will have access to all the correct outlets and actions. You can then hook the controllers into a single UIViewController to control how they interact with each other.
The preferred way though, would be separate NIbs for separate controllers, and to have them all as UIViewController subclasses. If you move to iOS5 they have superseded NIBs in IB with Storyboards. These allow you to have separate UIViewControllers in a single IB file, however they are more efficient in memory usage as they don't keep the whole object tree in memory.
This is a pretty loaded question. But, in my experience, I've found that IB causes more headaches for me than it's worth in complicated situations such as this. I recommend just forgetting about IB for this scenario and just create your views in code. IB is really supposed to alleviate some of the more mundane tasks of layout, style, etc.
I recommend that all of your views be placed in their own project files as this has paid off for me...nothing more painful than scrolling through 1000's of lines of code to find what you need...and worse yet, using that dreadful code collapse widget in the gutter.

Working with many interface elements in Cocoa

My app requires an interface that has many buttons, text fields and matrixes. And they need to change from time to time. Right now I do this by having all elements in IB already and hiding/showing/moving them when needed. What would others recommend? Should I do that? Should I use an NSTabView? NSView? Should create the elements programatically? If so, what if I have an element that is already created that I need again without changes? It would be a waste of releasing it and creating it again.
Any help would be greatly appreciated.
In my opinion, it's better to create interfaces programmatically if you have to animate views around a lot. If it's just a matter of hiding/unhiding them, IB works great, but if you need re-layout or create unknown numbers of views dynamically it's not worth trying to make it all work with nib files.
As for general advice:
Create subclasses (from UIView or UIControl or one of their subclasses) for every kind of element you're going to use. It's tempting to piece together composite views from your UIViewController, but you'll really be much better off creating real classes.
Study the standard Cocoa view classes, and try to create similar API:s in your own controls and views.
Put as much data (sub-element positioning etc) into a plist, so that you can easily change it from one centralized place instead of having to dig around in the code.
If you are often creating several dozen short-lived views, it's worth keeping them in a pool and reusing them. But if it's just a few labels being added and removed intermittently I wouldn't worry too much about it. As usual: don't optimize too early.
Your current approach sounds fine. If you're showing/hiding them but otherwise they remain unchanged, why go through the trouble of creating them with code, when your XIB keeps a "freeze-dried" copy of exactly what you need already?
As long as you're keeping them within logical groups, you can just move/swap/show/hide the group's container (like NSBox or an NSView). If you have a LOT of logical groups, which aren't always shown every session, you can separate them out into their own XIBs and only load them when they're needed, to save launch time and memory.
If you use NSViewController, it's even better because you can make clean breaks for each logical group. Load the panel as the view and the view controller will keep outlets/actions and has a one-to-one relationship with a xib.