user3772344
user3772344

Reputation: 153

Call method for different UIViewController

I am making master detail application, i have dynamic Detail ViewController. Detail ViewController are changed.

But in every Detail ViewController I have one common method updateInfo I want to call that method

Here is my code

UINavigationController *nav=[self.splitViewController.viewControllers objectAtIndex:1];
 UIViewController *controller=[nav.viewControllers objectAtIndex:0];
 [controller updateLastInfo];

But it gives me error no method found.

it will work if i use UIViewController name.

  HomeViewController *controller=(HomeViewController)[nav.viewControllers objectAtIndex:0];
     [controller updateLastInfo];

But i dnt want to do above things.

I have tried to explain. Please help

Upvotes: 0

Views: 301

Answers (3)

Caleb
Caleb

Reputation: 125037

UIViewController doesn't have a method named updateInfo, so the compiler will of course complain when you try to send that message to a pointer that's known only to point to an instance of UIViewController. When you use the class name, like this:

HomeViewController *controller=(HomeViewController)[nav.viewControllers objectAtIndex:0];

you're providing more information to the compiler, using a type cast to tell it "Hey, don't worry, I know for certain that the object I'll get back is a HomeViewController. Since you seem to have several types of view controllers that all have this method, the best thing to do is to declare the updateInfo method in a protocol and then have each of those UIViewController subclasses implement that protocol. So, your protocol declaration would be in a header file and might look like:

@protocol SomeProtocol

- (void)updateInfo

@end

and each class that has an -updateInfo method would just need to declare that it adopts the protocol:

@interface HomeViewController <SomeProtocol>
//...
@end

and then make sure that you have an -updateInfo in your class implementation:

@implementation HomeViewController

- (void)updateInfo {
    //...
}

//...
@end

Then, in your code, you can either check that the object conforms to the protocol using -conformsToProtocol: like this:

if ([controller conformsToProtocol:@protocol(SomeProtocol)]) {
    UIViewController<SomeProtocol> *c = (UIViewController<SomeProtocol>*)controller;
    [c updateInfo];
}

or else just check that the object responds to the selector before calling it:

if ([controller respondsToSelector:@selector(updateInfo)]) {
    [controller performSelector(updateInfo)];
}

The other answers you've received (using id or creating a common base class) are also good ones, but to be safe make sure you do some checking before calling your method. For example, you can use -isKindOfClass to make sure that the view controller you get back is in fact an instance of your common base class, and you can use -respondsToSelector: as above to check that an id points to an object that implements updateInfo.

Upvotes: 1

Ben Kane
Ben Kane

Reputation: 10070

You could subclass UIViewController and make a base DetailViewController class that houses common functionality of your detail view controllers. Then you would make all of your detail view controllers subclass DetailViewController instead of UIViewController. This would be a safe way to do it and would also allow you to add extra functionality to your updateInfo method in the specific detail view controllers.


If you want an unsafe way, you could make your controller object of type id. I wouldn't suggest this approach as it relies on your personal knowledge of the code. If someone else (or yourself down the road) sets it to a view controller that doesn't have that method, the code will still try to run and will crash.

Upvotes: 1

Sunny Shah
Sunny Shah

Reputation: 13020

You can use id

 UINavigationController *nav=[self.splitViewController.viewControllers objectAtIndex:1];
    id controller=[nav.viewControllers objectAtIndex:0];
    [controller updateLastInfo];

Upvotes: 1

Related Questions