IOS - The correct way for using #import classes - objective-c

I am writing a test project to learn to write everything in code. I want to do this way so that I can better understand what the Elements in Storyboard do for me behind the scene's
In my project I have several UIViewControllers which share the same UI elements. For Example I have a UITool bar at the top of the screen with several buttons in it.
Now I want to put that UIToolbar in a separate class so that I do not have to write it all out or copy n paste it in every controller.
Now I know I can achieve this by doing this:
#import "General_Add_ons.h" //the UIToolbar is properly set up in this file
#interface FirstViewController : General_Add_ons
and then I just use [self topToolBar]; //topToolBar is the name of the toolbar
Now I just want to clarify is this the best and or only way to this?
Somehow I feel I should be able to do this:
General_Add_ons *gao = [[General_Add_ons alloc] init];
[gao topToolbar];
Am I thinking about this the wrong way? The first way seems to be limiting in case I have multiple external classes.
Thanks in advance.

Your approach seem correct. If you have several UIViewController instances that need the same UI elements or other controller code, you can put those elements in a UIViewController subclass. In your case, I believe the class General_Add_ons is the UIViewController from which your subclasses will inherit.
This class (your General_add_ons) should have a property for the reusable toolbar, e.g.
#property (nonatomic, strong) UIToolbar *toolbar;
As an aside, class names in Cocoa, by convention are: prefix+capitalized words without underscores. Apple has a great reference on naming conventions.
EDIT
For clarification, you can subclass your custom subclass as many times as you need. For example in my code, I have a class CCFViewController that encapsulates common properties and behaviors that I want all of my view controllers to have. In the project, then, all of the view controllers inherit from that parent controller. Similarly, your toolbar will live in the superclass and the other controllers inherit from it.

I am not 100% sure but i think you should try it this way:
General_Add_ons *gao = [[General_Add_ons alloc] init];
[gao.topToolbar anypossiblemethodcall];

Related

Setting a "grandparent" class in Objective C

I'm creating multiple different UI subclasses which can be created using JSContext, and I'd like them all to inherit a certain set of methods.
The classes vary from NSButton to NSTextView. It would be nice to have a single subclass act as NSView parent class, but I can't figure out if this is possible — or how to begin searching.
For example:
#interface CustomButtonClass : NSButton
I'm looking for a way to make NSButton inherit from a custom NSView subclass.
Is there a way to go around this, or do I need to create multiple intermediate classes?
The answer was super obvious, but coming from different languages, I struggled to make the connection. Thanks to all the comments, it was super easy to figure out.
Rather than trying to insert an intermediate class somewhere in the inheritance tree, you can create a category for NSView. Categories can also include all the required protocols.
For example, in my case, I wanted to expose multiple NSView methods to JSContext, and create some of my own, which would work on any NSView-derived object.
#protocol JSInterfaceExports <JSExport>
// Anything you want to expose to JS
- (void)customMethod;
// You can also expose all the common NSView properties
// and methods to JS in this protocol
#property (nonatomic) NSRect frame;
- (void)removeFromSuperview;
#end
#interface NSView (JSInterface)
// Any custom methods and properties
- (void)customMethod;
#end
Include this file on any NSView subclass, make them comply to <JSInterfaceExports>, and you are set.

Getting NSTextField Value from another Class

I have a class called TextFieldMagic which handles the NSTextField manipulations, animation,validation etc.
I want to get the NSTextField instance from tne TextFieldMagic class in my AppDelegate. I tried the following and I couldnt get it working. I'm just getting (null)
- (IBAction)testHide:(id)sender {
TextFieldMagic *textFieldMagic = [[TextFieldMagic alloc] init];
NSLog(#"%#",[textFieldMagic.textField stringValue]);
}
Of course, I could create an IBOutlet for NSTextField in my AppDelegate to get this working, but I want to understand how to do it w/o creating an IBOutlet in AppDelegate.
That's not the correct approach. With MVC, which is the design pattern adopted with Cocoa apps, the NSTextField is part of the View and should be used exclusively by the Controller in order to populate the Model.
In other words you need to expose some or all of the Model data for other classes to use, and you should not be attempting to use the same View from multiple Controllers.

Category declaration in *.m file affects whole app

I implemented the following category for UINavigationController inside of one *.m file:
#interface UINavigationController (ConfirmPop) <UINavigationBarDelegate>
#end
#implementation UINavigationController (ConfirmPop)
- (BOOL)navigationBar:(UINavigationBar *)navigationBar shouldPopItem:(UINavigationItem *)item
{
...
return YES;
}
#end
I was trying to check some conditions before popping the current view controller, and it worked all right but I short noticed that that category affected all UINavigationControllers in my app. Why does that happen? I thought this would only happen if I declared it on a header file and if I imported somewhere - which is not the case.
Categories apply globally. There isn't a way to apply them selectively.
Categories are used to add new functionality to all instances of that class, especially when your code isn't responsible for creating instances of that class -- otherwise subclassing might be a better choice.
You could create your own instance of a UINavigationController with the desired behavior and only use it where you want that behavior. Or if that's somehow not possible, you could add property-like methods to the category that toggle the desired behavior on and off.

How to avoid duplicate code objective-c

I have a two different ways of representing data in my app: via UITableView or UIScrollView.
So I have 2 main classes: AppTableView: UITableView and AppScrollView: UIScrollView.
And I want to implement the same additions to both views. So I wrote two classes: SomeAdditionsTableView: UITableView and SomeAdditionsScrollView: UIScrollView. The code of this classes is the same.
Main classes now looks like
AppTableView: SomeAdditionsTableView and AppScrollView: SomeAdditionsScrollView.
How to avoid this code duplicate? Thanks in advance.
Yeah this is a problem with the lack of multiple inheritance in Objective-c. I had the same problem when needing certain methods on a subclass of UIView and UIScrollView separately here: Subclassing UIView vs UIScrollView. There are 3 possible solutions I know of:
If you don't need to store any kind of instance variable, simply declare a category on UIScrollView and make sure to import that category into the two subclasses. This is the easiest solution, but least likely to work since you probably need to store state information if you're subclassing anyway.
Only create a subclass of UITableView and simply don't use it as a UITableView when you don't want a UITableView. You can technically just use a UITableView as a UIScrollView without invoking any of the tableView's methods. Of course, you're going to end up carrying around the 'weight' of a tableView (all of it's instance variables) but there no reason you have to use a UITableView as a UITableView and not just a UIScrollView.
Delegate as much of your code to a separate object to minimize code duplication. In each separate subclass carry an instance variable that is the method delegate and forward method calls to that delegate. Now here's where it gets fun. You can use protocols to declare the delegate methods in your subclass and override a special NSObject method: - (id) forwardingTargetForSelector:(SEL)aSelector to make sure those method calls get sent to the delegate. You use a category on the subclass that conforms to the protocol declared in the delegate class. This will expose all the methods of the delegate class in the subclass without requiring you to actually implement those methods in the subclass. When the runtime can't find the declared method in the subclass, it will call - (id) forwardingTargetForSelector:(SEL)aSelector, which you can use to return your delegate/forwarded class. This will prevent you from needing forward each individual method. Depending on what those method calls do, this may take a little more 'wiring', but it'll save you a lot of code writing in the end. It essentially 'mimics' multiple inheritance in objective-c using protocols. See my question/answer here for more details: https://stackoverflow.com/a/9419587/1147934.
Of the three, the last option tends to work the best for me. It takes a little work to get your head around but will significantly reduce code duplication. I also use it when I want to subclass without subclassing. The biggest requirement, though, is any class that you want to do this with will have to move it's method declarations out of it's interface into a separate protocol. But it's really not a big deal and the benefits of getting 'multiple inheritance like behavior' is great.
Also, there are times you may need the forwarded class to access instance variables in the forwarding class (the subclass). You can achieve this by using a delegate pattern whereby the forwarded class maintains a weak reference to the forwarding class in order to access those instance variables. For example, in your case, if you're trying to delegate methods that operate on a UIScrollView, those methods may need to be able to access that view. If those methods are stuck in a delegate class, they won't have direct access to the view's variables unless you give it to them. As usual with any delegate pattern, be very careful you don't create a retain cycle.
If your additions don't need any state of their own, you can make them a category on UIScrollView. Then, since a UITableView is a type of UIScrollView, you can use the category methods on one of those too.
If they do need to define new variables, then I would make it an independent class and have a MyTableView : UITableView subclass with a SomeAdditions property and, similarly, MyScrollView : UIScrollView.
You can achieve a lot by using protocols and "has_a"-relationships, instead of inheritance's "is_a"-relationships.
One very common pattern is delegate, but protocols are also useful for forwarding methods calls to encapsulated or wrapped objects.
in the following example to classes, that are not related to each other, share a common object, but it is also possible, that objects of the same kind use objects of different classes, that all implement a common protocol, so equal objects could do very different stuff.
#interface ClassA : NSObject
#property (strong) id<BrainProtocol> *brain
#end
##implementation ClassA
#synthezise brain;
-(void)theMethod
{
[brain theMethod];
}
#end
#interface ClassB : NSObject
#property (strong) id<BrainProtocol> *brain
#end
##implementation ClassB
#synthezise brain;
-(void)theMethod
{
[brain theMethod];
}
#end
ClassA *a = [[ClassA alloc] init];
ClassB *b = [[ClassB alloc] init];
//A object, that implements the BrainProtocol
Brain *brain = [[brain alloc] init];
[a setBrain:brain];
[b setBrain:brain];

Events for custom UIView

What's the best way for registering events for my UIView subclass, so that I can connect them to IBAction-s in interface builder?
Currently I've just got a standard UIView dropped onto my main view and I've set the class to "RadioDial" (my custom class). This displays the view fine, but I have no idea how to get events out of it.
Thanks
Please clarify: do you mean that you would like Interface Builder to offer your view controllers to wire up custom events that your view subclass will be emitting (much like the Button controls allow you to wire up Touch Inside, etc)?
If you need this type of functionality, you will need to use a generalized 'delegate' property on your View combined with a protocol.
#protocol RadioDialDelegate
-(void)dialValueChanged:(id)sender
#end
#interface RadioDial
{
id<RadioDialDelegate> radioDelegate;
}
#property (nonatomic, assign) IBOutlet id<RadioDialDelegate> radioDelegate;
This will allow the controller to wire up to the view (assuming it implements RadioDialDelegate) and receive any events that come out of the view. Alternatively, you can use an untyped delegate and in your View code, use a late bound call:
if([radioDelegate respondsToSelector:#selector(dialValueChanged:)]) {
[radioDelegate dialValueChanged:self];
}
Create a method in your view controller (if nothing else, you should have a RootViewController in you project). Let's say your method is
-(void) buttonClicked { code code code }
In the controller's header file (for example RootViewController.h) you then put:
-(IBAction) buttonClicked;
And in IB you right-click your button/radio dial/whatever. You will see a list of events and you can drag FROM the connector of the event you want your controller to receive, to the object in IB that represents the controler (probably First Responder). This depends on how your IB structure is set up, but it should be straightforward.
Another alternative is to learn how to create UIViews programatically, and forget about IB for the time being. Opinions are divided about whether it's better to learn to use IB at the outset, or whether it's better to learn how to do everything in code and save IB for later. In any case, it's necessary to learn both ways of setting up an interface at some point.