I seem to enjoy designing new UIViews and UIControls that implement their own -drawRect: method. This work well for me, especially when composed using UIViews in Interface Builder.
But composing them in Interface Builder is annoying because they just show up as boring plain rectangles.
It would be great if the views would actually render themselves as the built-in controls do.
Is there any way I can structure my project so that Interface Builder will render my custom views?
In order to do this, you actually have to create a plug-in for Interface Builder that uses your custom class. Once you create and install your plug-in, you will be able to drag and drop instances of your class (your view) onto another window/view/whatever just like any other control. To get started with creating IB Plug-Ins, please see the Interface Builder Plug-In Programming Guide. Also, I recommend taking a look at Aaron Hillegass's book, Cocoa Programming for Mac OS X. As well as being very well written and easy to understand, it has a chapter on creating your own IB Palette controls.
This is achievable by marking your UIView subclass with #IBDesignable. Once you do this, your custom views will render themselves in Interface Builder. You can even add parameters that can be configured by marking them as #IBInspectable. Here's a Swift example:
#IBDesignable class customView: UIView {
#IBInspectable var count: Int = 0
}
There's an article on NSHipster that provides more detail.
Related
I did this wonderful tutorial: Photoshop Tutorial For Developers: Creating a Custom UISlider and came away with two questions:
The example above makes every UISlider customized. Can you just subclass UISlider and tweak this code to make it it's own class that can be called upon?
Further, could you make this custom control available in the object explorer within Interface Builder, so you can just drag and drop it on your view like anything else in UIKit?
The docs for CocoaTouch classes will usually indicate if a class is not designed for sub-classing. In the case of UISlider, there's also some instructions for customizing appearance.
Custom Component in Interface Builder
To use a custom component within Interface Builder, its necessary to use the "object" component, and specify the class type to your custom class. Unfortunately this does not render any visual queues, like core UIKit classes.
Your own Plugin
It may be possible to provide a plugin to tweak Xcode, however this is no small undertaking as there are no official docs, so its necessary to search for open-source plugins on GitHub, etc and study the code. Even then, the plugin may break with subsequent version of Xcode.
Recommended Approach
Interface Builder is an amazing technology, however for more complex applications I recommend implementing views in code (override loadView in the VC). Here's some reasons:
Promotes better encapsulation and reuse. You can compose your own components (eg composition vs inheritance) using UIKit components, and provide a custom OO interface to them. Contrast this with lots of IB outlets in a view controller, which leads to poor reuse.
Fat-controllers don't really honor the MVC paradigm.
More flexible and fluent. Not all properties are exposed via IB, so in a complex case, its hard to know where to look. Is that setting in IB or code? Custom fonts, for example.
Xibs are really tricky to merge in a multi-person team.
I have been making applications for Mac with Objective-C for about a year now but due to not really understanding how to use classes properly I have only ever used the 'AppDelegate' files. I want to start using classes as soon as possible because from what I understand it's very bad practice to clump it in to one class. Basically, how do I have two windows, each controlled by it's own class. I understand how to make objects similar to NSString or something but don't understand how to have classes that control windows etc.
Thanks
Edit: Basically I want to know how to split up my application in to classes.
If I understand you correctly then you need to create individual controller classes sporting their own IBOutlets and IBActions and hook these up to your UI elements. To split up an existing application into smaller classes requires some knowledge of Object Oriented programming.
Alternatively, you might benefit from reading this (or a similar) book:
'Cocoa Programming for Mac OS X' by Aaron Hillegass.
Try looking for NSWindowController in the docs. You create a custom subclass of NSWindowController and a xib file for it. In the xib file, make sure you set the class on the File's Owner to your custom subclass, and make sure its window outlet is connected to the window in the xib. If all that sounds totally foreign, head for the books! =)
Then, in the code where you want to bring this window onto the screen, you create an instance of your custom subclass and associate it with the xib, like so:
MyCustomWindowController *controller = [[MyCustomWindowController alloc] initWithWindowNibName:#"myxib"]
[controller showWindow:self];
The xib loading system will hook up all your custom outlets and actions on the new controller, and you can show it or do other wonderful NSWindowController things.
Is there a simple way to expose, say, NSString or UIColor properties of a class such that they can be modified in interface builder?
This would be useful e.g. for adding color properties to a custom view (which are then used programmatically) so that they can be manipulated in Interface Builder as is appropriate.
In iOS 8 there are two new properties added, #IBInspectable and #IBDesignable. Here's a full write up.
http://www.weheartswift.com/make-awesome-ui-components-ios-8-using-swift-xcode-6/
This article from Cocoa with Love describes how to do what you want with Interface Builder Plug-ins for Mac development. Unfortunately, it is currently not possible to use IBPlugins with the iPhone SDK (note the Interface Builder Plug-in Programming Guide only appears in Mac OS X documentation, not iOS documentation).
There is no way to add a custom "non-IBOutlet" attribute but I suggest you to add a UILabel to make use of the text attribute of it, and of cause release that when the view is loaded.
So, I've been making iOS apps since the first iPod touch came out, but something has always flabbergasted me; why is the list of new Cocoa Touch classes restricted to subclasses of NSObject, UIView, and UITableView? I routinely make subclasses of UIImageView and UIViewController.
Am I "Doing It Wrong™?" Have I totally misunderstood MVC to the point where I make Controller classes where I shouldn't? What is the philosophical reasoning for requiring classes to never descend from a basic controller class?
What gives you the idea that you aren't supposed to subclass UIViewController? This is directly from the documentation for UIViewController:
In a typical iPhone application, there is usually at least one custom subclass of UIViewController and more often there are several.
The C of MVC is supposed to be the least re-usable part it's whole job is to mediate between M & V. If you find something that is in the C section of your code that you have to copy and paste into several subclasses of a given object or into several projects that code should be moved elsewhere.
If you are just basing this off the fact that there is not a nice popup menu item that says UIViewController, don't worry about it Apple has just not bothered to write a template file for that class yet.
Uhm... maybe it's just me, but I see a UIViewController subclass template when I choose new File.
UIViewController template http://files.me.com/aclark78/obnp83
Like #theMikeSwan says, there simply aren't GUI templates for this when you create a new class in Xcode GUI. But you can always create a new subclass whose parent is initially NSObject. After that, you just go to your code and change the parent class to whatever you like.
So... no, you are not doing it wrong in the sense that you rightly understand that often you want to subclass UIViewController; but yes, you are doing it wrong since you assume you shouldn't do this only because Xcode GUI does not support it :)
This is probably a simple problem for the high skilled Cocoa programmers, but I can't find how to control the graph in a separate window. I read carefully the Cocoa related books, go through many web notes,but I can't find a solution to my problem. The purpose is to use a dedicated window to draw the I=F(Vg) curves extracted by the GUI from a specific hardware. All the GUI and the hardware works fine ( thanks to the help provided by several members of stackoverflow) , but no way to send the parameters to the NSView to display the results.
So far, the GUI class is based on a NSObject, the graphic class is NSView.
Any idea, examples, links will be appreciated. Thank you so much.
Michael
So you have a controller class that receives data and owns a window? Just give it an outlet to the view.
This is the job of the controller in MVC: To pass data from the model (in this case, the hardware connection) to the views.