How to override a function that is part of a category's original class? - objective-c

for example let's say i have a class car with the following .h:
Car.h
#interface Car : Automobile
#property Engine * V6;
-(void)igniteEngine:(int) key;
-(void)StopEngine;
#end
and now I have a category Car(Test) with the .m file
Car(Test).m
#implementation Car(Test){
Oil * testingOil;
}
...
#end
and i want to override a function in the following way
-(void)igniteEngine:(int) key //inside test
{
[self applyTestingOil];
[(reference to original class) igniteEngine:key];
}
how would I go by doing this?
if there is a different way of approaching this problem that would also be helpful

Overriding a method in a category is not an option, as the behavior at runtime will be undefined: you have no way to know which of the base class or category implementation will be executed.
See Avoid Category Method Name Clashes.
If possible, the simplest way to do this is to subclass the base class, and override the method there.
Is subclassing is not an option, you can use method swizzling. This will exchange the method implementation with your own at runtime.
But as Mattt put it: "Swizzling is widely considered a voodoo technique", so I'd avoid it if I could.
If you think swizzling could solve your problem, and you're ready to "take the risk", take a look at JRSwizzle, which will handle most of the boilerplate for you.
Considering your ivar Oil * testingOil;, subclassing is again the only simple option. As rmaddy said in the comments, categories does not allow you to add ivars to the class. You'll need to use Associated Objects for this. And well... it's not pretty.

Related

Objective-C : Accessing fields in implementation

Is it possible to fields defined only in implementation but not in interface definition ?
#interface MyInterface .... #end --> dict not defined here!!!
#implementation MyInterface
...
NSDictionary *dict;
...
#end
In this case if somewhere I somehow accessed to this class, can I access to the dict or should I create a getter just like in Java ?
Edit after #Rob's answer
Thanks for the answer Rob, I wish I have the implementation of these interface and classes. Instead I am trying to bind two different libraries ( I know it is reallllly bad as architectural point of view but this is where I end up).
Basically, I am in react-native world. And we are using react-native-video as our player layer. But since AVPlayer does not support some subtitle types our head company sent us a library that needs a player instance and a view instance to draw subtitle on the view. I believe they will bind to events of the player and draw sub titles based on player states.
So react-native-video is in this github repo with the interface and implementation.
I find the UIView that includes the properties and casted it to the object itself RTCVideo in this case). But now I am stuck. I can go and change some stuff as per your suggestion in the "Development Pods" to be able to access but this is my last bullet :) I prefer to convince these two libraries in a friendly way :)
Yes, but the above syntax isn't what you want. The modern way to do this is with a class extension.
Your header file is the same:
#interface MyInterface
#end
But in your .m file, you create an extension by appending ():
#interface MyInterface ()
#property (nonatomic, readwrite) NSDictionary *dict;
#end
Now, inside your .m file, you can access self.dict normally, but outside of your .m file it won't appear available.
For full details, see Programming with Objective-C: Class Extensions Extend the Internal Implementation.
The syntax you've written actually creates a static (global) variable called dict that isn't tied to any instance.
It is possible to create raw instance variables using a {...} syntax, either on the extension or on the implementation, but this isn't used that often today, except for managing raw buffers that you don't want accessors for. The syntax is either:
#interface MyInterface () {
NSDictionary *_dict;
}
...
#end
or on the implementation:
#implementation MyInterface {
NSDictionary *_dict;
}
...
#end
But I recommend simple extensions with properties any time you can. And if you are considering creating an accessor for it, you definitely want to use #property and let the system do it for you.
If I understand your edits correctly, you're trying to read the internal ivars of an object that doesn't expose them with an accessor, correct? I believe specifically you want to access _player.
There's several common ways to do that. The key feature you want is Key-Value Coding.
The simplest approach for this problem is -valueForKey:
AVPlayer *player = [view valueForKey:#"player"];
The first thing -valueForKey: looks for is _<key>, and if it's just an object pointer (as in this case), it just returns it.
(This can be broken if a class return false for +accessInstanceVariablesDirectly, but the default is true, and it's unusual to override this.)
Another very common approach is to just declare any methods you know exist as a category. (This won't work for _player, since it's not a method, but in case you need similar things.) Imagine you wanted to call the "private" method -removePlayerTimeObserver. In your .m file, just say you know about it using a category:
#interface RCTVideo (PrivateMethods)
- (void)removePlayerTimeObserver;
#end
And since you know about it, you can call it:
[video removePlayerTimeObserver];
If you're wrong, and that method doesn't really exist, then the program will crash. In Objective-C, almost all rules are advisory. You can break them if you want to. ObjC programmers tend to be big rule-followers because otherwise the program crashes and ObjC has very clear rules that are pretty easy to follow. It's not because the system forces us to.

what is (overrides) in objective c

I'm following a tutorial on how to create a popover in Iphone here
what is (overrides) this code:
#interface UIPopoverController (overrides)
+ (BOOL)_popoversDisabled;
#end
#implementation UIPopoverController (overrides)
+ (BOOL)_popoversDisabled
{
return NO;
}
#end
This is an objective-C category. A category is a way of providing extra methods on a class, and they're useful in the following situations:
Extending a library class with domain-specific functionality. ie providing some extra features that will be useful for your application. This works whether or not you have the source-code for that class. For example, you could implement an [NSString asCreditCard] method or [UIColor applicationThemeColor].
Categories are also invaluable for grouping related functionality in a complex class.
Objective-C categories have the restriction that you cannot define additional ivars, and thus ivar-backed properties, on a category, although you can easily work around this using associative references - a run-time feature allowing you to link an object to a given class.
Associative References
To 'fake' a property or ivar on a category class use the following:
Define a 'key' to reference the associated property.
static char const* const carNamekey = "com.myObject.aKey";
The key doesn't necessarily have to have a value, since its the memory address of the object that is actually used.
Now, Implement the properties:
- (void) setCar:(Car*)car
{
objc_setAssociatedObject(self, &carNamekey, car, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
- (Car*) car
{
return objc_getAssociatedObject(self, &carNamekey);
}
If you wish you can add an #property declaration on the interface definition for the category, as an invitation to users of the class to use property-style (ie class.property = xxx) syntax.
Class Extensions
Another feature that is very similar to Objective-C categories is the class extension. A class extension is defined in the implementation block for a class like so:
#interface MyClass()
Some people refer to these as 'empty categories', but this is not quite correct. Unlike a category, a class extension will allow you to define additional properties and ivars on a class, without using associative references. This is useful for making a readonly property, internally writable, and things like that.
There - now you probably know more about categories than a lot of folks :)
Jasper Blues' answer explains categories nicely, so I'll just add that you should avoid using categories to override methods in the class to which you're adding the category. The reason is that the order in which categories are added to a class is undefined, so you can't know for certain whether the class will get your version of a method or one defined in another category. If you need to override methods in a class, create a subclass and put your overrides there.
However, people sometimes use categories to organize the methods in a class definition. If that's the case here, the method(s) in the overrides category are probably meant to override methods in the superclass, which is fine.

overriding undeclared methods in subclass

I have a class with some methods neither declared in .h file nor in any category, I want to override these methods in the subclass to change the behavior slightly. I am thinking of simply redefining those methods in subclass. Is it a good idea? would it even work?
Ideally the subclass needs to know what the methods are if it wants to override the method and still call super.
One way of doing this is by having a separate header file which both the super class and subclass implementations both import.
// MyClass_protected.h
- (void)someMethodThatYouWantSubclassesToBeAbleToOverride;
Then
// MyClass.m
#import "MyClass_protected.h"
// MySubClass.m
#import "MyClass_protected.h"
It'll 'work' in that the compiler allows it. The class that defines these methods probably assumes they do particular things when called, which your implementation needs to respect when overriding them to avoid introducing bugs in the use of the class's interface.
You can override private methods in a base class but the problem is that you can't call [super someMethod]. If you wish to completely replace the original method then this isn't an issue.
Otherwise you need to let the derived class know about the methods in the parent class.

How do I define a category that adds methods to classes which implement a particular protocol?

I want to add some methods to subclasses of NSManagedObject that implement the SOManagedObject protocol. I've tried defining it like this:
#interface NSManagedObject <SOManagedObject> (MyExtensionMethods)
...
#end
...but that doesn't seem to be valid. How do I define a category that adds methods to classes which implement a particular protocol?
Defining such a category on all such classes in general is not easily solvable. But your actual problem seems simpler: How does one add a category method to NSManagedObject for use only with subclasses that implement <SOManagedObject>? This is solvable.
What you want to do is add the method to NSManagedObject, then check that the instance you're working with can handle the messages you want to send it from <SOManagedObject>.
Let us suppose that we are given:
/* SOManagedObject.h */
#protocol SOManagedObject
- (void)frobble_so;
- (void)bobble_so;
#end
Now let's add a category method to all NSManagedObject subclasses that implement SOManagedObject:
/* NSManagedObject+SOConvenience.h */
#interface NSManagedObject (SOConvience)
/* Frobbles and bobbles - no effect on non-<SOManagedObject>-conforming
* instances. */
- (void)frobbleAndBobble_so;
#end
To do so, we implement the method like so:
/* NSManagedObject+SOConvenience.m */
#implementation NSManagedObject (SOConvenience)
- (void)frobbleAndBobble_so
{
if (![self conformsToProtocol:#protocol(SOManagedObject)]) return;
NSLog(#"%s: Thunderbirds are GO! Let's frobble and bobble!", __func__);
[self frobble_so];
[self bobble_so];
}
#end
You could optionally assert to ensure you are not sending the method to the wrong objects, or you could use respondsToSelector: instead of checking for protocol conformance. Whatever floats your boat, but this general tack should take you where you want to go.
I don't think it is possible. A similar question to this was answered earlier:
Defining categories for protocols in Objective-C?
Edit: I misread the question; I don't think it's possible to do what you're trying to do without messing with the Objective-C runtime. See Dave's comment below for why my answer is incorrect.
You should be able to do this if you swap the protocol and category notation like so:
#interface NSManagedObject (MyExtensionMethods) <SOManagedObject>
...
#end
Adam Sharp posted a solution that worked for me.
It involves 3 steps:
Defining the methods you want to add as #optional on a protocol.
Making the objects you want to extend conform to that protocol.
Copying those methods into those objects at runtime.
Check out the link for the full details.

In Objective-C, do I redirect a containing instance's method without subclassing it?

In Objective-C, how do you rewire a class's instance method to call a method in another class?
Say a UIView class A contains another UIView class called childA. I want it so that when childA's drawRect is called, a method in class A is invoked without having to subclass childA and do the desired call in its drawRect there. How can this be achieved?
Also, how do I supply a method to childA's draw class dynamically? I know this is probably not a good practice but it would be useful for testing purposes.
To answer your first question about rewiring methods:
You don't want to be doing this on general principle, since it kinda defeats the whole purpose of object-oriented design, but for testing purposes, it can be useful. As long as you're on Leopard, it's not especially difficult, either.
Take a look at the Objective-C 2.0 Runtime Reference, which contains the keys to the kingdom, as it were. Look at the functions class_getInstanceMethod, method_getImplementation, method_getTypeEncoding, and class_addMethod which, in combination, let you change the methods of a class at runtime.
If you're just swizzling one selector for another, method_exchangeImplementations is a useful shortcut.
To answer your second question about supplying a method dynamically, that's as simple as passing a SEL to a method and then calling -performSelector:withObject::
#interface MyView : NSView {
SEL drawingSelector;
id drawingDelegate;
}
#property SEL drawingSelector;
#property id drawingDelegate;
#end
#implementation MyView
- (void)drawRect:(NSRect)rect {
[self.drawingDelegate performSelector:drawingSelector withObject:[NSValue valueWithRect:rect]];
}
#end
For the first issue you raise, it seems like you would set up UIView A as a delegate object of childA and the other UIViews - then they could use delegate methods to call the extra drawing features you wanted in A.
Either that or have each child ask for the superview and if it is of type "A" call the method you are interested in.