1

I'm writing a little quiz application. So I have a first view, where I ask a person to enter his/her name and a button which is the IBAction to go the next view with the first question. In the end, after a person has answered all questions, comes the congratulations view, where I want to copy the name, that was entered on the first view. Say there will be a phrase "Well done, John!" How can I do it?

On the first view(FirstViewController) I made a textfield

IBOutlet UITextField *text1;

And on the last view in .h:

IBOutlet UITextField *text2; 

and

-(IBAction)copy:(id)sender;

And in .m:

- (IBAction)copy:(id)sender
{
    [text2 setText:[text1 text]];
}

and

#import "FirstViewController.h"

But it says identifier text1 is undefined

I don't know what else to do...

Paras Joshi
  • 20,427
  • 11
  • 57
  • 70
Ann
  • 475
  • 1
  • 5
  • 14

7 Answers7

0

Override the init method of SecondViewController as follows

-(id)initWithUsername:(NSString *)username
 {
      //create instance and then do 
      text2.text = username ;
 }

And in the FirstViewController , where you create the instance of SecondViewController init it using the above

  SecondViewController *second = [[SecondViewController alloc] initWithUsername:text1.text]; 
Subbu
  • 2,063
  • 4
  • 29
  • 42
0

For passing value from one VC to other you have to do following code :

  1. First declare local variable in next view where you want to move like.

    @property(nonatomic, strong) NSString *personName;
    
  2. Now prepare object of second VC in the first VC.m file on button click action. But before that must set storyboard identifier of that second VC in storyboard.

    SecondViewController *obj = (SecondViewController *) [self.storyboard instantiateViewControllerWithIdentifier:@"SecondViewController"];
    obj.personName = self.txtUserName.text;
    
  3. Now go on there on second VC and do whatever you want.

    Note : Here you don't need to used userdefaults, OR prepared init methods with parameters, OR using delegates etc.

Pavan Gandhi
  • 1,729
  • 1
  • 22
  • 36
0

You can override the

        - (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil

method of last view controller with something like:

        - (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil andUserName:(NSString*)userName

(don't forget to declare this method in your .h file.)

Now while initializing your last view controller, you can pass the name of the user to last view controller.

In the implementation of the this overriden method in last view controller, copy this name in some local variable. and use it.

Hope this will solve your problem.

Pravara Patil
  • 513
  • 1
  • 3
  • 10
  • The problem with this is that you would be required to pass along the name to each intermediary view controller just so you could pass it to the last one, which is bulky, in my opinion. – CIFilter Sep 21 '11 at 13:50
  • Yes, I agree. this solution is applicable if you need to communicate values between two immediate view controllers – Pravara Patil Sep 21 '11 at 13:58
0

In your firstView add NSString with its property
Something like this in .h file

NSString *username;

and

@property (nonatomic , retain) NSString *username;

in .m file

username = text1.text;

In LastView
im .m file

#import "FirstView.h"

And where ever you want username try this

FirstView *firstview = [[FirstView alloc] init];
text2 = firstview.username;

Hope it works..!!

iUser
  • 1,075
  • 3
  • 20
  • 49
  • You're trying to get `username` from a newly created `FirstView` instance, which is different than the one in which the user has inserted text. You can however get the `FirstView` by looping in the view hierarchy (if it wasn't popped out). – alex-i Sep 21 '11 at 14:30
-1

The best way to do this would be taking the variables you need on various views and handling them on the delegate since the delegate has access to everything. Making a Global variable is never advisable that is what the delegate is for.

You can refer to this question that treats the same issue: Passing data between view controllers

Community
  • 1
  • 1
Jose Luis
  • 3,307
  • 3
  • 36
  • 53
  • Accessing the app delegate is the same, conceptually, as using a global variable. The app delegate should *not* be used to store data. The approach you're suggesting, while seemingly convenient at first, quickly becomes a mess if you keep abusing it. – CIFilter Sep 21 '11 at 13:47
  • Could you please explain in details? I'm really dummy) – Ann Sep 21 '11 at 13:50
  • You will always have the delegate and the delegate is the one that manages the controllers. It is NOT the same as a global variable it is one of its meant functions. [Using generic dataObject in Delegate](http://www.iphonedevsdk.com/forum/iphone-sdk-development/54859-sharing-data-between-view-controllers-other-objects.html) It is the most logical approach. Doing a Singleton is dangerous and memory consuming. Sure downvote me, but if you want to be fair you have to downvote babbidi aswell. – Jose Luis Sep 21 '11 at 13:52
  • @Ann See my answer about using `NSUserDefaults`. It's probably what you want. – CIFilter Sep 21 '11 at 13:52
  • @Joze Nowhere in Apple's documentation or design patterns do they suggest using the app delegate to store your application's data. The delegate is simply meant to respond to application lifecycle events, not be an intermediary that every class accesses for common data. – CIFilter Sep 21 '11 at 13:54
  • @Ann The delegate has access to all controllers and all controllers have access to the delegate. You need to declare a variable in the delegate (the variable you need) and then access it with a method defined in your controller. This link has an example of how to achieve this: [Example](http://www.iphonedevsdk.com/forum/iphone-sdk-development/54859-sharing-data-between-view-controllers-other-objects.html) – Jose Luis Sep 21 '11 at 13:55
  • @Joze You are incorrect. The app delegate only has access to the controllers you specify. It cannot reach out to arbitrary view controllers. You shouldn't be making suggestions that result in bad design pattern usage. – CIFilter Sep 21 '11 at 14:02
  • This question talks about the proper use of the app delegate: http://stackoverflow.com/questions/338734/iphone-proper-usage-of-application-delegate – CIFilter Sep 21 '11 at 14:06
  • Encouraging singletons is very dangerous. If you can avoid it don't do it. If you really need the interaction of many variables then you have to, meanwhile stick with the delegate. I don't like the feeling of an instance using up memory permanently and never being released. There is stated the usage of delegates but it encourages singletons and I simply don't agree with that. Use singletons if you have to a god like class is just dangerous.[GodObject](http://en.wikipedia.org/wiki/God_object) – Jose Luis Sep 21 '11 at 14:09
-1

You can add a NSString member (along with a property) in the application delegate class.

/// AppDelegate.h, or whatever it's called in your application
@interface AppDelegate : NSObject <UIApplicationDelegate> {
    NSString *username;
    // <rest of the members>
}
...
@property (nonatomic, retain) NSString *username;
@end

/// AppDelegate.m
@implementation AppDelegate
@synthesize username;
@end

/// FirstViewController.m
-(void)viewDidDissappear:(BOOL)animated{
    [super viewDidDissappear:animated];
    AppDelegate *appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
    appDelegate.username = text1.text;
}

/// LastViewController.m (or whatever it's called)
-(void)viewDidLoad{
    [super viewDidLoad];
    AppDelegate *appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
    [text2 setText:[NSString stringWithFormat:@"Well done %@", appDelegate.username]];
}

Ok, so for everyone to be happy, you can (and are suggested to) create your own singleton class in which you can hold non-persistent global variables, and use in the code above instead of the application delegate.

/// SharedData.h
@interface SharedData: NSObject {
    NSString *username;           /// or instead you can have a NSMutableDictionary to hold all shared variables at different keys
}
+(SharedData *)sharedInstance;

@property(nonatomic, retain) NSString *username;
@end

/// SharedData.m
#include "SharedData.h"

static SharedData *_sharedInstance=nil;
@implementation SharedData
@synthesize username;
+(SharedData)sharedInstance{
    if(!_sharedInstance){
        _sharedInstance = [[SharedData alloc] init];
    }
    return _sharedInstance;
}
@end
alex-i
  • 5,406
  • 2
  • 36
  • 56
-2

I would make use of NSUserDefaults to set the user's name when they enter it. Then, in your last view controller, just query NSUserDefaults again for the name you want. Granted, this is still global state, but NSUserDefaults is meant for this sort of purpose:

// In the first view controller

NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
[userDefaults setObject:@"John Doe" forKey:@"XXUserNameKey"];       // This should actually be an extern for your app to use globally

// In the last view controller

NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
NSString *userName = [userDefaults stringForKey:@"XXUserNameKey"];

Adding state to your app delegate is an abuse of the design pattern.

Also, I should clarify that NSUserDefaults should not be used as a general-purpose storage container. Its intent is for common, shared data like user names, preferences, etc. Something like the name a user enters at the beginning of a game seems to fall within the usage pattern.

CIFilter
  • 8,647
  • 4
  • 46
  • 66
  • If your data includes custom classes, this will not work. You'd have to convert those objects to something that could go into NSUserDefaults - like a dictionary - and then convert back on the other end. Not worth the effort, and will be significantly slower than simply passing a reference. – Jose Luis Sep 21 '11 at 13:55
  • Plus NSUserDefaults is awfully slow it is like scratching your back with your feet. It has no sense. Using the delegate is elegant and simple. – Jose Luis Sep 21 '11 at 13:57
  • @Joze Just because your suggestion is not correct shouldn't invalidate mine. You have no basis for claiming that `NSUserDefaults` is slow. – CIFilter Sep 21 '11 at 14:00
  • I am not only saying and KNOWING that it is slow, I voted based on the fact that NSUserDefault can't always be used against the always usability of the delegate. – Jose Luis Sep 21 '11 at 14:05
  • 1
    @LucasTizma While I agree that the delegate can get messy, there's no reason why shared data can't be kept in the application delegate. `NSUserDefaults` is designed to make data persistent, not to make global variables inside the application. – alex-i Sep 21 '11 at 14:09
  • @babbidi The reason is exactly because it will get messy. Once your app has hundreds of references to the app delegate to pass data around, you're in big trouble. I don't understand why people recommend violating a design pattern this way, just because it's easy. – CIFilter Sep 21 '11 at 14:11
  • 1
    @LucasTizma you're actually doing the same thing, use `NSUserDefaults` (`[NSUserDefaults standardUserDefaults]`) just because it's a singleton. – alex-i Sep 21 '11 at 14:18