Let's say, for instance, that I want to place some code in the viewDidAppear: method for all UIViewController (including subclasses) objects from my project:
-(void)viewDidAppear:(BOOL)animated{
[super viewDidAppear:animated];
NSLog(#"Did show: %#:%#", NSStringFromClass([self class]), self.title);
}
Is there a way to do this without using categories (for UIViewController), and without having to manually change the superclass of all my view controllers to a new class that defines this method?
The reason I don't want to use a category is because I might want to define methods and call their super implementation.
For instance, is it possible to automatically add an intermediary class between UIViewController and whatever other classes inherit from UIViewController at runtime (or using preprocessor macros)?
The common way to achieve this is called method swizzling. Mike Ash has an article of how to do this correctly.
The general idea is to exchange the original implementation of an Objective-C method. Usually you call through to the original implementation from the inserted function/method.
Here's a quote from Mike's article:
The Obligatory Warning
Overriding methods on classes you don't own is a dangerous business. Your override could cause problems by breaking the assumptions of the class in question. Avoid it if it's at all possible. If you must do it, code your override with extreme care.
Related
I have a framework in obj-c which is included by other modules. I want to allow the modules which are going to include it to provide their own implementation for certain methods.
I can't use subclassing because of some issues around serializing these objects. So, have to rely on using category.
I am thinking of declaring a method/selector for the object and then modules will define the category and implement that method. Something like below:
Framework will declare interface like below:
#interface framework:NSObject
- (void)methodToBeImplemented;
#end
#implementation framework()
- (void)invokeClientDefinedMethod
{
if([self respondsToSelector:#(methodToBeImplemented)]) {
[self methodToBeImplemented];
}
}
//Module-1 will link against this framework and define the category
#implementation framework(methodImplementor)
- (void)methodToBeImplemented
{
...
}
#end
Can I choose not to implement methodToBeImplemented at all in framework and implementation to be provided by the modules themselves.
I know that I can do it performSelector route. But I cringe to do so because I want to send pointers to my method which is not really possible with performSelector
If possible, I would highly recommend using a delegate pattern for your object so that callers can pass a delegate that conforms to a protocol rather than directly extending the class. That's the normal way to implement this kind of system. But if there's a particular reason a delegate is not possible, you can build what you're describing.
What you're looking for is an informal protocol, which is how almost all protocols were handled prior to the introduction of #optional.
What you want to do is define a category on your class in your public header:
#interface Framework (OverridePoints)
- (void)methodToBeImplemented
#end
This declares that such a method may exist, but it does not enforce its actually being implemented. The key is having a name in the parentheses. This can be anything (I used "OverridePoints" here), but it cannot be empty since that would be an extension instead of a category.
Once you have that, then the rest of your ideas work. You can test for respondsToSelector:, and the consumer can implement (or not implement) the category methods just as you describe.
The one danger is that there is nothing preventing multiple parts of the program implementing the same method in categories. That is undefined behavior, but the compiler will not catch it for you.
This has a sort of Responder Chain feel to it, but the difference there is, the responder chain is a defined operation on views and view controllers specifically.
Well, I need to pass along a method call through several unrelated classes, and being fairly new to Objective-C, i'm not sure if it would be a hack to define a protocol, and then implement that protocol on every class that the call needs to pass through.
For example...
ClassA is the delegate to ClassB.
ClassB is the delegate to ClassC
... hence the 'responder chain' feel.
Does this make sense for the code to pass along a call from C to B to A.
I assume at some point, when the chain gets too long, you'd probably recommend a notification technique instead, but I don't know what that recommended length might be.
#protocol DidSomething
-(void)userDidSomething:(NSString*)something
#end
ClassA <DidSomething>
-(void)userDidSomething:(NSString*)something
{
NSLog(#"The user did something %#",something);
}
ClassB <DidSomething>
-(void)userDidSomething:(NSString*)something
{
[self.delegate userDidSomething:something];
}
ClassC <DidSomething>
-(void)thatWasInteresting
{
[self.delegate userDidSomething:#"Cool"];
}
Nope. Nothing wrong with that. Save for the potential complexity.
You could define it as a protocol, if you want. Or you could define it as a common abstract superclass (if possible).
Protocols are generally the way to go these days and using #optional requires the use of a respondsToSelector: test (or conformsToProtocol:).
All in all, though, you should be very careful about the use of such a pattern. Specifically, it implies a lot about the architecture of your application and, thus, you want to make sure the architecture is sound.
Another alternative is using NSNotificationCenter to post NSNotifications. Object can add themselves as observers. Depending on your needs, this might be a good alternative to passing a message through a chain of delegate.
It is especially useful if more than one object needs to respond to a message.
I was just understanding the method swizzling done in obj c Method Swizzling and dangers of using method swizzling and couldn't help but draw a comparison between doing method swizzling and overwriting method implementation using categories.
They both help override the functionality of the predefined framework methods.
So is there any difference between the two or they can be used interchangeably?
The main difference is that Objective C prevents you from invoking the original implementation from a category override. This is because Objective-C's super invocations start from the super-class, while categories override methods on the same class level.
Method swizzling, on the other hand, lets you keep a reference to the original implementation as well, so that you could call it from inside your implementation. For example, in the article at your first link the author writes this:
- (void) logged_viewDidAppear:(BOOL)animated {
[self logged_viewDidAppear:animated];
NSLog(#"logged view did appear for %#", [self class]);
}
The second line makes a call to logged_viewDidAppear: method, which looks like an unconditional call to itself that should cause infinite recursion. However, this is not what happens: after swizzling, this call gets transformed into a call to the original viewDidAppear: because of the way method swizzling works.
In contrast, overriding a method from a category does not give you access to the logic of the method that you are overriding. It lets you replace the logic, but it does not let you extend it.
extension UIViewController{
public func myViewDidLoad(){
self.viewDidLoad()
//but you need to call this method everywhere replacing
}
//you cant do this
public func viewDidLoad(){
self.viewDidLoad()
//my code
}
}
Categories or extension let you do these:
Add computed properties and computed type properties
Define instance methods and type methods
Provide new initializers
Define subscripts
Define and use new nested types
Make an existing type conform to a protocol
(from Apple)
They don't let you extend original method of the same class that you are extending and if you try like the above code method signature conflict pops up.
You might want to check this website to get the concept diagrammatically. I really loved it.
http://matteogobbi.github.io/blog/2014/12/15/extending-methods-in-a-category-by-method-swizzling/
Make sure to check this awesome article for good implementation detail:
http://nshipster.com/method-swizzling/
I guess this is solved by writing a #protocol.
But I'm hungry for knowledge. Is there some flag or other way to require subclasses to override specific methods and not call super? Like the opposite of NS_REQUIRES_SUPER / objc_requires_super?
I do that in code not using any flags.
- I add assertion in the method of the super class that needs to be overridden in case this method is get called
Here I have a class that have a method fetchUserData that should be overridden by the child class
- (void)fetchUserData
{
NSString *descrip = [NSString stringWithFormat:#"child implementation for method:%# : %#",NSStringFromSelector(_cmd), NSStringFromClass([self class])
NSAssert(NO, descrip);
}
If I understand this right you're essentially asking how to make an abstract class... forcing subclasses to implement methods.
Check out : Creating an abstract class in Objective-C
In short, have the method throw an exception.
There are some things here that should be useful.
Specifically subclassResponsibility:
EDIT: Good point in the comments - GNUStep != Foundation. In other words, the methods on the page I linked to should be used with caution. However, I've personally used subclassResponsibility: and it works.
I have class called ViewController. How to make this class is a sub-class of "metaiosdkViewController" and "JWslideViewController". Help me with syntax.
i have written like this
#interface ViewController : MetaioSDKViewController,JWslideViewController
but this giving me error
objective-c doesn't support multiple inheritance,but if you want to add some extra behaviour you can achieve it through delegates..
yes objective-c doesnt support multiple inheritance but you can give one parent so
#interface ViewController : MetaioSDKViewController
and
#interface MetaioSDKViewController : JWslideViewController
this is just an idea I know you can implement well as per your need
What is it that you want to achieve with multiple inheritance?
Do you want to override methods from each of these super classes?
Note that objective c provides 2 mechanisms for extensibility:
1) Implementing a Protocol and make your object the delegate:
#interface ViewController : <MetaioSDKViewController,JWslideViewController>
This enforces ViewController to implement certain methods as defined in contract by 2 delegates, and at some point in processing, they get called. If you don't implement them, they may simply not be called but you may not get desired functionality.
Example: UITableViewDataSource protocol that defines many methods that UITableViewController subclass implements. cellForRowAtindexPath is very famous example of a delegate method that your own table view subclass must implement to draw your own custom cells.
Note that this is not the type of extensibility that subclasses provide in general sense. Your class does not extend any functionality here. Rather it becomes what it says - a delegate - someone who is assigned to do some task. Like you do:
yourTableView.delegate = self; //tell self to be the delegate of yourTableview
Library code does it's stuff and in some point in processing it calls [delegate someMethod]. If your own class implements it, it calls it, otherwise delegate will be nil, and it may just be NO-OP and you don't get desired functionality. Again, this is implementation-dependent. Maybe the protocol defines that the method is compulsory, in which case your class MUST implement this method in order to compile.
2) Implement a category:
This is sort of a shortcut way to extend library classes. They act like an extra stub which, when your code runs, attaches itself to the already existing memory layout of the library objects and provides extra functionality.
You can define a category on any of the in-built classes as well. In fact that is the primary objective it is used for. For example, here is an NSString category which provides HTML conversion. There are hundreds of categories implemented as open source and they provide enormous benefits where library code falls short. Discussing their suitability in entirety is however out of scope for this discussion.
One thing to note however is: You do not override anything using a category. Rather you are supplying something in extra. For example if you want some custom drawing across all your app views, you can define a category on UIView in your project and then all your views could simply include the category header file. You don't even have to inherit from this category, you simply inherit from the base type.
e.g. in the NSString category example above, you do not have to define your NSString to be of type NSString+HTML. Instead you just include the responsible NSString+HTML.h file wherever you want those extra methods like stringByConvertingHTMLToPlainText and so on. The changes remain limited to your project - to the files where you include this category.
Categories do not provide for extra data members - and that is something that only inheritance can provide. Yet, multiple inheritance among viewcontrollers is something you should definitely reconsider hundred times - you will see that what you are looking for is not multiple inheritance.