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

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.

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.

Do delegate methods inherit from method in protocol class?

In a category I got from a book, there is a protocol specified. It requires one method and declares that method in the category as well.
If I implement the protocol in another object (a table view cell), my understanding is that I MUST include the required method. However, other than the title of the method being the same as the one in the category, do I inherit any of the code from the category version? That code is meaningful because only after that code completes do I want to do something.
category: .m
#protocol DownloadHelperDelegate <NSObject>
-(void)didCompleteDownloadForURL:(NSString *)url withData:(NSMutableData *)data;
#end
- (void)didCompleteDownloadForURL:(NSString *)url withData:(NSMutableData *)data{
// doThis
// doThat
// readyToDoSomethingElsewhere
}
In tableviewCell: .h
#import "category.h";
#protocol category
.m
-(void)didCompleteDownloadForURL:url withData:data;
{
// Did doThis happen?
// Did doThat happen?
// If so, I want to do Something
}
Since the category is a category on UIImageView, it only adds methods to that class.
Since your class is derived from UITableViewCell and that does not derive, directly or indirectly, from UIImageView, it does not inherit an implementation of -didCompleteDownloadForURL:withData: from the category.
I'm guessing the category's method would not be an appropriate implementation of the protocol method, anyway. It has the same signature, but I suspect it has a different purpose. In particular, I suspect the category method's purpose is, at least in part, to forward the call along to a delegate which implements the protocol. So, it wouldn't make sense for the delegate itself to inherit that implementation.
It's just a coincidence that the category method and the protocol method have the same signature. In fact, I would suggest that the category method be changed to start with a unique prefix so that there's no chance that it collides with a method on UIImageView, which might be private to Apple or added in a future version of UIKit.

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

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.

Is it possible to dynamically implement a protocol in Objective-C?

I know that I can extend a class (for example a framework class) using categories, but is it possible to have a class for which you do not control the source code implement one of your custom protocols? I not only want to have it respond to certain messages if sent to an instance, but also, ideally, want objects of that class to return true on runtime type checks when querying for the protocol.
You can define a category that conforms to the protocol, so you'd do something like:
#interface UIWebView (MyGreatExtensions) <UITableViewDelegate>
#end
#implementation UIWebView (MyGreatExtensions)
- (CGFloat)tableView: (UITableView *)tableView heightForRowAtIndexPath: (NSIndexPath *)indexPath {
return 42.0;
}
// ...
#end
A small edge case to consider is that if someone else tries to do the same thing (e.g. a third-party framework also adds the protocol via a category) then you can't guarantee that your version will be used (and of course neither can they).
More on this approach from Mark Dalrymple.
I think this is possible. You can easily create dynamic proxies in Objective-C (this is how NSUndoManager does its magic) by overwriting NSObject's forwardInvocation: method, intercepting all non-recognized messages that an implementor of the protocol would respond to. I have never done this myself, so there might be a more elegant way to do this.
In addition, to fool the runtime checks into agreeing that your object does implement the protocol, you could override NSObject's class method conformsToProtocol: like so:
+ (BOOL)conformsToProtocol:(Protocol *)aProtocol {
if (aProtocol == #protocol(MyDynamicallyImplementedProtocol))
return YES;
return [super conformsToProtocol:aProtocol];
}
There might be more methods that you need to override, one example would be NSObject's instancesRespondToSelector: and the resolve*: methods. Examine the NSObject class reference to find out more.

If two different Categories having same method, then which one will be invoked by Objective C runtime system?

If two different Categories having same method, then which one will be invoked by objective C runtime system ??
for example:
#interface ClassA (MathOps)
-(void)CategoryMethod;
#end
#interface ClassA (MathOps1)
-(void)CategoryMethod;
#end
#implementation ClassA(MathOps1)
- (void) CategoryMethod{
NSLog(#"Inside Category Method 2");
}
#end
#implementation ClassA(MathOps)
- (void) CategoryMethod{
NSLog(#"Inside Category Method 1");
}
#end
Now if i am calling, [ObjClassA CategoryMethod];, Then which one called ? Why ?
It's undefined. It depends on which category gets loaded first by the runtime, are there's no documented order in which that happens.
Bottom line: don't do this. :)
As #Dave DeLong states, the behavior is undefined. One of the methods will "win", and there's just no way to know which one. If any other code depends on the loosing method, you'll find yourself debugging some potentially weird errors. Best to avoid the situation all together. This is a particular problem when implementing "obvious" helper methods. If those methods get added in a future framework version, your category will either override the new method in the class (if it's in the main class body) or may override the method if its added in a category. Eek.
Many Cocoa frameworks that provide categories for existing (e.g. Cocoa) classes follow a pattern whereby they prepend their class prefix to the method in order to minimize the chance of name collision. So, for example, you would create categories like:
#interface NSObject (MyCategory)
- (void)myprefix_categoryMethod;
#end