ios - modal View controllers - how to display and dismiss -
i'm breaking head lastly 1 week on how solve issue showing , dismissing multiple view controllers. have created sample project , pasting code straight project. have 3 view controllers corresponding .xib files. mainviewcontroller, vc1 , vc2. have 2 buttons on main view controller.
- (ibaction)vc1pressed:(uibutton *)sender { vc1 *vc1 = [[vc1 alloc] initwithnibname:@"vc1" bundle:nil]; [vc1 setmodaltransitionstyle:uimodaltransitionstylefliphorizontal]; [self presentviewcontroller:vc1 animated:yes completion:nil]; }
this opens vc1 no issues. in vc1, have button should open vc2 while @ same time dismiss vc1.
- (ibaction)buttonpressedfromvc1:(uibutton *)sender { vc2 *vc2 = [[vc2 alloc] initwithnibname:@"vc2" bundle:nil]; [vc2 setmodaltransitionstyle:uimodaltransitionstylefliphorizontal]; [self presentviewcontroller:vc2 animated:yes completion:nil]; [self dismissviewcontrolleranimated:yes completion:nil]; } // shows warning: effort dismiss view controller <vc1: 0x715e460> while presentation or dismiss in progress! - (ibaction)buttonpressedfromvc2:(uibutton *)sender { [self dismissviewcontrolleranimated:yes completion:nil]; } // going vc1.
i want go main view controller while @ same time vc1 should have been removed memory good. vc1 should show when click on vc1 button on main controller.
the other button on main view controller should able display vc2 straight bypassing vc1 , should come main controller when button clicked on vc2. there no long running code, loops or timers. bare bone calls view controllers.
please help.
this line:
[self dismissviewcontrolleranimated:yes completion:nil];
isn't sending message itself, it's sending message it's presenting vc, asking dismissing. when nowadays vc, create relationship between presenting vc , presented one. should not destroy presenting vc while presenting (the presented vc can't send dismiss message back…). you're not taking business relationship of leaving app in confused state. see reply here: dismissing presented view controller in recommend method more written:
[self.presentingviewcontroller dismissviewcontrolleranimated:yes completion:nil];
in case, need ensure of controlling done in mainviewcontroller
. should utilize delegate send right message mainviewcontroller viewcontroller1, mainviewcontroller can dismiss vc1 , nowadays vc2.
in vc2 vc1 add together protocol in .h file above @interface:
@protocol viewcontroller1protocol <nsobject> - (void)dismissandpresentvc2; @end
and lower downwards in same file in @interface section declare property hold delegate pointer:
@property (nonatomic,weak) id <viewcontroller1protocol> delegate;
in vc1 .m file, dismiss button method should phone call delegate method
- (ibaction)buttonpressedfromvc1:(uibutton *)sender { [self.delegate dissmissandpresentvc2] }
now in mainviewcontroller, set vc1's delegate when creating vc1:
- (ibaction)present1:(id)sender { viewcontroller1* vc = [[viewcontroller1 alloc] initwithnibname:@"viewcontroller1" bundle:nil]; vc.delegate = self; [self present:vc]; }
and implement delegate method:
- (void)dismissandpresent2 { [self dismissviewcontrolleranimated:no completion: ^{ [self present2:nil]; }]; }
present2:
can same method vc2pressed:
button ibaction method. note called completion block ensure vc2 not presented until vc1 dismissed.
you moving vc1->vcmain->vc2 want 1 of transitions animated.
update
in comments express surprise @ complexity required accomplish seemingly simple thing. assure you, delegation pattern central much of objective-c , cocoa, , illustration simple can get, should create effort comfortable it.
in apple's view controller programming guide have this say:
dismissing presented view controller
when comes time dismiss presented view controller, preferred approach allow presenting view controller dismiss it. in other words, whenever possible, same view controller presented view controller should take responsibility dismissing it. although there several techniques notifying presenting view controller presented view controller should dismissed, preferred technique delegation. more information, see “using delegation communicate other controllers.”
if think through want achieve, , how going it, realise messaging mainviewcontroller of work logical way out given don't want utilize navigationcontroller. if do utilize navcontroller, in effect 'delegating', if not explicitly, navcontroller of work. there needs some object keeps central track of what's going on vc navigation, , need some method of communicating it, whatever do.
in practice apple's advice little extreme... in normal cases, don't need create dedicated delegate , method, can rely on [self presentingviewcontroller] dismissviewcontrolleranimated:
- it's when in cases yours want dismissing have other effects on remote objects need take care.
here imagine work without delegate hassle...
- (ibaction)dismiss:(id)sender { [[self presentingviewcontroller] dismissviewcontrolleranimated:yes completion:^{ [self.presentingviewcontroller performselector:@selector(presentvc2:) withobject:nil]; }]; }
after asking presenting controller dismiss us, have completion block calls method in presentingviewcontroller invoke vc2. no delegate needed. (a big selling point of blocks cut down need delegates in these circumstances). in case there few things getting in way...
in vc1 don't know mainvc implements methodpresent2
- can end difficult-to-debug errors or crashes. delegates help avoid this. once vc1 dismissed, it's not around execute completion block... or it? self.presentingviewcontroller mean more? don't know (neither i)... delegate, don't have uncertainty. when seek run method, hangs no warning or errors. so please... take time larn delegation!
update2
in comment have managed create work using in vc2's dismiss button handler:
[self.view.window.rootviewcontroller dismissviewcontrolleranimated:yes completion:nil];
this much simpler, leaves number of issues.
tight coupling hard-wiring viewcontroller construction together. example, if insert new viewcontroller before mainviewcontroller, required behaviour break (you navigate prior one). in vc1 have had #import vc2. hence have quite lot of inter-dependencies, breaks oop/mvc objectives.
using delegates, neither vc1 nor vc2 need know mainvc or it's antecedants maintain loosely-coupled , modular.
memory vc1 has not gone away, still hold 2 pointers it:
mainvc'spresentedviewcontroller
property vc2's presentingviewcontroller
property you can test logging, , doing vc2
[self dismissviewcontrolleranimated:yes completion:nil];
it still works, still gets vc1.
that seems me memory leak.
the clue in warning getting here:
[self presentviewcontroller:vc2 animated:yes completion:nil]; [self dismissviewcontrolleranimated:yes completion:nil]; // effort dismiss view controller <vc1: 0x715e460> // while presentation or dismiss in progress!
the logic breaks down, attempting dismiss presenting vc of which vc2 presented vc. sec message doesn't executed - perhaps stuff happens, still left 2 pointers object thought had got rid of. (edit - i've checked , it's not bad, both objects go away when mainvc)
that's rather long-winded way of saying - please, utilize delegates. if helps, made brief description of pattern here: is passing controller in construtor bad practice?
update 3 if want avoid delegates, best way out:
in vc1:
[self presentviewcontroller:vc2 animated:yes completion:nil];
but don't dismiss anything... ascertained, doesn't happen anyway.
in vc2:
[self.presentingviewcontroller.presentingviewcontroller dismissviewcontrolleranimated:yes completion:nil];
as (know) haven't dismissed vc1, can reach through mainvc. mainvc dismisses vc1. because vc1 has gone, it's presented vc2 goes it, @ mainvc in clean state.
it's still highly coupled, vc1 needs know vc2, , vc2 needs know arrived @ via mainvc->vc1, best you're going without bit of explicit delegation.
ios objective-c ios6
No comments:
Post a Comment