How to make an iPhone App for beginners – Part 2: Memory and Controllers
Memory is probably the most boring part of iPhone development, but also one of the most important. Depending on the iPhone you have you will have available more or less than 256MB’s (iPhone 3GS), where part of that is shared with the OS, leaving you less than 128MB’s, so you have to be very careful managing memory or Apple may reject your app.
Memory Management
“If you create an object, it’s your responsibility to release it”. That’s the golden rule you have to follow in memory management.
Let’s open the project we were working on in the previous chapter of this series, i called it “ClassTest”. Remember?. In that project we created a class called “Person” and an instance of the class with the object called “p”.
“p” was created with:
Person *p = [Person new];
That’s the easiest way to create and initialize an object. But there is also an other way which is more customizable and makes a better example to explain how memory works.
Person *p = [[Person alloc] init];
With “Alloc” we are saying “Go and claim the mount of memory necessary to hold this object”. Then with “Init” we are initializing that space of memory, we are putting something inside. But what is the idea of doing initialization this way?. Well, init can be customizable, you can override the init method or, for example, if you are creating a string you can use other built-in init variations like:
NSString *s = [[NSString alloc] initWithString:@"Hello World"];
Release Method
Ok, we have created an object, now it’s our responsibility to release it when we are done using it. To release an object we call the “Release” method before the return stament:
[p release];
When we call release, we are asking the computer to destroy the object, we won’t need it anymore. If you want to use it in the future you will have to create it again, so be very careful when you release your objects.
A very common error people commit is to try to use an object when it has been already released. If you do so your program is going to explode and the console will insult you.
Some times you may see a method called “Dealloc” in the implementation of a class. This method is part of the NSObject class, it is called when you say “release”, some people like to override this method when they need to do something before releasing an object. Here is an example:
-(void) dealloc{ NSLog(@"Bye"); [super dealloc]; }
If you are going to override dealloc just make sure you call “[super dealloc]” at the end of the method. Dealloc is must not be defined in the .h file of the class, it is inherited, to override it.
Autorelease Pools
And autorelease pool is an object than can handle for us the releasing of our objects. This is how to create an autorelease pool:
int main (int argc, const char * argv[]) { NSAutoreleasePool *pool = [[pool alloc] init]; NSLog(@"Hello World") [pool drain]; return 0; }
This sounds very convenient. Why don’t we always send our objects to an autorelease pool?. Because it means that our objects are living more than they should, so you must avoid using them, they are made for very few cases.
Lets say you have a function like this:
-(a) something { A *a [[A alloc] init]; [a release]; return a; }
If you do this you application is going to crash, because we are releasing an object and then trying to return it. In this cases you have to say “Release it later”. To do so we have to send it to the autorelease pool and it is going to call [a release] a few second or milliseconds later, it is hard to say when it is going to release it, that’s why you shouldn’t use it all the time. Here is how to do it:
-(a) something { A *a [[A alloc] init]; [a autorelease]; return a; }
Your first iPhone App
Now that you know how to handle memory let’s create an iphone app that reads your name and say “Hello, [typed name]”. Are you excited?.
Go to File->New Project, click iPhone OS->Application and double click “View-Based Application” in the right list. This is the most used template to create iPhone Applications. Give it a name, i’m going to call it “FirstApp”.
Go to the resources folder in the “Group and Files menu” and double click “FirstAppViewController.xib”, if you gave your project a different name than mine it is going to be “[ProjectName]ViewController.xib”. Interface Builder will appear.
In the “Library” window find text field, and drag it to the “View” window like this:
Then drag the right side of the field to expand it.
With the text field selected go to the “Inspector” window, it will be showing the textfield properties, find “Placeholder” and type “Please, type your name”.
Then drag a “Round Rect Button” and place it below the text field, double click it and type “Ok”. Last, drag a label to the view and expand it to match the width of the text field, double click it and erase everything inside. Your View should look like this:
Now save and go to Xcode. Open the “Classes” folder and click FirstAppViewController.h. This is the class where we are going to add our code to make the view we did in Interface Builder do what we want.
First you need to ask your self “What elements i have in my user interface that are going to hold information?”. We have a text field and a label. Fine, let’s create the logical representation of it.
#import @interface FistAppViewController : UIViewController { IBOutlet UITextField * Name; IBOutlet UILabel * Output; } @property (nonatomic, retain) IBOutlet UITextField * Name; @property (nonatomic, retain) IBOutlet UILabel * Output; @end
I created two objects one for the text field and one for the label, then i used @property (nonatomic, retain), with this we are saying to our getters and setters to retain the information and not release it. This may be a little confusing right now, but don’t worry.
Now we need to add a method to be fired when we tab the button. Make sure to add it right before @end.
-(IBAction) ProcessName;
Now go to the implementation file “FirstAppViewController.m”. Right after the implementation line: “@implementation FirstAppViewController” we need to synthesize the objects. This means that the getters and setters will be created for me. Type this:
@synthesize Name; @synthesize Output;
Then, after that we need to write the implementation of out “ProcessName” method:
-(IBAction) ProcessName { NSString * message = [[NSString alloc] initWithFormat:@"Hello, %@",Name.text]; [Output setText:message]; [message release]; }
First i created the message to be displayed in the label. Next i set the text attribute of the label to be the message. And last, just because i created the message, i have to release it. Save and build the project.
Now we have everything ready, except for one little thing, we need to connect the interface with the code. Go back to Interface Builder and right click the “File’s Owner” icon in the “Document” window. Notice that a small black window will pop up will all the object and the actions we just created. Find Output, in the right border you’ll see a little circle, click and drag it to the label in the “View” window.
Then do the same for the text field, drag the circle in “Name” over the text field in the view. For the button we wrote an action, not a object, so drag the circle in ProcessName at the “Received Actions” section to the button and a small black menu will show up, select “Touch Up Inside” this means that ProcessName is going to be called when the user touch the button.
Click File->Save and go to Xcode. Click “Build and Run” to test the app.
Click the text field, write your name and hit ok.
Cool. Now let’s see how we can hide the keyboard when the button is touched.
Let’s go back to the “ProcessName” method in FirstAppViewController.m. Right before the message declaration add “[Name resignFirstResponder];” this will make the text field resign the first responder, which in this case is the keyboard. The method should look like this:
- (IBAction) ProcessName { [Name resignFirstResponder]; NSString * message = [[NSString alloc] initWithFormat:@"Hello, %@", Name.text]; [Output setText:message]; [message release]; }
Build and run the app and now the keyboard should go away the you touch the button.
If we want to hide the keyboard when we tab the return button we need to do something called delegation.
Delegation
To delegate means to leave a certain responsibility to another one. In this case we are talking about telling the iPhone to leave the responsibility of hiding the keyboard to us. But how we do this?
Go to Interface Builder, click the text field in the “View” window and in the inspector click the second tab. In the “Outlets” section you’ll find “delegate”
Drag the circle from “delegate” to the “File’s Owner” icon in the “Document” window.
What we just did is made the “View” the delegate of the text field. Open “FistAppViewController.m”.
After the “ProcessName” method we are going to write the method that we are delegating.
-(BOOL) textFieldShouldReturn:(UITextField *)textField{ [textField resignFirstResponder]; [self ProcessName]; return YES; }
This method is built-in, we are just overriding it. You can find more methods in the documentation, search for UITextFieldDelegate.
Now when you tab the return button in the keyboard it goes away.
Conclusion
In this tutorial we have learned many things. Try to practice making more applications to not forget them because they are fundamental.
In the next chapter we are going to talk about alerts and table views, don’t miss it.