I have a class called BaseViewController that inherits from UIViewController and a class called BaseTableViewController that inherits from UITableViewController. Both of these classes have identical shared logic (i.e. rotation handling, helper methods, etc.). Right now the code is simply duplicated in both. I've considered just making a ViewControllerHelper class and exposing it as a public property, but I was wondering if there were any more elegant solutions.
if you don't need any shared ivars/properties, you could write an extension for UIViewController
I'd create a common class like BaseViewController with two initializers:
initWithList: (for table view) and initWithSomething: for simple UIViewController stuff. Each of those initializers would load separate xibs (one with the UITableView as main view, other - as simple UIView).
You'd have the same methods in every instance. And it would only need to implement UITableViewDelegate and UITableViewDataSource protocols.
Related
I've seen several Obj-C tutorials. The delegate classes all inherit from NSObject. For example, the applicationDidFinishLaunching delegate method, in some tutorials, it inherited from NSObject but NSApplication to implement it. The reason I don't think it should inherited from NSObject is that I didn't find any delegate protocol declaration in it, but I found that delegate protocol declaration in NSApplication. My Objective-C toy environment is GnuSep.
Here is some code:
#interface browserController : NSObject //here. inheriting from NSObject,but NSObject don'have any protocols declaration about applicationDidFinishLaunching.
{
NSBrowser *browser;
}
#end
#implementation browserController
- (void)menuAction:menuItem
{
..............................
}
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
NSWindow *win;
ActiveBrowserDelegate * abd;
WindowDelegate *wd;
NSRect wf = {{100, 100}, {600, 500}};
NSRect bf = {{10, 10}, {580, 350}};
.............................
}
It is called informal protocol (though GNUstep declared it anyway as GSAppDelegateProtocol for documentation purpose) NSApplication will simply check it at runtime if your delegate object will respond to the message, (using -respondsToSelector:) A delegate can be a view, a string, a proxy, anything as long as you make it responds to the selector. You don't need to make your delegate implement every method in such protocol since all verifications would be done at runtime. To make it looks cleaner you could just redeclare -applicationDidFinishLaunching: in #interface though you don't really need to, just make one in the #implementaiton is enough.
A delegate may inherit from anything appropriate. It is usually supposed to implement a certain protocol.
A protocol is a way of implementing a formal communication interface between two classes.
However, it is most unlikly that a delegate will inherit from its communication partner class.
With other words: Protocols are often used to overcome the unavailability of multiple inheritance. (Pretty much like interfaces in Java)
Example: A UIViewController subclass' instance controls a view that contains a UITableView. Rather than subclassing the UITableView for the implementation of its look or data, there are two delegates assigned to the table view object. One delegate serves as provider for custom layout (provides items such as the header view) and another (?) delegate provides the data that is being displayed.
Now, this delegate could be any object, inheriting from NSObject and implementing the two protocols. This object cold then be instanciated by the view controller and assigned to the table.
However, it is common practice that the view controller itself serves as delgate for the table(s) that it controls. That is a good pattern but strictly spoken not required. It could be any object.
Now the custom view contoller inherits from UITableViewController (which already implements the protocols and inherits from ViewController) and serves as delgate for the table view. The table view itself could be any subclass of UITableView. (Although this is a bad example here because subclassing UITableView is normally not advisable)
If the delegate does not need to inherit from any class and just implements the protocol, then it shold at least inherit from the cocoa base class NSObject. That ensures that it inherits all the usual capabilites and behaviour of any object. (init method, copy method, description method etc.) That may be required to work properly with other classes of the framework such as beeing used as an object within an NSArray, NSLog etc.
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];
In the Master-Detail Xcode template, where do I define a function such that it is globally accessible (by all UIViewControllers and their subclasses)?
One possibility: You can define a category on an UIViewController with the method. So any UIViewController now has this method too.
Another possibility: subclass a UIViewController and write you method there. And then subclass from this custom viewcontroller.
Edit:
Also, my MasterViewController is a subclass of the UITableViewController while the DetailViewController is a subclass of UIViewController. If I subclass them both to a custom UIViewController, the MasterViewController will lose its UITableViewController inheritance
You could subclass a UITableViewController and do the same thing as with the UIViewController and subclass from this.
The basic idea is to have a UITableViewController and a UIViewController as template.
You can create methods in the appDelegate class that you can access through all your app. For example, in your AppDelegate.h you have declared this method as follow:
-(void)myMethod;
In your AppDelegate.m, you define it as:
-(void)myMethod
{
NSLog(#"myMethod is getting called");
}
From any other classes (Master or Detail, etc.), you access myMethod by:
#import "AppDelegate.h"
AppDelegate *appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
[appDelegate myMethod];
make the class and the methods static. use the plus instead of minus e.g. +(void)methodName:param(ParamType *); .
Note, you can't instantiate a object of this class. It is like procedural programming. I usually use if I need the same but changing value in different objects and views. I don't a better way it works for me, though.
If you have some code that doesn't care what class of object calls it, it could probably be encapsulated into a function or subroutine instead of a method.
A method is a special type of function or subroutine that knows about an object and its class. A function or subroutine is like a global method that doesn't.
Added:
Objective C is a superset of the C programming language. So C functions and subroutines are the same in both languages. You can write one in a (or any) .c or .m file, and declare it in a .h file to be included wherever you want it used. Pass it parameters as needed and get a return value from functions, just like methods (except for being unrelated to any inherent class of object).
Added #2: But since you want your method to know about some NSStreams, then it should probably be a method of some Model class (MVC paradigm) containing those streams, and not truly global. Pass this Model object to any view controllers or other classes that need to access it.
Totally being a newbie by to objective C this perplexing question occurred to me .
So here it is,
Lets say say we have a viewcontroller that implements UITableViewDelegate.If we extends this viewcontroller does the child class inherits the UITableViewDelegate callback methods. So we can override the certain callbacks like cellForRowAtIndexPath etc. from the child class.
Have a good day
Yes, absolutely. The child class will also conform to the protocol. The implementation of these methods is taken in the superclass, or in the child class if it is redefined in it.
I have some functionality that I need in all my classes which derive from either UIView or UIImageView.
More specifically, I have gesture related code that both these classes need.
Currently my implementation is:
UIGestureView : UIView
UIGestureImageView : UIImageView
and make all classes derive from these.
These classes will again contain methods that the derived class will implement.
My problem is that the gesture handling code is duplicated in UIGestureView and in UIGestureImageView.
The natural thing here (as a c++ programmer) would be to use multiple inheritance
UIGestureView : UIView, GestureHandler
UIGestureImageView : UIImageView, GestureHandler
and let GestureHandler perform all the generic work but as far as I have understood this is not possible.
What is the objective-c way of doing this (without too many levels of child calling parent etc.)?
Just to stress, the problem is how to avoid implementing the same code twice, once in UIView (or its derived class) and again for UIImageView (or its derived class).
You could extend UIView with your gesture handling, and then every objects that inherits from UIView will have the methods you want. Not quite as awesome and subclassing, but would work on the global scope.
#interface UIView (GestureHandling)
- (void)didMoveAFinger:(UITouch*)touchOrWhatever;
// etc., etc.
#end
I have had similar issues with UIViewController and UITableViewController. I have a subclass of one that I want to share code with the subclass of the other. Yet there is no common place to inject that code if you want a subclass. The alternative is categories on the common superclass.
Check out categories: http://macdevelopertips.com/objective-c/objective-c-categories.html
You should try using protocols and delegation. They solve the multiple inheritance problem in objective-c.
#protocol MyProtocol <NSObject>
//Method declarations go here
#end
#protocol MyProtocol2 <NSObject>
//Method declarations go here
#end
#interface CustomView : UIView <MyProtocol, MyProtocol2>