Objective c handle adding child view controller or remove from parent - objective-c

I have a small question about UIViewController.
Is it possible to handle, in a custom UIViewController class, when the controller is added to current view controller using
[self addChildViewController:customViewController];
or when removing
[customViewController removeFromParentViewController];
For now, I have done what I want using viewDidLoad and dealloc methods but I was wondering if there were a better solution.
Thanks,

Your view controller can override this method when it wants to react to being added to a container.
- (void)didMoveToParentViewController:(UIViewController *)parent;
As by Apple doc
If you are implementing your own container view controller, it must
call the didMoveToParentViewController: method of the child view
controller after the transition to the new controller is complete or,
if there is no transition, immediately after calling the
addChildViewController: method.
The correspectiv for dealloc (which is anyway discouraged) is by Apple doc
- (void)willMoveToParentViewController:(UIViewController *)parent;
If you are implementing your own container view controller, it must
call the willMoveToParentViewController: method of the child view
controller before calling the removeFromParentViewController method,
passing in a parent value of nil.

Related

Instantiating nib lazily in UIViewController's view property accessor

In the application I'm currently working on, there's a case where I have 2 screens for a set of data: one is a list and one is a map. Each screen has its own view controller. The default screen is the list view, so that view controller loads first. But the other map screen view controller is also loaded and set up (as it encapsulates some geographic map-related data that the list screen view controller uses), even though the map screen is not visible yet.
I don't want the map screen view controller's nib and views to be loaded and initialized until the user switches to that screen, however.
Is there anything wrong with overriding the view property accessor within the map screen view controller as in the code below, and lazily loading/instantiating the nib? (The view property is not accessed until the map screen is about to be displayed, right before the map screen view controller's viewDidLoad method gets called.) I've tested that this works well, but I've never seen it done this way.
- (UIView *)view {
if (!_view) {
UINib *nib = [UINib nibWithNibName:#"MyNibName" bundle:nil];
[nib instantiateWithOwner:self options:nil];
}
return _view;
}
Figured out a better answer to this.
The code I'm working with isn't actually my own, and I hadn't noticed that the map screen's view controller wasn't actually a subclass of UIViewController, it was just subclassing NSObject (and adding its own view property).
By changing the map screen's view controller to actually inherit from UIViewController, and then using the designated initializer of initWithNibName:bundle:, the nib is by default lazily loaded/instantiated when the view property is accessed -- just like I was doing.
So, the answer to my question would be this: use the system frameworks and you won't even run into these issues! :) But it does seem to be the case that my code aligned with the actual best practice pattern; see Apple's guidelines and recommendations here.

Why need to use 'addChildViewController:' method

please explain me, why I need to use addChildViewController: method?
After all, when I put subview to view [some_obj.view addSubview:some_view], these subview knows about his controller.
Thanks.
addChildViewController
Needs to be called, cause the parent controller needs to hold a reference to its child view controller for lifetime / background management... this reference cannot / shouldn't be obtained from UIView, when added as a subview
Also you can than reference parent from the child via self.parentViewController
Apple Says about addChildViewController
Adds the given view controller as a child. If the new child view
controller is already the child of a container view controller, it is
removed from that container before being added. This method is only
intended to be called by an implementation of a custom container view
controller. If you override this method, you must call super in your
implementation.
For adding / removing, you can refer to this great category and have no worry when to call it:
UIViewController + Container
- (void)containerAddChildViewController:(UIViewController *)childViewController {
[self addChildViewController:childViewController];
[self.view addSubview:childViewController.view];
[childViewController didMoveToParentViewController:self];
}
- (void)containerRemoveChildViewController:(UIViewController *)childViewController {
[childViewController willMoveToParentViewController:nil];
[childViewController.view removeFromSuperview];
[childViewController removeFromParentViewController];
}

Push view to navigation controller from button in other class

I have a UIButton that I create in my sub class ViewController, and add it to my MainViewController.
Now, I added a target method to this button that should push another view controller to my Navigation controller (the one that in the MainViewController).
I know that the method did call when I push the button, but the view wasn't push to the Navigation Controller.
I scanned this drawing - this is the drawing (I also added part of my code):
This is the code I'm using in my button:
(remember it's in a deferent ViewController).
- (void)buttonPressed:(UIButton *)sender
{
Photo_ScreenGlobalView *photo = [[Photo_ScreenGlobalView alloc] init];
[self.navigationController pushViewController:photo animated:YES];
}
Usually I solve these situations with delegation. If there is a view controller which is subordinate to another (i.e. a "sub" view controller) but should have the ability to trigger navigation changes, etc... then it should have a weak pointer back to it's 'parent'. Then the parent VC should implement an appropriately named protocol with a callback for the child to use. The names of these things can be generic, such as #property navigationDelegate and requestNavigationToViewController: or they can be more semantic, such as #property userFormDelegate and userFormDoneButtonPressed:
Generally speaking, a subordinate view controller should not be able to directly modify navigation at it's parent's level; but it can trigger it via more loosely-coupoled interfaces like these.
i came back to let you all know how i actually did it.
after googling a lot found this nice and quick guide how to make DELEGATE
and working with delegate solved all my problems. if you need any help don't hesitate to send me PM.
this is the guide:
http://css.dzone.com/articles/do-not-publishcreating-your

Check if View has been Removed or Not?

I have a UIView class which I am currently removing from my view by using from inside the class [self removeFromSuperview]. Hopefully that's the correct thing to do.
However, now from my view controller (of which I add this view to) I need to know when it has removed itself so that I can call a method when this happens.
Generally speaking, the view shouldn't be doing things like removing itself. That's the job of the view controller.
If a UIView subclass can produce events that require the view hierarchy to be changed, I would define a delegate property for that view, and when an event occurs, call a method on that delegate. Then, when your view controller adds the view, it would set itself as the delegate and define the relevant method to handle the event.
If you have removed the UIView
view.removeFromSuperview()
you can check if it exists with the following code:
if !(view.superview != nil) {
//no superview means not in the view hierarchy
}
You could have a delegate callback setting the controller as the view's delegate. When you're about to remove the view, make the delegate callback and implement the callback method in your controller.
The 'removeFromSuperview' has always seemed backwards to me… :(
I'm assuming you are making the remove call after some sort of action, like a button press or something. if that is the case, set the buttons delegate to be the view controller, not the view class, and inside the action method in the view controller, call
[yourCustomView removeFromSuperview];
The best choice would be to let the controller remove the view
[self.view removeFromSuperview];
and to know if the view was removed (or never added) you can ask
if(![self.view superview]) {
//no superview means not in the view hierarchy
}
Not sure what sdk you are using - but I am using iOS 5 and I just use the following method in the superview:
-(void)willRemoveSubview:(UIView *)subview{
if([subview isEqual:someView]){
//do stuff
}
//you could do some stuff here too
}

iOS Dev, How can I call a method in the super class of my UIViewController?

i have two UIViewControllers for example A and B.
On A there is a button when pushed loads view B as a sub view. Using the standard initWithNibName. On B there is a button which dismisses View B and should call a method in view A (its Parent View). I thought it should be a simple [super methoddName:perimeter] but this doesn't work. after placing a NSLog printing out the name of the parentViewController it returned null which is odd as surly it should return View A as the Parent view.
any Ideas Cheers
super refers to your class's superclass, not its parent view controller.
A way to quickly do this is create a new init method that takes an instance of view controller A, use that to set the target of your button.
The best way is to define a new protocol on view controller B. Make view controller A conform to it. On init of B, pass in a refernce to A to use as your delegate. Then on the button push in B call the desired method on the delegate.
You might be better off by letting view controller A be a delegate on view controller B.
A can set the delegate property on B when after loading it but before pushing it into view, and when B needs to call the required method, it can just call it on the delegate object.
That makes the coupling between the controllers looser, and if you let the delegate conform to a protocol, you can keep B's knowledge of A to a minimum.
It's better design, if you ask me.
parentViewController won't work if you add view controller B's view as a subview. You will have to find the view controller A in a different way.
Say, if you had added B's view as a subview like this,
[A.view addSubview:B.view];
then you can call view controller A like this.
[[B.view.superview nextResponder] methoddName:perimeter];
If you have added B.view as a subview somewhere within the view hierarchy of A.view.
UIResponder * responder = B.view.superview;
do {
responder = [responder nextResponder];
} while ( ![responder isMemberOfClass:[A class]] );
// `responder` is referencing your view controller A. You will have to cast it.
Easiest way to do this especially if it is a static method:
ViewControllerB
#import "ViewControllerA.h"
- (void)dismissView{
//implementation to close the view
[ViewControllerA methodName:perimeter];
}
Good Luck!