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

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.

Related

why must i inherit NSobject instead of NSapplication to implement delegate method on GNUSTEP?

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.

Making a reference to an UIViewController from an ObjectiveC class

So my question is: How to make a reference to a UIViewController from an outside ObjectiveC class. I have a ViewController, and a UIScrollView on it, and a class that needs to override some methods, and eventually return said UIScrollView. So, i figured that the easiest way to do this is to type:
return destinationViewController.scrollView;
but i don't quite know how to make the destinationViewController reference. Help?
You should be able to pass it as a parameter to the outside class, otherwise you should rethink your class design. In worst case, you can store it in AppDelegate or some specialized singleton (or public static field (like static UIViewController *g_ViewController) in the worst worst case)...

How to avoid duplicate code objective-c

I have a two different ways of representing data in my app: via UITableView or UIScrollView.
So I have 2 main classes: AppTableView: UITableView and AppScrollView: UIScrollView.
And I want to implement the same additions to both views. So I wrote two classes: SomeAdditionsTableView: UITableView and SomeAdditionsScrollView: UIScrollView. The code of this classes is the same.
Main classes now looks like
AppTableView: SomeAdditionsTableView and AppScrollView: SomeAdditionsScrollView.
How to avoid this code duplicate? Thanks in advance.
Yeah this is a problem with the lack of multiple inheritance in Objective-c. I had the same problem when needing certain methods on a subclass of UIView and UIScrollView separately here: Subclassing UIView vs UIScrollView. There are 3 possible solutions I know of:
If you don't need to store any kind of instance variable, simply declare a category on UIScrollView and make sure to import that category into the two subclasses. This is the easiest solution, but least likely to work since you probably need to store state information if you're subclassing anyway.
Only create a subclass of UITableView and simply don't use it as a UITableView when you don't want a UITableView. You can technically just use a UITableView as a UIScrollView without invoking any of the tableView's methods. Of course, you're going to end up carrying around the 'weight' of a tableView (all of it's instance variables) but there no reason you have to use a UITableView as a UITableView and not just a UIScrollView.
Delegate as much of your code to a separate object to minimize code duplication. In each separate subclass carry an instance variable that is the method delegate and forward method calls to that delegate. Now here's where it gets fun. You can use protocols to declare the delegate methods in your subclass and override a special NSObject method: - (id) forwardingTargetForSelector:(SEL)aSelector to make sure those method calls get sent to the delegate. You use a category on the subclass that conforms to the protocol declared in the delegate class. This will expose all the methods of the delegate class in the subclass without requiring you to actually implement those methods in the subclass. When the runtime can't find the declared method in the subclass, it will call - (id) forwardingTargetForSelector:(SEL)aSelector, which you can use to return your delegate/forwarded class. This will prevent you from needing forward each individual method. Depending on what those method calls do, this may take a little more 'wiring', but it'll save you a lot of code writing in the end. It essentially 'mimics' multiple inheritance in objective-c using protocols. See my question/answer here for more details: https://stackoverflow.com/a/9419587/1147934.
Of the three, the last option tends to work the best for me. It takes a little work to get your head around but will significantly reduce code duplication. I also use it when I want to subclass without subclassing. The biggest requirement, though, is any class that you want to do this with will have to move it's method declarations out of it's interface into a separate protocol. But it's really not a big deal and the benefits of getting 'multiple inheritance like behavior' is great.
Also, there are times you may need the forwarded class to access instance variables in the forwarding class (the subclass). You can achieve this by using a delegate pattern whereby the forwarded class maintains a weak reference to the forwarding class in order to access those instance variables. For example, in your case, if you're trying to delegate methods that operate on a UIScrollView, those methods may need to be able to access that view. If those methods are stuck in a delegate class, they won't have direct access to the view's variables unless you give it to them. As usual with any delegate pattern, be very careful you don't create a retain cycle.
If your additions don't need any state of their own, you can make them a category on UIScrollView. Then, since a UITableView is a type of UIScrollView, you can use the category methods on one of those too.
If they do need to define new variables, then I would make it an independent class and have a MyTableView : UITableView subclass with a SomeAdditions property and, similarly, MyScrollView : UIScrollView.
You can achieve a lot by using protocols and "has_a"-relationships, instead of inheritance's "is_a"-relationships.
One very common pattern is delegate, but protocols are also useful for forwarding methods calls to encapsulated or wrapped objects.
in the following example to classes, that are not related to each other, share a common object, but it is also possible, that objects of the same kind use objects of different classes, that all implement a common protocol, so equal objects could do very different stuff.
#interface ClassA : NSObject
#property (strong) id<BrainProtocol> *brain
#end
##implementation ClassA
#synthezise brain;
-(void)theMethod
{
[brain theMethod];
}
#end
#interface ClassB : NSObject
#property (strong) id<BrainProtocol> *brain
#end
##implementation ClassB
#synthezise brain;
-(void)theMethod
{
[brain theMethod];
}
#end
ClassA *a = [[ClassA alloc] init];
ClassB *b = [[ClassB alloc] init];
//A object, that implements the BrainProtocol
Brain *brain = [[brain alloc] init];
[a setBrain:brain];
[b setBrain:brain];

Forcing a superclass to call its own method when sender subclass has the same signature

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.

i need help understanding a few methods in a view based application

when i create a new view based application a few methods in the implementation file (.h)
i do not understand their purpose and when i look into the developer center its kind of hard to understand because of how its explained.
what purpose do these methods have and what are they used for in plain english.
- (void)loadView
- (void)viewDidLoad
- (void)viewDidUnload
what im guessing the viewdidload is , is that when the view is loaded and anything between the braskets are executed first, but when there are other custom methods created (if that is the purpose of viewdidload) how does it know which method to execute? is the code executed from top to bottom? being that whatever method is listed first is executed?
also i have noticed the word super inside brackets along with other keywords. what is the purpose of super?
thank you!
Well, "super" means Super Class, or the parent class that your current class extends.
#interface MyViewController : UIViewController{}
In the code above, that you can find in some .h files, MyViewController extends UIViewController. So, all the time that you call "super" inside MyViewController, you are calling the UIViewController.
So, when you see the following structure, inside MyViewController...
- (void)viewDidLoad {
[super viewDidLoad];
.
.
.
.
.
}
... it means that when the method "viewDidLoad" is called, it will first call the method from it's super class, to after run it's own code.
if you let the whole viewDidLoad method commented, it means that the parent method will be called automatically, because you are not overwriting it like on the previous example.
To understand what all the methods (loadView, viewDidLoad, viewDidUnload), take a look at the UIViewController Class reference on Apple Developer Connection.
Cheers,
VFN
Your class is a derivative of the system class UIViewController (is a subclass, in Objective C lingo). [super someMethod] means - call this method for the base class (superclass in ObjC lingo).
If you're familiar with C#, super in ObjC means same as base in C#. And the same as super in Java. :)
The system-provided UIViewController class has loading functionality in its loadView method. This method is called by the system, and it does a lot of work. The viewDidLoad method, on the other hand, is defined in the base class but does not do much. Its purpose is that you can override it and provide your own functionality there. Same for viewDidUnload.