I've a fairly complex window that is backed by a controller class that is obviously growing to meet the needs of my view window. While I believe I am sticking to proper MVC I'm still having problems managing a fairly largish controller class.
How do you breakdown your objects? Maybe use Categories? For example, one category to handle the bottom part of the window, another category to handle my NSOutlineView, another category to handle a table, and so on and so forth?
Any ideas or suggestions are welcome.
It sounds like it's a complex window controller that's growing to unmanageable proportions? This is getting to be a more common issue because of applications which, like the iApps, do most of their work in a single window.
As of Leopard, the recommended way of breaking it down is to factor out each part of the window into its own NSViewController subclass. So, for example, you'd have a view controller for your outline view, and a view controller for each of your content views, etc.
Also, I'd like to second the use of #pragma marks to divide code files up into segments, and in addition to categories, I also like to use class extensions for private methods.
It's a simple answer, but the code folding feature of the Xcode IDE can be handy for focusing your attention on sections of a class. Another little thing that might help is going to View->Code Folding and turning on Focus Follows Selection. This makes it so the background color of the scope of your current selection is white while everything else is shades of gray.
Categories are ideal for this. Create a new file for each category, and group them by functionality, as you suggested.
I've tried using Categories in situations like this and I just end up confusing myself, wondering how in the world I'm calling that method when it's "obviously" not in the class I'm looking at.
I'd recommend liberal use of #pragma mark in your source code. Makes it super-easy to browse through all your methods.
Related
I would like to add a file to my project, who's sole purpose would be to hold an array. I would then #import this file wherever I need to add/get from the array.
My problem is that when I create a new file (I'm using Xcode 4), I'm not sure what type of template to choose, and then what subclass to choose.
My reason for doing all of this is because I have a SplitView-Based app, and one of the views has a textfield, where I am trying to output data. My problem is that whenever I switch to a different view and then switch back, only the most recent entry is there. I am not 100% why that is but I suspect it is because when I switch to a different view, the current view is forgotten about, along with the variables in it.
This is not a good way to do it. There are many ways to do what you want: prepareForSegue: if you are using storyboards, delegation, instantiating your viewcontroller in code and setting a property in the header-file..those are just a few ways.
The way you are proposing is a slippery slope to bad Objective-C code and is only going to cause you more headaches in the future. Take the time to learn to do it right.
Check out this to get you thinking in the right direction.
How you save your data doesn't appear to be your problem. Take a look at the MVC design pattern and how view controllers implement it. They often rely on a dataSource protocol, which links the data from a "Model" to your "View" in a logical way to achieve your intended purpose.
The view controller should then be able to assign a delegate (usually itself (self) to keep the view populated with the correct data, whether the view gets unloaded or not.
If your view controller doesn't refer to a data source or a corresponding protocol, it would still be worth your time to see how you might take advantage of that design pattern. It will pay off in the long run to know this.
Instead of saving variables to a text file, you should consider using NSUserdefaults instead.
But I don't think that's the real solution to your problem, just wanted you know that there are other ways than saving stuff to a text file.
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];
}
how should I call a class for a timeline custom view? My project's prefix is HM.
HMTimelineView
or
HMTimeline
Shouldn't I name any view class with the suffix View? But why is it NSButton but NSImage**View**?
To me, HMTimeline sounds like it could be a model object, so I would recommend the "View" suffix, but this is a decision you'll have to make based on what you think makes your code easier to understand.
There may be naming rules regarding this that I'm not aware of, but I believe NSButton isn't called NSButtonView because a button is intrinsically a client-visible interface object--it doesn't present a specific model object and is unlikely to be confused for a model object, so it's convenient to leave off the suffix.
if it is inherited from UIView
then
HMTimelineView will be best
if it is inherited from NSObject
then
HMTimeline will be best.
u have to understand that
whenever anyone go to use urCustom objects like HMTimelineView,HMTimeline then then they will automatically come to know
"oh it would be from View" -for HMTimelineView.
"oh it would be from NSObject" -for HMTimeline.
If you object is just a view, then you can put view on the end of it. The difference in NSButton and NSImageView are because an NSButton has a view, it itself is not a just a view, it is a button :P. NSImageView is the view of the image, it has an image, but is the object to view the image.
There also isn't a "correct" way. Using HMTimeline by comparison to HMTimelineView will not break your code. Its just a way to help a developer understand what the object is.
The “View” suffix is used inconsistently in Cocoa. Generally speaking, NSControl and its public subclasses don’t use “View”, but there are some inconsistencies (like NSText). In general, a view that presents content (which I assume a “timeline view” does) should have a “View” suffix.
This highly depends on your preferences, I guess, and understandability of the whole set of class names that make up your app. Much also depends on conventions that you will simply learn by looking at how other code is written, mostly the same SDK.
I think that HMTimelineView is far more understandable than HMTimeline. You also have to think that possibly you will have a HMTimeLineViewController, so HMTimeLime would be possibly ambiguous. Think of this, if you want: views, controllers, and models play a role in a design pattern (MVC) so that it is useful to identify them with a suffix. The same can be said for delegate classes, where the suffix is also usual.
About NSButton, it certainly derives from NSView, but its direct class is NSButton; so, in a sense, I think that its "control nature" prevails on the view nature, and NSButton is far more understandable then UIButtonView.
Hope this helps.
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.
I am currently trying to create a menu system for a game and cannot arrive at any really sound way to do it. There are several menu screens, each of them non-trivial, so that I would like to keep these as separate classes. The main problem I am having is passing control between these menu screens.
I tried building each of the screens as a singleton and call one screen from the other directly, ie. something like [[MainMenu instance] display] in Objective C. This is a bit messy, because (1) I have to write the singleton boilerplate code for each of the menu screens and (2) the classes get dependent on each other, sometimes I have to code around circular dependencies etc.
I thought about making the classes fully static to get around the instance management (which is a bit extra in this case, since there really is just one instance of each screen). But this also looks quite ugly, especially with Objective C having to “fake” class variables by declaring them static.
Then I thought about some “manager” class that would create the instances and pass the control around, but I am not sure introducing an extra class would solve the problem, especially if this class was to be named Manager :-)
I should note that I do have a working system, it just doesn’t feel very nice. By which I mean there is a bit of code duplication going on, if I am not careful the thing might hang, and so on. Any ideas? I am aware that this is underspecified, so that the discussion will probably be more of a brainstorming, but I am interested in the ideas anyway, even if they do not outright solve my problem.
Update: Thank You all for the ideas. What I did in the end:
I reworked the menu contents (buttons, graphics, etc.) to fit under one interface called ScreenView. This is a general interface that looks like this:
#protocol ScreenView
- (void) draw;
- (BOOL) handlesPoint: (CGPoint) p;
- (void) appearWithAnimation;
- (void) disappearWithAnimation;
- (BOOL) hasFinishedAnimating;
#optional
- (void) fingerDown;
- (void) fingerUp;
#end
Thanks to this protocol I was able to throw away all the specific menu screens and create a general menu screen that takes a list of subviews to display and handles all the presentation like drawing, transitions, events and such. This general menu screen does not get subclassed much, because most of the menu screens are happy simply displaying a list of subviews. This would be the V in MVC.
Then I also created a controller class that handles all the events for a certain menu screen. (Obviously the C in MVC.) The root controller class handles the instance management, transitions between menus and some other little things. Most of the menu screens get a customized subclass of the controller that handles the events from the buttons and other subviews.
The number of classes got up, but the code is much cleaner, does not repeat itself and is less prone to errors. The instance management is still not perfect, but I’m reasonably happy with the design. Once again, thank to all who answered.
One of the tricks I learned to decent design is always separate your data from your code. This will do WONDERS for your specific problem.
By this I mean that the menu items (strings) and relationships between the menus should be stored somewhere either in an array or a separate file (and read into an array).
You then use this array to instantiate all your menu classes.
Once you recode it to work this way (I've done this with menus), all your code will fall into place, you'll also factor out--90% of your menuing code (each menu will no longer be it's own class, just the same class instantiated with its own unique data.
The target of the menu items are stored in the "data" as well (as method pointers or class instances).
I think a MenuManager class would be the way to go. You'd have one Menu base class which all the menu screens derive from, and the manager would have a pointer to the currently active menu screen. It could also, for example, keep track of previous menu screens for easy use of back buttons on menu screens in arbitrary menu screen calls. Maybe just use a std::vector for that so you don't have to recreate the previous menu screens when going back (this would also prevent loss of entered information, like in an Options menu with an Advanced submenu).
Putting all the contents of the menus into a dictionary, dumping to a plist and reading each as necessary by the menu screens is likely the simplest route but in all honesty, you should consider taking a more MVC-centric approach to solving the problem. The screens should be for presentation of data not the storage of it. If you provide for a clean separation of the data from the views, the problem solves itself.