How to implement Objective-C Category on several custom classes - objective-c

I have several subclasses of UIViewController that I want to use a single category to give them all a couple of methods. The thing is I only want my classes not the base UIViewController to have that categories methods.
Say I have:
PanelAViewController
PanelBViewController
...
That I want to implement and respond to a class:
PanelAnimations
-(void)animateIn;
-(void)animateOut;
I could use a protocol and insert the methods each time but they use the same methods and values, so wouldn't a category suit?
I am just not sure how to define the category for these custom classes.

Why you didn't consider subclassing, instead of using categories or protocols? Here here you can simply create an AbstractViewController class (which heritates from UIViewController) that defines the panel animations methods, and then derive your own concrete controllers (PanelAViewController, PanelBViewController, etc.) from the abstract one.
The abstract class will define the methods and eventually some stubs in the implementation (is up to you if you want that PanelA and PanelB should call super or not). This depends on the abstraction degree you want to give to the abstract class. See the code example below.
Sometimes it is not clear if it is better to use a protocol or subclass or delegate mechanism. Most of the times the boundary is not clear and the final decision is more dependent on the programmer preference than a "codified" architectural rule. Typically you use protocol when you want different objects to have a common behavior for certain tasks (e.g.: you have a complex set of entities and one of these entities should be used as a map annotation: in such case you must simply provide this specific entity the MKAnnotation protocol compatibility); delegate is mostly used when you want to extend a class without subclassing it or without given the final user the possibility to subclass it. In your case I think subclassing is the most appropriate choice as all classes are strictly part of the same class hierarchy, they share a common code (or common interface) and provide each a specialized implementation.
//
// AbstractViewController.h
//
#import
#interface AbstractViewController : UIViewController
-(void)doAnimate;
-(void)didAnimate;
#end
//
// AbstractViewController.m
//
#import "AbstractViewController.h"
#interface AbstractViewController ()
#end
#implementation AbstractViewController
-(void)doAnimate {
NSLog(#"Abstract do animate");
}
-(void)didAnimate {
NSLog(#"Abstract did animate");
}
//
// ConcreteViewController.h
//
#import "AbstractViewController.h"
#interface ConcreteViewController : AbstractViewController
#end
//
// ConcreteViewController.m
//
#import "ConcreteViewController.h"
#interface ConcreteViewController ()
#end
#implementation ConcreteViewController
-(void)doAnimate {
[super doAnimate];
NSLog(#"Subclass do animate");
}

Seems like your best bet would be to derive a custom class from UIViewController, call it say "MyUIViewControllerBase". Add your custom methods to that class, then derive the rest of your view controllers from it. No category needed and it solves your problem.

Suppose you have control over all your custom ViewControllers, the easiest way would be creating a subclass of NSViewController - like MyViewController - and subclass every other of your own ViewControllers from it. This way you would not even have to write a category for them. You could simply implement your wanted features within the MyViewController.
NSViewController
|
MyViewController -- implement your shared methods here
/ \
MyViewControllerA MyViewControllerB

Related

Simulate multiple inheritance in Objective-C

I have kind of an abstract class for my UIViewControllers (lets call it MyViewController) which overrides some basic methods like viewDidLoad or viewDidDisappear. In this methods some preparations are made, like setting up colors for the navigation bar, or preparing the bar buttons or something like that.
Now I want this basic behaviour for my UITableViewControllers also. So I made a new class that inherits UITableViewController (lets call it MyTableViewController) and copied 99% of the code from MyViewController.
In this image you see my current architecture. Listed are the overriden methods, in which other private methods are called. Again, MyViewController and MyTableViewController share 99% codebase (only difference is the name of the class and the super class).
For obvious reasons this is crap.
Is there an elegant solution to make MyTableViewController a subclass of both MyViewController and UITableViewController?
This is one suggestion, but I don't know how useful it is because I don't know your code.
You could implement a bunch of methods in a category for the UIViewcontroller class. For example:
#implementation UIViewController (myCategory)
- (void)setupColors;
...
#end
Since both MyViewcontroller and MyTableViewcontroller inherit from UIViewController, they would inherit your methods.
The only thing that you would copy in both implementation is the invocation of those functions, but the duplicate code would be much less.
- viewDidLoad...
{
[self setupColors];
}
Just be careful if you override methods, because you can't call [super ... ] on a category as you can in an inherited class
Shared implementation for your common methods could be done either with a category or with composition. Since a category can't be used to directly override existing interface (e.g. viewDidLoad:) you would need to put your private methods into the category and call them from your subclass overrides. Another option would be to put your shared implementation in a separate class (which might be a singleton) and compose an instance of that as a property of both MyViewController and MyTableViewController, e.g.:
#interface MyViewController : UIViewController
#property (nonatomic, strong) MyControllerStyler *controllerStyler;
#end
#implementation MyViewController
- (void)viewDidLoad {
[super viewDidLoad];
[controllerStyler viewDidLoad];
}
...etc...
The composed class's methods could reference the controller if needed, e.g.:
#interface MyControllerStyler : NSObject
- (void)viewDidLoadInController: (UIViewController *)controller;
...etc...
While a category seems perfectly fine for this example, if your extensions collectively represent a meaningful unit of your design (such as a collection of visual styling attributes) that might argue for a separate object (or objects) to better represent your intent.

Core Data: Where to put awakeFromFetch and awakeFromInsert?

I would like to override awakeFromFetch and awakeFromInsert.
As I leave the auto-generated NSManagedObject subclasses unchanged and put my custom code in categories, my question is:
Where do I put awakeFromFetch and awakeFromInsert in order that these methods get called correctly?
If your managed object subclass files are generated by Xcode, then you can also put the methods in a category of the managed object subclass, so that the code is not overwritten when you re-generate the class files in Xcode.
MyEntity+Extensions.h
#import "MyEntity.h"
#interface MyEntity (Extensions)
#end
MyEntity+Extensions.m
#import "MyEntity+Extensions.h"
#implementation MyEntity (Extensions)
- (void)awakeFromFetch
{
}
- (void)awakeFromInsert
{
}
#end
You might want to also consider mogenerator. It's a command-line tool which generates two classes for each of your managed objects and ensures your custom code is never overwritten when your model changes.
According to NSManagedObject class reference you should put it in a subclass - calling super implementation is necessary:
Important: Subclasses must invoke super’s implementation before performing their own initialization.
You have to implement them in your subclasses. If the code is the same for all of your subclasses and you want to avoid copy-pasting them into each of them, I would suggest to write one subclass of NSManagedObject that implements them and then make your specific entity-classes subclasses of that class.
//MyManagedObject.h
#interface MyManagedObject : NSManagedObject
//...
#end
//MyManagedObject.m
#implementation
- (void)awakeFromFetch
{
//...
}
- (void)awakeFromInsert
{
//...
}
#end
//OneOfMyEntities.h
#interface OneOfMyEntities : MyManagedObject
//...
I feel making an extension is better option than subclass because in subclass you need to change the parent class again n again whenever you generate... i hope thats the better approach....

Cocoa Singletons and Protocols

I want to define a protocol and create an easy, standard way to grab a 'default', shared implementation of said protocol - singleton style. Cocoa adhere's to the following pattern:
[NSUserDefaults standardUserDefaults]
[NSNotificationCenter defaultCenter]
but in both cases, they have #interfaces at the bottom of the object hierarchy. I'm struggling with how to do this using #protocols. I can obviously create a class that has empty or simple method implementations - but in reality, what I want is a #protocol at the bottom of the hierarchy. I've tried something like:
#protocol ConfigurationManager <NSObject>
//...
#interface ConfigurationManagerFactory : NSObject
+ (id<ConfigurationManager>)sharedConfiguration;
#end
// ...
id<ConfigurationManger> config = [ConfigurationManagerFactory sharedConfiguration];
[config ...];
and it works - but I'm always having to explain how to use this and why I did it this way. Is there a way to conform to Cocoa's syntax (calling convention) while still leveraging the value of #protocols?
As an aside, is there a reason why I wouldn't want to use #protocols like this? The implementing #interface can still leverage categories and alternate implementations, etc - just like how instantiating an NSString usually leaves you with a class extending NSString.
Here's an idea: create your protocol and a class with the same name with a factory method that returns you the default implementation of the protocol:
#protocol ConfigurationManager <NSObject> ...
#interface ConfigurationManager : NSObject <ConfigurationManager>
+(ConfigurationManager *) defaultConfigurationManager;
...
Other specialized implementations can then inherit from your base class.
The whole point of a protocol is that it specifies an interface without providing an implementation. If you want a default implementation, provide a class that implements your protocol, much as the NSObject class implements the NSObject protocol. Then clients can either subclass the class that you provide, or instantiate the class you provide and use the resulting object's implementation, as with your config object.

ObjC: must I specify the inheritance in the header file?

Common examples for a ObjC object are like this (for the header file):
#interface A: B {
int x;
int y;
}
#end
Is it possible to avoid the inheritance specification (i.e. B here) in the header file?
In my case, the framework A defines that class A and another (sub-)framework B defines the class B (which is a subclass of NSView). A links to B. In my application, I link to A and I don't need to know anything about B except that it is a subclass of NSView. And I want to avoid to link to B. But if B is in the header file, I think I cannot avoid it, that's why I was asking about how to avoid it.
No. You have to specify the superclass for any subclass. May I ask why you would want to do something like this?
Your application will need the code for B, therefore you must either link to B's framework, or compile the B framework into your A framework. Either way, you cannot use an instance of A without the code for B, and you must include B's header in your A header.
no.
you must often work around this with a class cluster, hold a private implementation, or create an object factory. then you can minimize the dependencies across modules.
you'll still ultimately need to link to the sub library at some stage if you intend to use it (e.g. create an instance of).
Update - Demonstrate Private Implementations
Private implementations can be entirely opaque. If you do expose them, here are two ways to implement private implementations which are visible to clients:
via protocol:
// MONDrawProtocol.h
// zero linkage required
// needs to be visible to adopt
// may be forwarded
#protocol MONDrawProtocol
- (void)drawView:(NSView *)view inRect:(NSRect)rect;
#end
// MONView.h
#protocol MONDrawProtocol;
#interface MONView : NSView
{
NSObject<MONDrawProtocol>* drawer;
}
#end
// MONView.m
#include "MONDrawProtocol.h"
#implementation MONView
- (void)drawRect:(NSRect)rect
{
[self.drawer drawView:self inRect:rect];
}
#end
via base:
// MONDrawer.h
// base needs to be visible to subclass and types which use MONDrawer
// may be forwarded
#interface MONDrawer : NSObject
- (void)drawView:(NSView *)view inRect:(NSRect)rect;
#end
// MONView.h
#class MONDrawer;
#interface MONView : NSView
{
MONDrawer * drawer;
}
#end
// MONView.m
#include "MONDrawer.h"
#implementation MONView
- (void)drawRect:(NSRect)rect
{
[self.drawer drawView:self inRect:rect];
}
#end
If you don't specify a superclass in the interface, then your class is a root class. This means it doesn't inherit from any other class, so it is responsible for providing its own implementation of the required methods (most of those defined by the NSObject class and protocol). Since this is not a simple task, it is highly encouraged that you inherit from some other class which provides these methods.
Yes you can, with that you will also lost default implementations of alloc, init, etc. Which makes you write your own alloc, init and other stuffs which was there in NSObject
can't you just include a mock version of the class you're inheriting from A's header itself? Not sure if that will cause problems, but it would allow you to clean up your linking requrirements a bit. B-new could then be a category of B'Original
I have one solution now. Instead of providing the class, I just provide a function like this:
NSView* allocA();
Internally in the framework A, A is a subclass of B.

Sharing common method implementation between classes implementing the same protocol in Objective C

I have a protocol.
MyProtocol.h:
#protocol MyProtocol
#property(nonatomic, retain) NSString* someString;
- (void)doesSomethingWithSomeString;
#end
And 2 classes that implement the same protocol. For some reason the 2 classes cannot inherit from the same base class. E.g. 1 of them might need to inherit from NSManagedObject (Core Data class in Apple's Cocoa framework) while the other shouldn't.
Class1.h:
#interface Class1: NSObject<MyProtocol> {
NSString* someString;
}
//Some method declarations
#end
Class1.m
#implementation Class1
#synthesize someString;
- (void)doesSomethingWithSomeString {
//don't use property here to focus on topic
return [[self someString] capitalizedString];
}
//Method definitions for methods declared in Class1
#end
Class2.h:
#interface Class2: SomeOtherClass<MyProtocol> {
NSString* someString;
}
//Some method declarations
#end
Class2.m
#implementation Class2
#synthesize someString;
// This is exactly the same as -doesSomethingWithSomeString in Class1.
- (void)doesSomethingWithSomeString {
//don't use property here to focus on topic
return [[self someString] capitalizedString];
}
//Method definitions for methods declared in Class2
#end
How can I avoid the duplication of -doesSomethingWithSomeString? (I guess I need something like categories for multiple classes).
Update:
There has been some suggestions of a helper class and delegating calls from Class1 and Class2 to it. It might be a good approach generally, especially if the methods are long.
In this case, I am looking at Class1 inheriting from NSObject and Class2 inheriting from NSManagedObject. The latter being a base class that Class2 has to subclass from, as a model/entity within the Apple Core Data framework.
So while delegation to a third class is one way to do this, there needs to be a lot of boilerplate delegation wrapper code for what amounts to many short 1-2 methods in the 3rd class. i.e. high boilerplate delegation code to actual code ration.
Another point is, as this is a model class, the common code mostly acts on ivars/properties, the delegation class will end up written almost like global C functions..
You can create a helper class an then use it from Class1 and Class2, and then only the call to the method on the helper class will be duplicated
This situation indicates that your Class1 and Class2 are not fully factored into classes that handle just one concern. The fact that you have a common implementation indicates that there should be a third class that provides that implementation and to which Class1 and Class2 can delegate that concern. In other words, this is a case for composition instead of inheritance.
Update
If it doesn't make sense to delegate to a class, don't forget that Objective-C is a superset of C. There's nothing stoping you from implementing a library of C functions that you can call from both classes to encapsulate the common behavior. If you're committed to conveniences like NSAssert et al., you can always implement them as class methods on a utility class or category on NSObject.
Personally I think this should be duplicated. You will likely need to customise one of them eventually and then you will be annoyed at all the work you did to prevent the duplication. Anything large can go into categories on the objects you are working with similar to whats going on inside capitalizedString.