Configuring the DetailController View

Goal: Add the user interface to the customer detail view and specify the outlets in the DetailController.m and DetailController.h files.

  1. Click the DetailController.xib file to open Interface Builder.
  2. Select View > Utilities > Object Library. In the Object Library panel, select the Text Field item, drag it onto the view three times to create three text fields aligned vertically to the right of the screen.
    You can resize the text fields using the resize handles and position the button by dragging it to the desired location.
  3. In the Object Library panel, select the Label item, drag it onto the view three times to create three labels to the left of and aligned with the three text fields. Replace the default Label text with:
    • First Name
    • Last Name
    • Phone
  4. In the Object Library panel, select the Round Rect Button item, drag it onto the view, and rename it to Submit.
    To make connections to the user interface from the view controller, you must specify outlets in the DetailController.h file and add property declarations for the instance variables and a declaration for the action method.
  5. Open the DetailController.h file and replace the existing code with the provided code.
    #import <UIKit/UIKit.h>
    #import "SUP101_Customer.h"
    
    @interface DetailController : UIViewController {
    }
    
    @property (nonatomic, retain) IBOutlet UITextField *fname;
    @property (nonatomic, retain) IBOutlet UITextField *lname;
    @property (nonatomic, retain) IBOutlet UITextField *phone;
    @property (nonatomic, retain) SUP101_Customer *originalObj;
    @property (nonatomic, retain) IBOutlet UIButton *submitButton;
    
    -(IBAction)buttonPressed:(id)sender; 
    
    @end
    
  6. Click the DetailController.m file and replace the existing code with the provided code.
    #import "DetailController.h"
    #import "SUP101_SUP101DB.h"
    #import "SUP101CallbackHandler.h"
    
    @implementation DetailController
    @synthesize fname, lname, phone, originalObj, submitButton;
    
    // The designated initializer.  Override if you create the controller programmatically and want to perform customization that is not appropriate for viewDidLoad.
    //- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
    //    if ((self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil])) {
    //        // Custom initialization
    //    }
    //    return self;
    //}
    
    - (void) onReplaySuccess:(NSNotification *)notification
    {
        // 'replay success' means the server accepted the changes. Refresh
        // the in-memory object so it's in sync with the local database,
        // and re-enable the submit button so additional changes can be made.
        SUP101_Customer *successObj = (SUP101_Customer *)[notification object];
        if (successObj.id_ == self.originalObj.id_) {
            [self.originalObj refresh];
            self.submitButton.enabled = YES;
        }
    }
    
    - (void) onReplayFailure:(NSNotification *)notification
    {
        // 'replay failure' means the server rejected the changes. Refresh
        // the object from the local database and restore the text fields,
        // and re-enable the submit button so additional changes can be made.
        SUP101_Customer *failedObj = (SUP101_Customer *)[notification object];
        if (failedObj.id_ == self.originalObj.id_) {
            [self.originalObj refresh];
            fname.text = originalObj.fname;
            lname.text = originalObj.lname;
            phone.text = originalObj.phone;
            self.submitButton.enabled = YES;
        }
    }
    
    - (IBAction)buttonPressed:(id)sender
    {
        
        if (([lname.text compare:originalObj.fname] != NSOrderedSame) ||
            ([fname.text compare:originalObj.lname] != NSOrderedSame) || 
            ([phone.text compare:originalObj.phone] != NSOrderedSame))
        {
            SUP101_Customer *newCustomer = [SUP101_Customer find:[originalObj id]];
            if (newCustomer) {
                newCustomer.lname = lname.text;
                newCustomer.fname = fname.text;
                newCustomer.phone = phone.text;
                
                // After saving changes and sending them to the server
                // disable the 'submit' button so the object won't be changed
                // while there are pending changes.
                [newCustomer save];
                [newCustomer submitPending];
                [sender setEnabled:NO];
            }
            
        }
        
    }
    
    /*
     // Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
     - (void)viewDidLoad {
     [super viewDidLoad];
     }
     */
    
    
    // Override to allow orientations other than the default portrait orientation.
    - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
        // Return YES for supported orientations
        return (interfaceOrientation == UIInterfaceOrientationPortrait);
    }
    
    - (void)viewWillAppear:(BOOL)animated {
        fname.text = originalObj.fname;
        lname.text = originalObj.lname;
        phone.text = originalObj.phone;
        
        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onReplaySuccess:) name:ON_REPLAY_SUCCESS object:nil];
        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onReplayFailure:) name:ON_REPLAY_FAILURE object:nil];
    	[super viewWillAppear:animated];
    }
    
    - (void)viewWillDisappear:(BOOL)animated {
        [[NSNotificationCenter defaultCenter] removeObserver:self];
        [super viewWillDisappear:animated];
    }
    
    - (void)didReceiveMemoryWarning {
    	// Releases the view if it doesn't have a superview.
        [super didReceiveMemoryWarning];
    	
    	// Release any cached data, images, etc that aren't in use.
    }
    
    - (void)viewDidUnload {
    	// Release any retained subviews of the main view.
    	// e.g. self.myOutlet = nil;
    }
    
    - (IBAction)touchesEnded:(NSSet*)touches withEvent:
    (UIEvent*)event
    {
        UITextView* fname1 = (UITextView*) [[self view] viewWithTag:
                                            1];
        UITextView* lname1 = (UITextView*) [[self view] viewWithTag:
                                            2];
        UITextView* phone1 = (UITextView*) [[self view] viewWithTag:
                                            3];
        [fname1 resignFirstResponder];
        [lname1 resignFirstResponder];
        [phone1 resignFirstResponder];
    }
    
    - (void)dealloc {
        self.originalObj = nil;    
        [super dealloc];
    }
    
    
    @end
    
  7. Click the DetailController.xib file to open it in Interface Builder, click the First Name text field, and select View > Utilities > Attributes Inspector.
  8. In the Attributes Inspector panel , scroll to the View section and enter 1 in the Tag field.
  9. Set the tags for the Last Name and Phone text fields to 2 and 3 respectively.
  10. Control-drag from the File's Owner icon in the middle pane to each of the text fields and select the fname, lname, and phone outlets respectively to create connections between the text fields and the outlets defined in the DetailController.m file.
  11. Select View > Utilities > Connections Inspector to confirm that the outlets have been correctly configured:

    iphone_custdetail_text_connect
  12. Control-drag from the File's Owner icon in the middle pane to the Submit button and select submitButton.