execute a method in all the ViewControllers - ios

Maybe it is not possible but here is my question:
I need to execute the same method on all the ViewControllers, precisely on the viewDidLoad or on the viewDidAppear methods.
Is there any way on the AppDelegate or somewhere of doing this apart from calling this function from every single controller?

Try this,
Create a BaseViewController
#interface BaseViewController : UIViewController
and create all other ViewControllers by subclassing BaseViewController
#interface AViewController : BaseViewController
and do ypu stuff in viewDidLoad or on the viewDidAppear of BaseViewController

Here is a simple approach to do this. Follow OOPS & make the use of inheritance like this.
Make a baseViewController & add two methods for example.
btBaseViewController.h
#interface btBaseViewController : UIViewController
#end
-(void)renderPadUI;
-(void)renderPhoneUI;
Provide a no-op definition for these two methods.
btBaseViewController.m
-(void)renderPhoneUI {
// to be overridden by derrived classes
}
-(void)renderPadUI {
// to me overridden by derrived classes.
}
And in viewDidLoad do something like this
if(IS_IPAD) {
[self renderPadUI];
}else{
[self renderPhoneUI];
}
Now Sub class your ViewControllers from this btBaseViewController class as
btHomeViewController.h
#interface btHomeViewController : btBaseViewController
#end
Now if you do not provide the definition of methods renderPhoneUI and renderPADUI btHomeViewController the base version will be executed.
Thats simple.

I'm guessing making a UIViewController subclass that does what you do and make every controller of your app of that new subclass type.
MyUIViewController.h
#interface MYUIViewController : UIViewController
#end
MYUIViewController.m
#implementation MYUIViewController
- (void)viewDidLoad
{
[super viewDidLoad];
[self myMethodCall];
}
And then, every UIViewController that needs to execute this method, should be of MYUIViewController type.

You can define the method in the app delegate or you can make a subclass of a UIViewController

Related

iOS Protocol - Delegate always nil

I have two controllers. A BaseViewController and MyController. On BaseViewController I have as property an NSObject that has a Protocol
BaseViewController.h
#property (nonatomic, strong) MyListener *myListener;
MyListener.h
#protocol MyListenerProtocol;
#interface MyListener : NSObject
#property (nonatomic, weak) id<MyListenerProtocol> delegate;
#end
#protocol MyListenerProtocol;
#protocol MyListenerProtocol <NSObject>
#optional
-(void) myMethod: (int) input;
#end
MyController extends BaseViewController
#interface MyController : BaseViewController <MyListener>
and in it's viewDidLoad:
super.myListener = [[MyListener alloc] init];
super.myListener.delegate = self;
in BaseViewController in a method, when called it does:
if (self.myListener && [self.myListener.delegate respondsToSelector:#selector(myMethod:)]) {
[self.myListener.delegate myMethod: input];
}
But in this point the "self.myListener" is always nil.
What I want is to call a method in the child view controller when a BaseViewController's method is called (but only for some children view controllers, not all).
Any suggestions?
Please implement a custom getter for the property named delegate, set it normally and set a breakpoint there. This way you will find the cause of the problem.
Also, be aware that a weak property will go away as soon as no other objet points to the
Object that you set as delegate.
The most likely cause (and an insanely common cause) is that your BaseViewController method is being called prior to viewDidLoad. Have you verified this is not the case?
As a note, you mean self in all the places you've put super.
Also note, in this line:
if (self.myListener && [self.myListener.delegate respondsToSelector:#selector(myMethod:)]) {
There is no reason for self.myListener &&... If self.myListener is nil, the rest of the call will become false automatically.
You should tell the MyController the delegate it uses, but you tell the wrong name.
#interface MyController : BaseViewController <MyListener>
change to:
#interface MyController : BaseViewController <MyListenerProtocol>
Set delegate in prepareForSegue method.
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
LastNameViewController *lastNameViewController = [segue destinationViewController];
lastNameViewController.delegate = self;
}

Where to set delegate = self? Or should I just use a different design pattern?

EDIT: edited for clarity
Disclaimer: I'm new and pretty bad. But I have tried very hard and read lots of stuff to figure this out, but I have not...
I think my whole delegate pattern would work, except I can't figure out how to set the delegate property of ViewController to self in the MatchLetter class. The reason is because I can't figure out how to call code there. It's not a view controller, so viewDidLoad or prepareForSegue won't work.
This is what I've got:
ViewController.h
#import <UIKit/UIKit.h>
#class ViewController;
#protocol letterMatchProtocol <NSObject>
- (BOOL) isLetterMatch:(char) firstLetter;
#end
#interface ViewController : UIViewController
#property (nonatomic, weak) id <letterMatchProtocol> delegate;
#end
ViewController.m
#import "ViewController.h"
#interface ViewController ()
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
char c = 'a';
// This is the method I want to delegate to MatchLetter, to have a BOOL returned
BOOL returnValue = [self.delegate isLetterMatch:c];
}
#end
MatchLetter.h
#import <Foundation/Foundation.h>
#import "ViewController.h"
#interface Delegate : NSObject <letterMatchProtocol>
#end
MatchLetter.m
#import "MatchLetter.h"
#implementation Delegate
// this is the code I think I need to run here, to set the delegate property...
// ViewController *viewController = [ViewController new];
// viewController.delegate = self;
// ... so that isLetterMatch can be run here from ViewController.m
// But I don't know where to put this code, or how to get it to run before the ViewController
// especially since there are no segues or views to load.
- (BOOL) isLetterMatch:(char)firstLetter {
if (firstLetter == 'a') {
return YES;
}
else {
return NO;
}
}
#end
Can somebody please tell me the best way to proceed? Thanks for reading
You asked "Where to set delegate = self? Or should I just use a different design pattern?".
Answer: Don't. An object should never be it's own delegate.
Your code is quite a mess.
Don't name a class "Delegate". A delegate is a design pattern. The whole point of a delegate is that any object that conforms to a particular protocol ("speaks the language") can serve as the delegate. You don't need to know what class of object is serving as the delegate, but only that it speaks the language you need.
An analogy: When you call the operator, you don't care who is working the operator desk. You don't care about his/her gender, religion, ethnic background, how tall they are, etc. You just care that they speak your language.
Likewise, when you set up a delegate, it doesn't matter what type of object gets set as the delegate. All that matters is that the object that is the delegate conforms to the protocol for that delegate.
A table view can have ANY object serve as it's delegate, as long as that object conforms to the UITableViewDelegate protocol. You usually make you view controller be the table view's delegate, but you don't have to. You could create a custom class that manages your table views, and have it be the delegate. There is no "TableViewDelegate" object class. There is instead a UITableViewDelegate protocol, and any object that conforms to the protocol can act as a table view's delegate.
Edit: Your question is confusing. I think what you're proposing is that your Delegate class would create a view controller and make itself the delegate for the view controller.
If that's what you are talking about, your thinking is backwards. The view controller is using the Delegate class as a helper class. Any given instance of a view controller class can create an instance of the Delegate class and set it as it's delegate if it desires. You might have 3 instances of ViewController at one time, each with it's own instance of your Delegate class.
Thus, the ViewController object is the one that should create and set up an instance of Delegate if it needs one:
- (void) viewDidLoad;
{
self.delegate = [[Delegate alloc] init];
//other setup here
}

iOS change UIViewController

In my app I have a gradient as a background. This gradient is made programmatically. The way that I now use this is like this:
I have a UIViewController which needs to display the gradient and in that class I do this :
- (void) viewWillAppear:(BOOL)animated{
[super viewDidAppear:animated];
[Gradient gradientInViewController:self];
}
This ain't so bad but this needs to be done in all the classes which isn't very good programming. What I want is instead of making a class a UIViewController, I want it to be a GradientViewController which is a subclass of UIViewController and in this class I will handle everything.
So my question is how do I do this? I think this has to be done through categories? But I can't figure out how to get the image on the screen. Should this be done in viewWillAppear or something?
Make a GradientViewController which handles the gradient drawing
#interface GradientViewController : UIViewController
#end
#implementation GradientViewController
- (void) viewWillAppear:(BOOL)animated{
[super viewWillAppear:animated];
[Gradient gradientInViewController:self];
}
#end
Then inherit all your other controllers from that
#interface YourViewController : GradientViewController
#end
#implementation YourViewController
- (void) viewWillAppear:(BOOL)animated{
[super viewWillAppear:animated];
// no need to do anything
}
#end
It's more flexible to do it through helper classes or categories though, even if there's a bit of repetition.
Note as pointed out by Nguyen Duc, that you are calling [super viewDidAppear:] for viewWillAppear: which is wrong, I edited the answer.
Why not use Interface Builder and have a xib that knows how to load your image for you automatically?
You can get this behaviour "for free" throughout your app simply by subclassing UIViewController:-
#interface GradientViewController : UIViewController
#end
and implementing your gradient code in viewDidLoad: as such:-
- (void)viewDidLoad
{
[super viewDidLoad];
[Gradient gradientInViewController:self];
}
Then just use GradientViewController instead of UIViewController everywhere you need your gradient.
Alternatively you can use a category. This can be useful because you can use categories for "themes" for your app, configuring various UI elements of your UIViewControllers. But I'd set up a category on UIViewController specifically to set your gradient, and then call the category method in every view controller that needs it - do not attempt to do it by overriding viewDidLoad: or viewWillAppear: in a category.
Just create a new view controller (let's call it GradientViewController for example), put the same code that draws the gradient into its view viewWillAppear, then make all your view controllers a subclass of the view controller by replacing
#interface SomeViewController : UIViewController
with
#interface SomeViewController : GradientViewController

Why is textFieldwithPlaceHolderText undefined for one view controller that conforms to UITextFieldDelegate?

I have two UIViewController sublcasses, both of them conform to the UITextFieldDelegate protocol. IOW, I have these classes.
# MyVC1.h
#interface MyVC1 : UIViewController <UITextFieldDelegate>
# MyVC1.m
#interface MyVC1 () {
// Private variable, so not a property
UITextField *_myTextField;
}
#end
#implementation MyVC1
- (void)viewDidLoad
{
_myTextField = [self textFieldwithPlaceHolderText:#"*Text"];
}
#end
SAME CODE for MyVC2 class, except of course the class name.
However, and this is the strange part, my code compiles for MyVC1, but NOT for MyVC2. For MyVC2, compiler says "No visible #interface for "MyVC2" declares the selector "textFieldwithPlaceHolderText". What am I missing for MyVC2? I've double- and triple-checked!
Like Jsdodgers said, textFieldwithPlaceHolderText is not a method of UITextFieldDelegate. Check your #imports section on both controllers - maybe VC1 imports a category for UIViewController class that adds that method to it. A category import would look like this: #import "UIViewController+_.h"
Ok, it's late, and I'm sleepy. MyVC1 defines the textFieldwithPlaceHolderText method, but NOT MyVC2. I cut/past the viewDidLoad section, but forgot to cut/paste the method. Sorry to waste your time.
copy the method "textFieldwithPlaceHolderText" in myVc2.h in interface a
and implement in myvc2.m if i post anything wrong sorry for that

How to create a class with a UIViewController when the subclass of UIViewController is unknown

The title is what I think I need but i will go back one step. I want to create a class which handles certain things in an iOS app. This class might be called by multiple UIViewcontrollers in an iOS app. The class may need to show a UIView at some stage for user input. So my question is how can I show a UIView when I don't know which subclass of UIViewController is calling it? To what can I add the UIView from this class?
I suppose there are two possible answers either the class finds the current UIViewController or the calling subclass of UIViewController passes itself to the class so the class knows.
How is this supposed to be done.
Thanks guys for your help.
I'm going to expand on #ericleaf's comment regarding using a protocol and subclasses. It sounds like you are asking the following:
How can I create a resusable, generic class that presents a view
within a UIViewController subclass?
A great way to do this is to define a protocol in your generic class and have your view controller subclasses support this protocol. The protocol defines an interface for your custom class to comunicate with it's delegate, in this case a UIViewController subclass. Other than the protocol, the objects don't need to know anything else about the implementation of each other.
Any information your custom object needs to be able to present views within it's delegate would be passed via protocol methods. The specifics of the protocol are up to you based on your needs. You could have the custom object "ask" the delegate for information (e.g. what view should I put a subview in?) or you could have the protocol provide information to the delegate and let the delegate deal with it (e.g. here is a subview you can put wherever you want).
There is a lot of great documentation on protocols available on SO and elsewhere. This is long enough already so I kept the example fairly simple.
custom class .h file with protocol definition
// my custom class that adds adds a view to a view controller that supports it's protocol
// forward class definition for the protocol
#class MyAwesomeObject;
#protocol MyAweseomeObjectDelegate <NSObject>
- (UIView *)viewForMyAwesomeObject:(MyAwesomeObject *)awesomeObject;
#end
// this could be defined such that the delegate *must* be a UIViewController. I've left it generic.
#interface MyAwesomeClassObject : NSObject
#property (nonatomic, weak) id <MyAwesomeObjectDelegate> delegate;
#end
custom class .m file
// MyAwesomeObject.m
#import "MyAwesomeObject.h"
#implementation MyAwesomeObject
// this is a dumb example, but shows how to get the view from the delegate
// and add a subview to it
- (void)presentViewInDelegate
{
UIView *containingView = [self.delegate viewForMyAwesomeObject:self];
if (containingView) {
UIView *subview = [[UIView alloc] initWithFrame:containingView.bounds];
subview.backgroundColor = [UIColor redColor];
subview.autoresizingMask = UIViewAutoresizingFlexibleWidth|UIViewAutoresizingFlexibleHeight;
[containingView addSubview:subview];
}
}
MyViewController .h using the custom object
// MyViewController.h
#import "MyAwesomeObject.h"
#interface MyViewController : UIViewController <MyAwesomeObjectDelegate>
#property (nonatomic, strong) MyAwesomeObject *awesomeObject;
#end
MyViewController .m using the custom object
// MyViewController.m
#import "MyViewController.h"
#implementation MyViewController
- (void)init
{
self = [super init];
if (self) {
_awesomeObject = [[MyAwesomeObject alloc] init];
_awesomeObject.delegate = self;
}
return self;
}
// MyAwesomeObjectDelegate
- (UIView *)viewForMyAwesomeObject:(MyAwesomeObject *)awesomeObject
{
return self.view;
}
You can get the class into a string and do a compare.
For example, lets assume your custom UIViewController subclass is CustomViewCon and the UIViewController object reference is myUnknownClassObject, then:
NSString *classString = NSStringFromClass([myUnknownClassObject class]);
Then you can:
if([classString isEqualToString:#"CustomViewCon"]){
//do something like maybe present a particular view
myUnknownClassObject.view = myCustomView; //or anything..
}
Similarly you can check for any class.
Edit: According to the suggestions from comments, you could also do the following(better way):
if([[myUnknownClassObject class] isKindOfClass:[CustomViewCon class]]){
//same as before
}
Why wont you use a block for this?
BaseViewController.h:
#property (copy) void (^addViewBlock)();
- (IBAction)showViewWhenNeeded;
BaseViewController.m:
- (IBAction)showViewWhenNeeded
{
if (self.addViewBlock)
self.addViewBlock();
}
And in your child class, set that block's actions, and call the method when you feel like you should put up a view.
ChildViewController.m
// within some method, propably init or smth
[self setAddViewBlock:^{
[self.vied addSubView:...];
}];
// when need to actually add the view
[self showViewWhenNeeded];

Resources