Refacoring
If you have completed the iOS Tutorial from the earlier Hello World post, you should have a class named HelloWorldViewController which contains a userName property and a changeGreeting method looking something like this:
As you can see, the model object for the user data in our application is a simple NSString. This works fine for now, but the code will be more flexible if we have a separate model class which encapsulates this information. Let's call it HelloWorldModel:@property (nonatomic, copy) NSString *userName;...- (IBAction)changeGreeting:(id)sender {self.userName = self.textField.text;NSString *nameString = self.userName;...}
As you can see, we have basically just wrapped userName in another class. For convenience, there is also a constructor (initWithName) which takes a name as an argument.
@interface HelloWorldModel : NSObject@property (nonatomic, copy) NSString *userName;- (id)initWithName:(NSString *)name;@end@implementation HelloWorldModel@synthesize userName;- (id)initWithName:(NSString *)name {self = [super init];if (self) {[self setUserName:name];}return self;}@end
Next is to hook this model back into our app. This means replacing the userName field of the HelloWorldViewController class with a field of our own model type, and updating the changeGreeting method accordingly:
(Deleted lines are shown in
@property (nonatomic, copy) NSString *userName;@property (strong, nonatomic) HelloWorldModel *model;...- (IBAction)changeGreeting:(id)sender {self.userName = self.textField.text;NSString *userInput = [self.textField.text];self.model = [[HelloWorldModel alloc] initWithName:userInput];NSString *nameString = self.userName;NSString *nameString = [self.model userName];...}
Finally, let's establish some best practices early regarding memory management. In the short term, this probably won't be an issue because HelloWorld only has one view. However, as the application grows and more views are added, we want to make sure we clean up after ourselves if those views are unloaded.
In the event of a low-memory condition, iOS may decide to remove an app's unused views from memory. As the documentation explains, the app will be notified via the viewDidUnload method of UIViewController. When this happens, view controllers that store references to subviews and outlets should release those references, and also release any objects that were created to support the view.
Let's look at the implementation of viewDidUnload in HelloWorldViewController:
Notice that Xcode has already inserted some code to release references to the textField and label outlets. This happened automatically while we were building the interface for HelloWorld. What about our instance of HelloWorldModel? It won't be needed if the view is not visible, so let's release that too. Add this snippet to viewDidUnload:
- (void)viewDidUnload{[super viewDidUnload];// Release any retained subviews of the main view.// e.g. self.myOutlet = nil;// Added automatically in tutorial.[self setTextField:nil];[self setLabel:nil];}
[self setTextField:nil];Yay! Now we shall implement a unit test for this class.