Xcode 4.2 & Storyboard, how to pass data between views? Existing code error - iphone

I'm trying to learn how to pass data between views. Say set a label in the second view from text entered into a text field on the first view. I basically have tried making a string in the second view and then when switching from the first view to the second I set a string in the second view. Then when the second view loads its sets the text of a label to the same string. I NSLog right before and after the transition, before its fine, but when the second view loads it string gets erased. I'm not sure why this isn't working. Here is my project: http://www.mediafire.com/?83s88z5d06hhqb5
Thanks!
-Shredder2794

From my book (http://www.apeth.com/iOSBook/ch19.html#_storyboards):
Before a segue is performed, the source view controller is sent prepareForSegue:sender:. The view controller can work out what segue is being triggered by examining the segue’s identifier and destinationViewController properties, and the sender is the interface object that was tapped to trigger to the segue (or, if performSegueWithIdentifier:sender: was called in code, whatever object was supplied as the sender: argument). This is the moment when the source view controller and the destination view controller meet; the source view controller can thus perform configurations on the destination view controller, hand it data, and so forth.
(Of course another solution is "don't use a storyboard". Then the first view controller creates the second and can hand it data then and there.)
The reverse problem is much trickier; look at the Utility Application template for an example of how to use the delegate pattern.

StoryBoards are ready made things where you can reduce a lot of code you write.So consider controller A & B on storyboard.
Now for passing data From A to B you can connect them with a segue name its identifier and then you can use delegate methods in A as:
//This method gets called before transition from A to B.
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([[segue identifier] isEqualToString:#"THE IDENTIFIER YOU NAMED"])
{
id *objectOfController_B = [segue destinationViewController];.
objectOfController_B.lblTextDisplayOfA = //Something...
}
}
Now You can Explicitly transition it by using button in controller A.
- (IBAction)buttonPressed:(id)sender
{
[self performSegueWithIdentifier:#"THE IDENTIFIER YOU NAMED" sender:sender];
}
So I guess you can try experimenting on this and you will get it how and when transition occurs with segue.
Hope this helps.

There appear to be more than a few things to explain. I think working through a few tutorials will give you the answers you need. See http://www.raywenderlich.com/tutorials

i've asked more or less the same question a few weeks/month ago. there were some very good answers, especially the one from zoul, who built a demo project that will show you how to create a factory pattern application that will provide the views with the needed objects.
my question can be found here: iOS: Initialise object at start of application for all controllers to use and have a look at the answer from 'zoul'. it got me through this problem =)
good luck trying it out =)
sebastian

I spent "countless hours" my self trying to find a way to pass data and understand delegates with no comprehension and very little success. This video did something that all the other references I checked didn't do : keep it as simple as possible while clearly showing what was needed. Thank you so very much Mr Rob Smythe. http://www.youtube.com/watch?v=XZWT0IV8FrI

Have a look at this: http://iosdevelopertips.com/objective-c/the-basics-of-protocols-and-delegates.html
Delegate pattern is a common way to achieve what you are trying to do.

Related

Connect action of a XIB loaded from a custom class to a storyboard

I'm trying to create a reusable component to display some photo collection.
The basic flow is the following :
First view : View. It contains my so called library, designed programmatically and loaded from storyboard by assigning a custom class
I take a photo in a modal view, openend from the 'take picture' button
Once the photo is saved on disk, I ask PhotoLib to create a new PhotoCell from the photo path
I would like my PhotoCell to be touch enabled so when I tap it, it opens the second view in a modal way, but from what I read I cannot do this from my PhotoCell or the UIImageView inside (not a controller).
So how can I do ? View is embedded in a NavigationController, even if not shown in the screenshots below.
Thank you !
If you create Photocell in photolib, then photolib should implementing delegate methods from photocell. But photolib itself is not rootviewcontroller, so it should declare delegate methods itself, and the containing view should implement it.
Basically you pass Photocell from itself to Photolib (which implements delegate method
-(void) openPhotoCell:(Photocell*)cell
{
[self.delegate openPhotocell:(Photocell*)cell];
}
, then it passes it to View, which in its turn opens it.
It may seem like pulling a tooth from an ear, but actually it's quite working and if you write good self-explanatory code, it's not a problem. I'm currently working on some big project with tens views and controllers and it works pretty good and nobody has problem with that.
If you have more layers, then maybe you should look into NSNotification.
Hope it helped, I'd be glad to explain more.
UPD:
Links:
about delegates in cocoa fundamentals guide
delegation pattern in wikipedia

Xcode : Storyboard and retaining data in each controller

As you can guess i am a new programmer and i have trouble getting a simple thing!
I am making an app with multiple view controllers. Each controller have textfields and UIsegmentedControl items. When i am moving from one view controller to the other (uding modal trantition if that matters), the contents of the previous one (textfield entries and segmented control option) reset to their original state. How can i make them keep their previous state?
Thanks in advance.
-(void) prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{
bViewController *deneme = [segue destinationViewController];
[deneme setPassedValue:label.text];
}
This piece of code will solve your problem, I hope. It saves the label of whatever is inside of it. And you need to add some more code to other classes.
If this code helps you tell me and I can give you the whole code.
To save the application state you can use a model class, following the recommended MVC (model-view-controller) paradigm.
More information here: Retain view state upon reloading
As an alternative you could use the viewWillDisappear: event to save your view state, and then restore it on the viewWillAppear: event.
The viewWillDisappear: event is fired right before the view is going to disappear, and viewWillAppear: is fired before the view is put on the foreground, being ideal to make any changes to the UI.
These events might have already been declared for you in your view controller, but in case they're not check the prototypes here: http://developer.apple.com/library/ios/#documentation/uikit/reference/UIViewController_Class/Reference/Reference.html
You can also use a navigation controller to move from one view to another.
This way, you will push your new view on top of the previous one, and when you go back, the previous view has kept its state.
see this tutorial for more information on storyboard and UINavigationController :
http://www.raywenderlich.com/5138/beginning-storyboards-in-ios-5-part-1

How to set the delegate to another ViewController?

I've recently started developing for the iPhone and so far I'm doing pretty good but there's this basic pattern I really don't seem to get.
Say, I have a TabBar with two views and a custom delegate protocol, thus my structure is the following:
AppDelegate.h/.m
myDelegateProtocol.h
FirstViewController.h/.m
SecondViewController.h/.m
MainView.xib
FirstView.xib
SecondView.xib
Now I want to achieve the following: I placed a button in the FirstView.xib and I'd like the IBAction which it invokes (inside FirstViewController ofc.) to send a message to the SecondViewController ([self.delegate tellSecondViewContrToSayHi]) and invoke another method which simply prints a log into the console saying "hi I'm here."
So far I know what I need to do in theory:
Specify the protocol.
Implement the protocol in the SecondViewController.
Create an id< myDelegateProtocol > delegate inside my FirstViewController,...AND last but not least:
Set the self.delegate = secondViewControllerObject.
Now, nr.4 is where the problem's at. How on earth do I link the delegate to the other viewController? I mean I'm not the one instantiating the views as the tabBar kinda does that for me,... any advise? Or am I just way too tired to notice a really stupid thing I did somewhere?
Theoretically the same question also applies to the target:action: thing,... I mean, how do I define the target?
Thanks a lot,
wasabi
You have the right idea, assuming that you want relatively tight coupling between these controllers via that delegate protocol.
Since neither controller knows about the other until that delegate property is set you need to have some object which has a reference to both of them wire up that relationship. In your case that's probably the application delegate which can create both controllers, set one as the delegate of the other, and pass both along to your tab bar controller.
What you might actually want is to have the app delegate give both controllers a reference to some shared model object. Your FirstViewController can update that model when you tap a button and your SecondViewController can observe changes to the model to update it's display (or just update its view when it appears based on the current model state). That way your controllers don't need to know anything about each other.

Calling NSXMLParser based on navigation direction

I have an navigation-based app with three view controllers. The first has categories of information, the second has a list of items from that category and the third has detail on a specific item.
I populate view controllers 1 and 2 using an NSXMLParser which gets called on viewWillAppear. In the forward (VC1 to VC2 to VC3) direction, everything is fine, the parser gets called and the views are populated.
Unfortunately when the user chooses the back button on the navigation bar, the same process happens in reverse (VC3 to VC2 to VC1) as viewWillAppear is called again and so the parser is also called, even though it just fetches the same data.
I want to ensure that the parser is only called in the forward direction. Any ideas how I might structure this?
Thanks, Phil
Could you do something as simple as having a BOOL ivar called goingForward on VC2 that gets set to YES by VC1 prior to -pushViewController:animated: call and set to NO by VC3 prior to -popViewControllerAnimated: ... and then check goingForward in VC2's -viewWillAppear?
I am sure that there are more elegant ways of doing this (and look forward to reading about them) - but this should work, don't you think?

self.view = aViewController.view vs [aViewController loadView] -

I am trying to understand the behavior of view controllers when switching from one to another (displaying different views)
A part form the addSubiew statements which seem to work, I can't find an explanation to what happens with the two statements:
self.view = someViewController.view;
[someViewController loadView];
In fact I got a case where only the first one seems to work (the view defined within someViewController is displayed) and in another case only the second one.
More precisely, from the root viewController.view to anotherViewController.view (already istantiated) I have to use the first one, to come back I need to use the second one.
I can't understand what can it be the difference in the current situation which allows one or the other statement to work.
Thank you
It's very hard to even understand your question. But I'm gonna try to answer it:
The iPhone OS uses a stack of views and display the first one to the users.
You either pop (remove) or push (add) views to this stack.
The code you provided is somewhat "obscure". The best pratice to gain control is to add SubViews to your window or any other view
i.e. [window addSubview:viewController.view];
Don't override your current view by using self.view = someViewController.view;
Instead initialize your new ViewController and add it's view to the subview of your current view.
Any questions? Just comment.
Looks like you have some misconceptions about how view controllers work.
There are a couple things wrong with those 2 statements:
self.view = someViewController.view;
According to the docs of UIViewController.view :
"Each view controller object is the sole owner of its view. You must not associate the same view object with multiple view controller objects." -Apple Docs
Once that line of code executes, the view would have 2 different controllers, which is bad.
Next line:
[someViewController loadView];
This is bad because you should never explicitly call loadView.
From the docs of UIViewController.loadView :
"You should never call this method directly."
From the docs of UIViewController.view :
"If you access this property and its value is currently nil, the view controller automatically calls the loadView method and returns the resulting view. "
Spend some time with the viewController tutorials and guides such as "View Controller Programming Guide for iPhone OS". They are good docs and can teach a lot.