Marti Serra Vivancos
Marti Serra Vivancos

Reputation: 1189

How can I call a UIViewController method from an UIView subclass

I am developing and iOS app for iPad. I have an UIView subclass and I'd like to call a method of the ViewController from that subclass. I've tried to code a delegate but it doesn't work. Is that a good solution or I have to do it another way?

Upvotes: 1

Views: 3780

Answers (2)

iiFreeman
iiFreeman

Reputation: 5175

Try block, here is the sample:

MyView.h

@interface MyView: UIView 
...
@property (nonatomic, copy) void(^myEventCallBack)(id someData);
...
@end

MyView.m (How to call block sample)

...

- (IBAction)buttonTapped:(UIButton *)sender {
   if (self.myEventCallback) {
       self.myEventCallback(self.someImportantData);
   }
}

...

in your UIViewController:

self.myView = [[MyView alloc] initWithFrame:someFrame];

// THIS IS VERY IMPORTANT, USE __weak COPY OF YOUR UIViewController OBJECT (owner of object which contains block) INSIDE BLOCK TO PREVENT RETAIN CIRCLE, CAUSE BLOCK RETAINS ITS CONTENT
__weak MyViewController *self_ = self;
self.myView.myEventCallback = ^(id someData){
    [self_ doSomeProcessingWithData:someData];
};

also block can be used with return value, sample:

@property (nonatomic, copy) BOOL(^shouldStartProcessing)(void);

self.myView.myEventCallback = ^BOOL{
    return (self_.state == MyViewControllerStateReady);
};

Upvotes: 3

matt
matt

Reputation: 536047

In general the problem of communication between conceptually "distant" objects is tricky one, but it is the heart of Cocoa programming. Getting a reference from one instance to another is crucial! I discuss the problem in general here:

http://www.apeth.com/iOSBook/ch13.html#_instance_visibility

Here's one possibility. If this UIView instance is in the interface, then either its nextResponder is the view controller or it is the subview of a superview whose nextResponder is the view controller. Moreover, the view hierarchy parallels the responder chain. So simply walk up the responder chain until you come to the view controller.

UIResponder* r = someView; // the view instance, living in the interface
while (![r isKindOfClass:[UIViewController class]])
    r = [r nextResponder];

Now r is the view controller. Now cast to what you know is the actual view controller's class, and you will be able to call methods on it:

MyViewController* vc = (MyViewController*)r;

Here's my book's summary of the responder chain:

http://www.apeth.com/iOSBook/ch11.html#_the_responder_chain

However, there are many other possibilities. As someone has already suggested, you could set up lines of communication by means of NSNotification (shoutcasting); it's ugly, but it does work, and it's intended in part to cover just this sort of tricky situation.

Upvotes: 1

Related Questions