Archive for category Development

Sharing Information Between Views

One of the most common questions in the Getting Started section of Apple’s Developer Forums is, “How do I edit information in one view and update another using it?” Sometimes it’s expressed instead as how to compare or save information in different views but it’s really the same question. There are two answers: the expedient one and the good one. Before I get to either of those, however, I’d like to set up a sample situation.

The Problem:
I’m going to work with a project that’s created using the standard iPhone Tab Bar Application template, using Xcode 4.0.2. It defaults to having two view controllers and my plan is to have the first one be a data display screen while the second is a data editing screen. (Note: My latest build of this works on Xcode 4.5.2 and iOS 6.0 with conversion to ARC.)

To prepare for this, I edit the supplied .xib files so that FirstView.xib has only a UILabel element inside its view and SecondView.xib has only a UITextField element inside its view. I then modify the related code files for the view controllers to define and synthesize properties that match the label and the text field. Finally, within the .xib files, I make the connections between the File’s Owner properties that were just created in code and the visual elements.

Usually, this is the state the person has reached when they ask the question. If they haven’t made it this far, the questions are more likely to be about how to use Interface Builder.

The Expedient Solution:
This addresses the problem as a lack of understanding about objects. The point that’s being missed is that objects need to have references to other objects while the program is running in order to communicate. Since I want my view controllers to communicate with each other, one of them must have a reference to the other. I could have my editor update the display whenever data changed but, for a variety of reasons, I prefer the idea of the display being in control of its own content.

Within the code for the FirstViewController, I create a property that references a SecondViewController object and synthesize it. Instances of both controllers exist inside MainWindow.xib so I connect the new property of the first controller to the SecondViewController instance.

The last step is to write code so that the FirstViewController can obtain the most recent information whenever it is about to be displayed…and that is now trivial.

Relevant controller code:

//  SecondViewController.h

#import <UIKit/UIKit.h>

@interface SecondViewController : UIViewController <UITextFieldDelegate> {
}

@property (nonatomic, retain) IBOutlet UITextField *dataEditor;

- (NSString *)editedText;

@end

// SecondViewController.m

#import “SecondViewController.h”

@implementation SecondViewController

@synthesize dataEditor;

- (BOOL)textFieldShouldReturn:(UITextField *)textField {
    [textField resignFirstResponder];
    return YES;
}

- (NSString *)editedText {
    if (dataEditor == nil) {
        return @”Not initialized”;
    }
    return dataEditor.text;
}

- (void)dealloc {
    [dataEditor release];
    [super dealloc];
}

@end

// FirstViewController.h

#import <UIKit/UIKit.h>

@class SecondViewController;

@interface FirstViewController : UIViewController {
}

@property (nonatomic, retain) IBOutlet UILabel *dataDisplay;
@property (nonatomic, retain) IBOutlet SecondViewController *dataSource;

@end

// FirstViewController.m

#import “FirstViewController.h”
#import “SecondViewController.h”

@implementation FirstViewController

@synthesize dataDisplay, dataSource;

- (void) viewWillAppear:(BOOL)animated {
    [super viewWillAppear:animated];
    dataDisplay.text = [dataSource editedText];
}

- (void)dealloc {
    [dataDisplay release];
    [dataSource release];
    [super dealloc];
}

@end

The Better Solution:
Here, in addition to thinking about objects, I use a simple implementation of the Model-View-Controller (MVC) object pattern. In the previous solution, the second controller acted as the data model for the application. Programs become much easier to expand and modify when that role is given to objects specifically created for the purpose.

I create a new class called SharedModel and make it a subclass of NSObject. I create a property for it that will hold a reference to a NSString object. (In a real application, the SharedModel could be expanded to serve any amount of data, even remote sites.)

I remove all references to SecondViewController from the first controller and insert properties called ‘dataSource’, that each specify a reference to the SharedModel, into both controllers.

The following is not necessarily the best way to handle the creation of the SharedModel but, for illustration purposes, it works. In MainWindow.xib, I add a NSObject and set its class to SharedModel. I then connect the dataSource property of each view controller to the new SharedModel object in the .xib file.

The last steps are: to add one line of code in the second controller that updates the SharedModel when editing ends, to remove the code from the second controller that reported the edited text to the caller, and to modify the update line in FirstViewController so that it uses the data model instead of the second controller directly.

Relevant controller and model code:

// SharedModel.h

#import <Foundation/Foundation.h>

@interface SharedModel : NSObject {
}

@property (nonatomic, retain) NSString *editedText;

@end

// SharedModel.m

#import “SharedModel.h”

@implementation SharedModel

@synthesize editedText;

- (id)init {
    self = [super init];
    if (self) {
        self.editedText = @”Not updated”;
    }
    return self;
}

- (void)dealloc {
    [editedText release];
    [super dealloc];
}

@end

// SecondViewController.h

#import <UIKit/UIKit.h>

@class SharedModel;

@interface SecondViewController : UIViewController {
}

@property (nonatomic, retain) IBOutlet UITextField *dataEditor;
@property (nonatomic, retain) IBOutlet SharedModel *dataSource;

@end

// SecondViewController.m
#import “SecondViewController.h”
#import “SharedModel.h”

@implementation SecondViewController

@synthesize dataEditor, dataSource;

- (BOOL)textFieldShouldReturn:(UITextField *)textField {
    [textField resignFirstResponder];
    dataSource.editedText = textField.text;
    return YES;
}

- (void)dealloc{
    [dataSource release];
    [dataEditor release];
    [super dealloc];
}

@end

// FirstViewController.h

#import <UIKit/UIKit.h>

@class SharedModel;

@interface FirstViewController : UIViewController {
}

@property (nonatomic, retain) IBOutlet UILabel *dataDisplay;
@property (nonatomic, retain) IBOutlet SharedModel *dataSource;

@end

// FirstViewController.m

#import “FirstViewController.h”
#import “SharedModel.h”

@implementation FirstViewController

@synthesize dataDisplay, dataSource;

- (void) viewWillAppear:(BOOL)animated {
    [super viewWillAppear:animated];
    dataDisplay.text = dataSource.editedText;
}

- (void)dealloc {
    [dataDisplay release];
    [dataSource release];
    [super dealloc];
}

@end

, , ,

1 Comment

Timely: Market Research

For much of my programming career I’ve worked for small companies that were in the process of creating their first commercial software product. Usually, the impetus for creating a product was someone’s idea of what would cause a lot of people to spend money. It was never something that the idea person would spend his or her own money on, and the companies in question weren’t rich or mature enough to actually do research that would demonstrate whether or not the financial assumptions were true.

The immediate result of this mode of operation was requirements that could change at a moment’s notice whenever someone with political clout claimed to know what the mythical customer would want. The longer term results included a series of technical successes that did poorly when they were presented to a market that didn’t care and, in one case, entertaining fluctuations in pricing that ranged — as I remember it — between $0.00 and $1400.00, depending on whether “Software as a Service” was in vogue that day.

This brings me to an iPad program called Timely that I’ve recently uploaded to Apple for approval. I’ve specified, designed, and written it myself…just as I have many other programs in my life. Although I’ve asked some people for their opinions about features, what it contains in its first version is what I need.

See, when I’m not writing code, I’m fairly seriously caught up in my hobby of songwriting, singing, and guitar playing within the filk community.

Timely lets me store and display songs in a variety of formats and then accumulate them into overlapping set lists. It estimates set length as I change my mind while organizing one. It should let me stop carrying many pounds of paper when I go off to conventions, practices, and monthly filk circles. It displays songs by automatically scrolling them so that I don’t have to turn pages or compress song notation into a maximum of two pages. It organizes songs alphabetically and lets me make reference notes about them. It optionally plays a note when a song starts for times when I need a cue.

It’s the program I want and will evolve as my needs evolve and as I see more things I’d like it to do.

It has not been written for customers which may or may not exist and which might number between zero and seven billion. I wish I could have written it for all the people who might find it useful enough to buy it. That would have produced the best focus group, but it’s impossible to do and impractical to simulate. Instead, Timely has been written for one customer which, in my experience, is the second-best number.

5 Comments