Question

I'm trying to category UIViewController to override viewWillAppear:. But getting this warning.

Category is implementing a method which also be implemented in primary class

@implementation UIViewController (ViewWillAppearCategory)

-(void)viewWillAppear:(BOOL)animated
{
    //.........
}

@end

I want to do some stuff during view appear in all screen, So I don't want to touch in all screen. that's why, go with category.

I may implement some method in sub class and I can call that method in all VC(all Screen). But I don't want this. It automatically invoke in view will appear call. Is this any idea to do this or did any mistake in above?

Note: This code will only appear in development phase for some testing purpose. So I'll remove this code when go with app store. So It should be easier task during removal, that is I won't touch all screen. I won't keep this code during submission to app store.

Was it helpful?

Solution

In such cases you must try Method Swizzling, a very nice formed concept which allows you to change the implementation of an existing selector.

For more details and code please visit the link below.

http://nshipster.com/method-swizzling/

OTHER TIPS

categories are for adding new methods, not overriding existing ones. Maybe make a subclass of UIViewController, say, MyUIViewController, with this code:

-(void) viewWillAppear:(BOOL) animated {
    // do your "category" stuff
}

then make all your other UIViewControllers subclasses of MyUIViewController with this code:

-(void) viewWillAppear:(BOOL) animated {
    [super viewWillAppear:animated];
    // rest of code for this class
}

I understand the reasons why you want to have a simple solution to test something on all screens and remove it easily, however:

  • You can not call super in a category, and not calling [super viewWillAppear:] may have unexpected results depending on the class and its particular implementation.
  • Swizzling methods is a hack and as you'll remove it from your final version, your testing version becomes useless as it may behave very differently.

On the other hand creating a UIViewController superclass where you properly override viewWillAppear: is not that complicated:

  • The code will belong only to a single class. No need to repeat/maintain code for every "screen".
  • You only need to change the other controllers' superclass and Nibs or Storyboards references once.
  • You can keep the superclass for both testing and release and the behavior will be similar.
  • You can do so many more things in a superclass than in a category.

Ultimately it would be interesting to know what are you trying to achieve. You could probably achieve similar things by implementing a UINavigationControllerDelegate and keep track of controllers getting pushed and popped.


As for viewWillAppear documentation:

This method is called before the receiver’s view is about to be added to a view hierarchy and before any animations are configured for showing the view. You can override this method to perform custom tasks associated with displaying the view. For example, you might use this method to change the orientation or style of the status bar to coordinate with the orientation or style of the view being presented. If you override this method, you must call super at some point in your implementation.

Again, you can't do that from a category.

As you are saying the code is going to be executed only in debug mode. Then why do you worry about warnings let the warning come you continue your work when it comes to release you remove your Category.

If you don't even need to see the warning your go with your same answer like

#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wobjc-protocol-method-implementation"

-(void)viewWillAppear:(BOOL)animated
{
    NSLog(@"I get callback here too");
}

#pragma clang diagnostic pop

But I would say to go for subclassing because removing the existing class is also not that hard in XCode tool.

What you want to achieve defeats the purpose of a Category. However, there's another way aside from subclassing UIViewController but you have to touch the viewWillAppear method for each controller.

//UIViewController+CustomCategory.h
@interface UIViewConctroller (CustomCategory)

- (void)performCustomization;

@end

//UIViewController+CustomCategory.m
@implementation UIViewController (CustomCategory)

- (void)performCustomization {
    // Do custom stuff…
}

@end

Then in each controller

//MYViewController.m
#import "UIViewController+CustomCategory.h"

- (void)viewWillAppear:(BOOL)animated {
    [super viewWillAppear:animated];
    [self performCustomization];
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top