Push view to navigation controller from button in other class - objective-c

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

Related

Correct method to present a different NSViewController in NSWindow

I am developing an app that is a single NSWindow and clicking a button inside the window will present a NSViewController, and a button exists in that controller that will present a different NSViewController. I know how to swap out views in the window, but I ran into an issue trying to do this with the multiple view controllers. I have resolved the issue, but I don't believe I am accomplishing this behavior in an appropriate way.
I originally defined a method in the AppDelegate:
- (void)displayViewcontroller:(NSViewController *)viewController {
BOOL ended = [self.window makeFirstResponder:self.window];
if (!ended) {
NSBeep();
return;
}
[self.box setContentView:viewController.view];
}
I set up a target/action for an NSButton to the AppDelegate, and here's where I call that method to show a new view controller:
- (IBAction)didTapContinue:(NSButton *)sender {
NewViewController *newVC = [[NewViewController alloc] init];
[self displayViewcontroller:newVC];
}
This does work - it presents the new view controller's view. However if I then click any button in that view that has a target/action set up that resides within its view controller class, the app instantly crashes.
To resolve this issue, I have to change didTapContinue: to the following:
- (IBAction)didTapContinue:(NSButton *)sender {
NewViewController *newVC = [[NewViewController alloc] init];
[self.viewControllers addObject:newVC];
[self displayViewcontroller:[self.viewControllers lastObject]];
}
First of all, can you explain why that resolves the issue? Seems to be related to the way the controller is "held onto" in memory but I'm not positive.
My question is, how do I set this up so that I can swap out views from within any view controller? I was planning on getting a reference to the AppDelegate and calling displayViewcontroller: with a new controller I just instantiated in that class, but this causes the crash. I need to first store it in the array then send that reference into the method. Is that a valid approach - make the viewControllers array public then call that method with the lastObject, or how should this be set up?
What is interesting in your code is that you alloc/init a new view controller every time that you call the IBAction. It can be that your view its totally new every time you call the IBAction method, but I would think that you only have a limited number of views you want to show. As far as my knowledge goes this makes your view only to live as long as your IBAction method is long. That the view still exists, is because you haven't refreshed it. However, calling a method inside a view controller that is not in the heap anymore (since you left the IBAction method and all local objects, such as your view controller are taken of the heap thans to ARC) makes the app crash, because you reference a memory space that is not in use or used by something else.
Why does the app work when you ad the view to the viewcontrollers array? I assume this array is an array that has been initiated in the AppDelegate and now you add the view controller with a strong reference count to the viewcontrollers array. When you leave the IBAction method, the view controller still has a strong reference and ARC will not deallocate the view controller.
Is this the proper way? Well, it works. I would not think it is considered very good programming, since you don't alloc/init an object in a method that needs to stay alive after leaving the method. It would be better practice to allocate and initialize your view controller(s) somewhere in an init, awakeFromNIB or a windowDidLoad method of your AppDelegate. The problem with your current solution is that you are creating an endless array of view controllers of which you only use the last. Somewhere your program will feel the burden of this enormously long array of pretty heavy objects (view controllers) and will run out of memory.
Hope this helps.
By the way, this is independent of whether you use Mavericks or Yosemite. I was thinking in a storyboard solution, but that wouldn't answer your question.
Kind regards,
MacUserT

Call a method with childViewControllers on the same viewController

I'd like to know how to call a method in childViewController01 from childViewController02.
These ViewControllers are declared on the parentViewController, as follows.
○ParentViewController.m:
ChildViewController01 *childViewController01 = [[ChildViewController01 alloc] init];
[self.view addSubView:childViewController01];
ChildViewController02 *childViewController02 = [[ChildViewController02 alloc] init];
[self.view addSubView:childViewController02];
I know the way to call parentViewController's method from childViewController01.
○ParentViewController.m:
childrenViewController01.childDelegate01 = self;
○ChildrenViewController01.h:
#property (nonatomic, retain) id childDelegate01;
○ChildrenViewController01.m:
[childDelegate01 performSelector:#selector(parentMethod:) withObject:hogeObj];
so, I can call childViewControllers's method from parentViewController
○ParentViewController.m:
- (void) parentMethod:(id)hogeObj {
[childViewController02 childMethod02];
}
This is so tiring. I'd like to call childMethod02 from childViewController01 directly.
If you know how, please let me know a good way.
Thanks.
Part of the reason you use view controllers at all is to keep things separate and tidy. One view controller shouldn't really know anything about its siblings; it's only responsibility is managing it's view and child view controllers. The parent view controller should be in charge of managing the sibling view controllers. Your options to do this are to tell the parent view controller what you want to happen and have the parent send the message to the other view controller, "pollute" the state of the view controllers with references to each other like Metabble suggested, or use a notification pattern.
I've often used NSNotificationCenter for this purpose. Register for the notifications in each view controller and then post notifications to trigger the method calls in the other view controllers.
When you create the controller's, give them references to each other and store them.

Accessing an instance method of a ViewController From Another view controller

Let's say I have a view controller called vc1, which a synthesized property called property1, and i wants to access it from another view controller (vc2) and change it from vc2.
Now the methods created by the #syntisize to change and get properties are instance methods, so how can I get to them fro another view controller (do view controllers have instances in the app, and if so, what are they?)
Just to be clear I am using storyboards, so I never really instantiate the view controllers...
VC1.m:
-(void) yourMethod {
...
}
VC2.m
YOURViewController * vc2 = [[YOURViewController alloc]init];
[vc yourMethod];
[vc release];
Make sure to import your YOURViewController in your other view .m file
Something like that should work.
Or if you're having problems, try this tutorial here:
Tutorial on How-To Pass Data Between Two View Controllers
Hope this helps :)
While you can do it the way you describe, I think the common technique (assuming VC1 has a segue to VC2) is a bit different, where VC2 will have a property that will be set by prepareForSegue. See Configuring the Destination Controller When a Segue is Triggered in the View Controller Programming Guide.
You will need to link the storyboard views with the viewcontrollers so the view for vc1 would use the class vc1 etc for the rest (I assume you have done this because this is important when coding for different views)
Then all you need to do is where ever you are calling the properties so lets say the viewDidLoad method, declare the view controller like this:
- (void) viewDidLoad {
vc1 *viewController;
// Now you change the variable I'll presume its a UILabel so I'll change its text [viewController.property1 setText:#"I changed a different views UILabel"];
}
Let me know whether this works... Its worked for me before so should work

View Controller Doesn't respond to Action Methods

I have a simple test app (in OSX) that has a view controller with a button in its view. The button's action method is in the view controller's class, and that IBAction is connected in IB (through File's Owner). When the button is clicked, I get an EXC_BAD_Access error (except occasionally I get -[NSRunLoop buttonClick:] instead). I've read a bunch of posts here on SO having to do with NSViewControllers not being in the responder chain, but also that specifically hooking the action method up in IB should work. The only code I have is this:
In the app delegate:
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
TestController *controller = [[TestController alloc] initWithNibName:#"TestController" bundle:nil];
[self.window.contentView addSubview:controller.view];
}
And, in the TestController class, just this:
-(IBAction)buttonClick:(id)sender {
NSLog(#"%#",sender);
}
I have 2 questions. Why is this happening, and where is the correct mvc place to put IBActions for button methods (shouldn't controller classes handle these)?
First off, I believe in the App Delegate there is already a property called viewController already defined for you. You should use this code self.viewController = [[TestController alloc] initWithNibName:#"TestController" bundle:nil]; instead of TestController *controller = [[TestController alloc] initWithNibName:#"TestController" bundle:nil];. If that doesn't fix it, then I'm not sure what's wrong. Your code should return the attributes of the button you clicked. I created my own sample project and tested out your code (although my app delegate looked different than yours) and it worked fine.
Second, you should elaborate on your second question "Why is this happening, and where is the correct mvc place to put IBActions for button methods (shouldn't controller classes handle these)?". It's not very clear what you mean.
Hope this helps a little.
NSViewController will not respond to IBActions on mac os x on iPhone It is the correct place to put your IBAction as the view should only draw its content (data) not change it. But on Mac os x the NSViewController is for setting up the NSView it's no ment to respond to IBActions you have two choices one is to put your IBAction in your NSView or is create a NSWindowController .
On mac osx you have plenty of screen space and you will alway have views within a window you'll use NSViewController to add them to your window and to setup your view but the window is first in your responder chain then your NSWindowController . eg: you may have one window and two view controller showing the same view which may have 5 test fields in it and view controller one loads that with data but you can not edit the data then view controller two loads the same view with the same data but enable editing for the text fields so. but all action methods will go to the WindowController .
I recommend you to check your viewController's identity inspector.
It may indicate wrong custom class.
viewController created basically usually has name ViewController on the section.

Presenting a view controller modally - iPad

I found this code to display a modal view:
- (void)add:(id)sender {
// Create the root view controller for the navigation controller
// The new view controller configures a Cancel and Done button for the
// navigation bar.
RecipeAddViewController *addController = [[RecipeAddViewController alloc]
initWithNibName:#"RecipeAddView" bundle:nil];
addController.delegate = self;
// Create the navigation controller and present it modally.
UINavigationController *navigationController = [[UINavigationController alloc]
initWithRootViewController:addController];
[self presentModalViewController:navigationController animated:YES];
// The navigation controller is now owned by the current view controller
// and the root view controller is owned by the navigation controller,
// so both objects should be released to prevent over-retention.
[navigationController release];
[addController release];
}
My question is how do I implement this code (I'm going to place it in a buttonPress method)
Do I need to define anything in my header file? The bit that confuses me is that apple on provides this and no header file so i cant tell if anything should be there?
The code refers to RecipieAddViewController what do I repleace this with, "UIViewController" ?
What do I put as the delegate in the headerfile ? do I need to set this up anywhere else ? like with a property?
Is there anything else I need to do once I have copid this code in my buttonPress method to make it work?
Thanks and sorry for all the questions.
My question is how do I implement this code (I'm going to place it in a buttonPress method)
Define the method as an IBAction like -(IBAction)add:(id)sender and in interface builder bind a button's touch up inside event to the view controller object's add: action outlet.
Do I need to define anything in my header file? The bit that confuses me is that apple on provides this and no header file so i cant tell if anything should be there?
Nope. All this stuff needs is UIKit.h You usually need to change your header to add methods, add instance variables, or include custom classes. You may need a #import RecipeAddViewController.h somewhere (in your header or your implementation file) in order to use that class, however. This is true for any custom class you write that you want to use in another file.
The code refers to RecipieAddViewController what do I repleace this with, "UIViewController"?
Replace that with the view controller class you want to push. UIViewController itself is rarely useful naked. It's made to subclassed. So you create a new class that inherits from UIViewController, import it's header, create and instance of it, and push it on the navigation controller.