UIView/UIViewController accessing a textfield

Discussion in 'iOS Programming' started by whitehexagon, Jun 11, 2009.

  1. whitehexagon macrumors regular

    whitehexagon

    Joined:
    May 12, 2007
    #1
    in my view I only have a single textfield

    IBOutlet UITextField *textfield;

    I push my view controller onto a naviagation controller, with a couple of custom buttons added in the navigation bar on viewDidLoad in the controller..

    My question is: what's the preffered approach to working with the text field value? It seems logical to put (for example) save logic into the controller code. But then I need to somehow get the value from the view... should I implement a public method in the view or can I access the textfield from the controller in some better way? What's the best approach there?

    I'm still trying to get around the view/view controller approach used by Apple. Somehow UIView seems a bit redundant if all it contains are the IBOutlets.
     
  2. johnnyjibbs macrumors 68030

    johnnyjibbs

    Joined:
    Sep 18, 2003
    Location:
    London, UK
    #2
    See my post on the other thread regarding the text field becoming first responder.

    It's best not to call your text field textField as many of the delegate methods use this as a local declaration and you could run into problems.

    Best to call it myTextField/theTextField/aTextField or maybe something specific like usernameTextField, etc.

    About the views, remember that Interface Builder is not required for building an app so it's not all about IBOutlets.

    UIViews are extremely useful and fundamental to an app. All widgets and UI elements are actually subclasses of UIViews, including text fields. The UIView class defines many of the useful properties such as frame, bounds, size, background colour, etc. But you can also use 'container' views to position things nicely. So, for example, a toolbar is a view that other views such as buttons may be placed on. If you move the toolbar, you'll want to move all its subviews (such as buttons and labels) with it and this is taken care of automatically. Container views can also be invisible in that they just act as ways of grouping objects together. Scroll views are views to move all the content inside (all subviews) around the screen. Views also handle all the touch events via the inheritence of the UIResponder methods.

    Keeping track of all these views can get messy, so it is the job of the view controller to keep it all together. Most apps will rely on subclassed view controller objects (generally one for each screen, but it doesn't strictly have to be that way) to keep track of the views on a particular screen and respond to events appropritately. Your view controller can handle the text field's text output by adopting the UITextFieldDelegate protocol and then storing the output in an NSString variable.

    Use the following method to handle outputting the text field output, resigning it as first responder (to dimiss the keyboard) and store the text output in an instance variable:
    Code:
    - (BOOL)textFieldShouldReturn:(UITextField *)textField {
       // check that we have the right text field
       if (textField == myTextField) {
           self.textOutputString = textField.text
           [textField resignFirstResponder];
       }
       // we want to allow the text field to dismiss by returning a yes
       return YES;
    }
    
    In the above example, the text output is stored in an NSString instance variable called textOutputString in the main view controller.
     
  3. whitehexagon thread starter macrumors regular

    whitehexagon

    Joined:
    May 12, 2007
    #3
    Thanks for the detailed response to both posts. I'll try to keep the discussions separate.

    I think my problem is more fundamental understanding of accessing the myTextField value defined in the view, from myExtendedViewController.

    So in my controller I overide/implement:
    Code:
    - (void)viewDidLoad {
      [super viewDidLoad];
      self.navigationItem.rightBarButtonItem = [[[UIBarButtonItem alloc]
          initWithBarButtonSystemItem:UIBarButtonSystemItemSave 
          target:self 
          action:@selector(save)] autorelease];	
    And then I'd like to define my save method in the same place (since I'm not using an Action back onto a view method)
    Code:
    - (void) save{
    	NSLog(@"SAVE value:%@", [self.view.myTextfield text]);  //i know this doesn't work, but it's what I'm trying to do
    }
    So I can implement an accessor on the view to return back the string value ready for saving. or would I be better to return the reference for the TextField (eg for use with first responder setting). Or is there a way to reference the instance variable directly from the view, as in my non working save example.
     
  4. johnnyjibbs macrumors 68030

    johnnyjibbs

    Joined:
    Sep 18, 2003
    Location:
    London, UK
    #4
    I think you may be confusing the Model-View-Controller paradigm. The text field instance variable is an instance variable of the view controller, not its view.

    So in your save method, you would want to call this instead:

    Code:
    - (void) save{
    	NSLog(@"SAVE value:%@", [self.myTextField text]);
    }
    Note that myTextField belongs to the view controller (self), not the view controller's main view.
     
  5. whitehexagon thread starter macrumors regular

    whitehexagon

    Joined:
    May 12, 2007
    #5
    Yes that could very well be the case. I've been working through some examples from 'The iPhone developers cookbook' were the IBOutlet instances have so far been defined in the view header. I think it's back to the manuals then for how I should actually have defined by xib /controller / view relationship.
     
  6. johnnyjibbs macrumors 68030

    johnnyjibbs

    Joined:
    Sep 18, 2003
    Location:
    London, UK
    #6
    Just remember that the view controller is simply an object that manages the views on a particular 'page' of the screen. It is not a view itself, although it initialises its own UIView object the size of the screen by default (an internal instance variable), which normally needs to be hooked up in the Interface Builder. Views themselves are graphical objects at a certain position on the screen and should not really act as controllers themselves.

    You do not generally need to make subclasses of views very often, unless you want some custom drawing code, etc, but the view controller is the most commonly subclassed class in an iPhone application.

    For a simple single screen app using Interface Builder the general steps are as follows:
    1. Create a custom UIViewController object to manage your screen in Xcode (this may have been done for you from the template - e.g. RootViewController)
    2. Create a view nib template in Interface Builder (normally defined for you if you choose one of the application templates)
    3. In IB, change the File Owner object to your custom view controller name and hook up the view property
    4. Define any views as IBOutlets in your view controller program
    5. Hook up these outlets to their corresponding objects in IB (e.g. text fields etc)
    6. Complete coding to implement desired functionality
     
  7. whitehexagon thread starter macrumors regular

    whitehexagon

    Joined:
    May 12, 2007
    #7
    defining the text field outlet in the controller solved the access issue, think I'm going to bin this book! :)
     

Share This Page