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.
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.
Let's say I have this class and its subclass
#interface MySuperClass
- (void)open:(id)type value:(id)value;
- (void)openWebpage:(NSURL*)url;
#end
#interface MySubClass
- (void)openWebpage:(MyBookmarkClass*)bookmark;
#end
and that calling [someMySubclass openWebpage:someBookmark] calls [super open:BookmarkClass value:self.url]. And open:value calls [self openWebpage:url].
I realize this is very contrived, but I ran into a similar situation. My confusion is that even though [self openWebpage:url] is being called in MySuperClass, when it gets executed openWebpage: is being run in the context of the caller, MySubClass, which doesn't know what to do with an NSURL.
So my question is: is there any way to force something to be called in its original context? Or make it as though it calls super as many time as it can up the chain and find the method closest to the top?
There is only one context. There's a single object. Its class is MySubClass.
It is a mistake to have overridden the method with a different incompatible type. Don't do that. This is not C++ with function overloading. There's no dispatch based on the type of arguments.
The convention is to name methods by what they're acting on. So, you may have a method named -openWebpageURL: in MySuperClass and another method introduced in MySubClass named -openWebpageBookmark:. Note that MySubClass would still have a method named -openWebpageURL: inherited from MySuperClass.
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
I know of a couple of rules regarding Objective-C categories:
Category methods should not override existing methods (class or instance)
Two different categories implementing the same method for the same class will result in undefined behavior
I would like to know what happens when I override one of my own category methods in the same category. For example:
#interface NSView (MyExtensions)
- (void)foo; // NSView category implementation
#end
#interface MyClass : NSView
{ }
#end
#interface MyClass (MyExtensions)
- (void)foo; // MyClass category implementation
#end
With these interfaces defined, which method will be executed when I run the following code?
MyClass * instance = [[MyClass alloc] initWith...];
[instance foo];
[instance release];
Note: With my compiler, the MyClass implementation takes precedence, but I'm not sure if that is guaranteed to occur, or simply one specific flavor of undefined behavior.
To extend on drawnonward answer:
It's matter of hierarchy. Categories are really just a means of organizing source files. When compiled, all the methods of a class, including the ones defined in any category, end up in the same file.
Anything you could do in a regular class interface you can do in a category and anything you shouldn't do in a regular class interface you shouldn't do in a category.
So:
Category methods should not override
existing methods (class or instance)
You can use methods defined in the regular class interface to override inherited methods so you can override inherited methods in a category.
However, you would never try to have to two identical method definitions in the same ordinary interface so you should never have a method in a category that has the same name as a method in either the ordinary interface or another category on the same class. Since all the method definitions end up in the same compiled file, they would obviously collide.
Two different categories implementing
the same method results in undefined
behavior
That should be rewritten to say "Two different categories implementing the same method for the same class results in undefined behavior." Again, because all the methods for any one class end up in the same file, having two methods in the same class would obviously cause weirdness.
You can use categories to provide methods that override superclass methods because a class and its superclass are two distinct classes.
If your ever confused about whether a category will cause problem just ask yourself this: "Would the methods in the category work if I copied and pasted them all into the class' .h/.m files?" If the answer is "yes" then you're in the clear. If "no", then you've got problems.
Each method of each class has an implementation. A category adds or replaces a method for a specific class. That means the behavior you are seeing, where MyClass has one foo and NSView has another foo, is well defined. Any instance of MyClass will have a different foo than any instance of NSView that is not a MyClass, just as if foo had been defined in the main implementation and not a category. You should even be able to call [super foo] from MyClass to access the foo defined for NSView.
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.