Objective-C Lesson 10: Memory Management


Memory on the iPhone is limited. Although each new generation of hardware has increased the amount of physical memory in the device, applications are also taking more memory, and with the introduction of background apps in iOS 4, memory remains a resource to be conserved. iOS automatically quits applications that use too much memory; therefore it’s important to be aware of your memory usage and avoid leaking, which will increase your memory usage, or the equally annoying early release of elements, which will cause your app to crash. These issues are handled by the system in a garbage-collected environment, where the system will automatically release memory as needed, but this adds an overhead and is not available on iOS. On a similar topic, note that iOS does not have a paging system—data cannot be paged out to disk as needed. You can read and write data to disk, but this is not recommended (or even possible) for any object—only for data files, and even then sparingly, because disk access is inevitably slower than memory access.

Reference Counting

Cocoa’s memory management scheme is based off a reference counting system. It’s a simple concept—every object has a value, known as a reference count. When the object is created, the count is set to 1. Certain actions will increment or decrement this count, and when the count hits zero, the object is immediately freed from memory, at which point you cannot access it again.

Messages

Reference counting principally involves three methods—retain, release, and dealloc. The first two change the reference count; the latter frees up the memory of the objects. You generally override the dealloc method, as we have been doing in our classes, to free up the memory occupied by the class’s instance variables (usually by calling their dealloc method). Finally, the method always includes a call to super‘s dealloc method, which invariably calls NSObject‘s dealloc method. It is this specific method that frees up the memory; if you neglect to call this implementation, you get a compiler warning. Also note that you should always override this method, but you should never call it specifically—the system will call that method for you as necessary.

The retain method increments the retain count by one. It is inherited by all classes, and so can be called on any object, any number of times, at any time. The release method decrements the retain count by one.

Keeping track of the retain count requires some diligence on the part of the programmer. If you under-release an object, the memory will be leaked; if you over-release, you crash.

Memory Management Rules

The rules are simple, really.

  • If the method name has init, copy, or new anywhere in the method name (such as initWithName:, mutableCopy, or newCar), the method implies that the object will have been retained, and it is your responsibility to release that object later This also means that you’ll need to store that object in a variable, to be able to release it again.
    NSMutableArray *ma = [someArray mutableCopy];
    myMutableArray = ma;
    [ma release];
  • Any other method name, if the method returns an object, will be autoreleased.

All of Apple’s methods follow these rules, and yours should too.

Memory Management with Properties

When you create a property, you can specify certain parameters that the setters follow. Of note is the retain and copy parameters. Most object properties are declared as retain, which generates a setter like so:

-(void) setText:(NSString *)textValue {
    if (![textValue isEqualToString: text]) {
        [textValue retain];
        [text release];
        text = textValue;
    }
}

This value is retained, and as such you have to balance it out with a release in the dealloc method. The copy parameter does something similar, except that instead of retaining the new value, it copys it.

One thing to point out, as noted by a comment on last week’s post, is that in general you do not want to retain delegate objects. Otherwise, you’ll get a recursive memory coupling. For example, a table view’s delegate is generally the view controller which owns the table view itself. Therefore, if the delegate property retained the delegate, the table view would own its delegate, which would own the table view—you couldn’t release any one of them because they own each other. Make sure to avoid this issue.

Autorelease

The autorelease pool is a medium between directly managing memory, and garbage collection. A lot of methods return autoreleased objects—these objects are added to an autorelease pool, which is created in every program. When the drain method is sent to the pool, all of the objects within are sent a release method. This can be useful in a tight loop:

NSAutoreleasePool *tempPool;
for (i = 0; i < n; i++) {
     tempPool = [[NSAutoreleasePool alloc] init];
     // Create lots of temporary autoreleased objects that take a lot of memory
     [tempPool drain];
}

To autorelease an object, simply send the autorelease method.

Collection Classes

Collection classes, including NSArray, NSDictionary, and NSSet, retain all of the objects that you put into them. When the collection class is deallocated, all of the members in the class are also released.

On any platform, specifically the memory-constrained iOS platform, memory management is an important topic to keep in mind. It requires diligence on the part of the programmer—but the alternative is slow performance and/or crashes, both of which must be avoided. Following the simple rules is the fool-proof way to keep track of your memory management.

Objects (Part 4): Inheritance—iVars & Methods


Inheritance is a central tenet of object-oriented programming. In a nutshell, it refers to the creation of new classes by extending, or subclassing existing classes, and in doing so, inheriting their features.

In Fraction‘s interface file, we have the following line:

@interface Fraction : NSObject

The part in bold indicates that Fraction is a subclass of NSObject, a class that Apple provides. Nearly every class you will create or interact with will have inherited from NSObject, directly or indirectly.

Terminology

A root class is at the top of the inheritance hierarchy. Almost all Cocoa Touch and Foundation classes inherit from NSObject. Incidentally, NSObject is also an abstract class, so called because it’s not designed to be actually used—rarely will you ever use an NSObject; you’ll usually create and use subclasses. An abstract class therefore is one that is created for the purposes of subclassing.

A class that inherits from another is known as a child or subclass of its or superclass.

What Does This Mean?

Every subclass inherits certain properties of its superclass; exactly what is inherited can be controlled. By default, every class has access to all the instance variables of its superclass, and they work exactly as if you had defined those ivars in the subclass itself. In addition, a subclass will inherit any public methods that its superclass defines. As an example (kept in one file for brevity):

@interface Superclass : NSObject {
	int v;
}

- (void)initV;
@end

@implementation Superclass
- (void)initV {
	v = 20;
}
@end

@interface Subclass : Superclass {
	int w;
}

- (void)displayVars;
@end

@implementation Subclass
- (void)initW {
	w = 50;
}

- (void)displayVars {
	NSLog(@"v is %d, w is %d", v, w);
}
@end

int main(int argc, char *argv[]) {
	NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];

	Subclass *sub = [[Subclass alloc] init];

	[sub initV];		// Inherited method & ivar
	[sub initW];		// Own method & ivar
	[sub displayVars];	// Inherited method	[sub release];
	[pool drain];
	return 0;
}

Output:

v is 20, w is 50
Subclass inherits from Superclass, which inherits from NSObject

The inheritance chain

As you can see, we created an instance of an object of type Subclass. We then used it as any other class. Notice, however, that we called initV on the Subclass, and accessed the v ivar, neither of which were declared in Subclass. This is because these were already present in Superclass, and Subclass inherited them. The output proves that Subclass was able to access the inherited variables.

Which Method?

Remember that a method is simply a declaration of what a class can do; when it is invoked at runtime, it is chosen out of that “list.” How does the program figure out which method to call (especially if you have more than one method of the same name in the inheritance chain)? In fact, the procedure is very simple. The runtime environment searches for an explicit declaration of that method in the class of the object that you sent the message to (in the above example, the search for displayVars begins with the Subclass class. If it is found in that class, it invokes that method (in other words, it invokes the version closest to that class in the inheritance chain). If it isn’t found, it looks for the method in the superclass; if it’s found, it invokes that version; if not, the search continues, until either the method is found, or it isn’t. In the latter case, you get a compiler warning, that the class may not respond to the specific method. When your code tries to call this method during execution, your program will likely crash.

2010 in review


The stats helper monkeys at WordPress.com mulled over how this blog did in 2010, and here’s a high level summary of its overall blog health:

Healthy blog!

The Blog-Health-o-Meter™ reads This blog is on fire!.

Crunchy numbers

Featured image

A helper monkey made this abstract painting, inspired by your stats.

A Boeing 747-400 passenger jet can hold 416 passengers. This blog was viewed about 3,700 times in 2010. That’s about 9 full 747s.

In 2010, there were 37 new posts, not bad for the first year! There were 2 pictures uploaded, taking up a total of 65kb.

The busiest day of the year was October 15th with 136 views. The most popular post that day was Learn Objective-C in 24 Days.

Where did they come from?

The top referring sites in 2010 were iphonedevsdk.com, discussions.apple.com, tutorialsblogs.com, facebook.com, and en.wordpress.com.

Some visitors came searching, mostly for ios first program, ios hello world, ios lesson “hello world”, ios variable types, and initialise declare on same line objective c.

Attractions in 2010

These are the posts and pages that got the most views in 2010.

1

Learn Objective-C in 24 Days August 2010

2

Objective-C Lesson 1: Hello World! September 2010
3 comments and 1 Like on WordPress.com,

3

Resources August 2010
2 comments

4

Objective-C Lesson 2: Basic Variables September 2010

5

About Me August 2010
6 comments

 

Thanks to everyone who dropped by in 2010! In one day yesterday, we had more visitors than in all of August (when I began) combined. Happy coding in the new year!

Supplement: CS193P


Stanford University has offered the CS193P class for a few quarters now. It has become the ubiquitous source of beginning iPhone programming material for many people. The lectures are filmed and uploaded to iTunes U, and they are now available in 720p HD video. However, the lectures, which are the only option for non-enrolled students, are rather impersonal, and sometimes move too quickly (in my opinion). I have learned a lot from them, but I don’t think they’re the only source. In fact, I find that they are more helpful once I got the basics down. Nevertheless, there are real gems, and so I will be occasionally referring links as supplementary material.

To access the lectures:

  1. Launch iTunes and head into the iTunes Store (don’t worry, all the lectures are free).
  2. Click on iTunes U on the black bar near the top of the storefront.
  3. At the time of this writing, the lectures were under Staff Favorites. Click on the link, and you’ll be led to the main listing.

    CS193P Fall 2010 Lectures Listing

    iTunes Listing

Direct link (will open iTunes, if it is not already running):
http://itunes.apple.com/WebObjects/MZStore.woa/wa/viewPodcast?id=395605774

The lectures are available for streaming; alternatively, you can download them just like regular songs from iTunes. Note that file sizes are around 500MBs for the SD version and around 700MBs for the (linked) HD version.

The slides can be downloaded from the main website, listed above, as well as the sample code.

Creating a New iPhone Project


Over the next few Lessons, we will be creating a full-functioned calculator, that can handle basic arithmetic, as well as fractional operations. By the end, we will also have a GUI (graphic user interface), but for now, we will be working off the console, as we have been doing.

We’ll begin by creating a new project in Xcode. Note that the screenshots below are from Xcode 3.2.3 running under OS X 10.6.5; the steps should be generally the same if you’re lucky enough to be running Xcode 4. Note, however, that Xcode 4 is under NDA and is only available for paid developer program members; therefore, we will not be talking about Xcode 4 until it is officially released.

Let’s begin!

Creating the Xcode Project

Launch Xcode. If it’s not in your Dock already, navigate to /Developer/Applications, and ideally, drag it to your Dock; otherwise, you’ll have to look for it every time you launch the program.

Xcode is located at /Developer/Applications/Xcode.app

Location of Xcode on Disk

When the launch window shows up, click “Create a new Xcode project”; alternatively, navigate to File > New Project (⇧⌘N). Choose the “Window-based Application”, and make sure “Product” is “iPhone.” Do not use Core Data. See the screenshot below:

Choose the Window-based Application template

Xcode 3 New Project Window

Save the project anywhere on disk; I’d recommend having a dedicated “Developer” folder in your Home folder. (Of course, feel free to search for an icon that you can use for your folder.) I’d also strongly recommend that you save your project as “Calculator”; otherwise, your code could result in errors.

Save your Project as "Calculator"

Save your Project as "Calculator"

After you click “Save,” you’ll be presented with the main Xcode window. Note that yours probably will look a little different from mine, but the general functionality is still the same. If you wish to adopt my layout, I’m using the All-In-One layout, found in Xcode > Preferences > General > Layout.

The Xcode main window

Xcode 3 Main Window

Regardless of which view you use, you will see the File list, the Organizer, and the Toolbar. For this Lesson, we will only be concerned with the File list and Organizer. I’ll do an Extension on using Xcode later.

At the moment, click on Build and Run from the toolbar. After a brief moment, the iPhone Simulator will appear, and you will see a blank (white) screen.

Blank iPhone Simulator Window

Blank iPhone Simulator Program

Here, you’re done…for now. Feel free to close the current project window…we’ll be returning to it in a few lessons. Hopefully though, this has whetted your appetite. We now move on to proper object-oriented programming

Objective-C Lesson 4: if() statements and Booleans


As mentioned before, boolean values are simply true-or-false. In Objective-C, unlike many other languages, they are represented as YES or NO:

BOOL trueOrFalse = YES;
BOOL gameOver = NO;

Internally, however, they are stored as zero and one.

if() Statements

The if() statement is used to check for conditions. Just like we use if in normal English, if() in code is used to test for a condition—they test for the value of a boolean (or any int—in this case, a zero is considered false; any non-zero value is true).

Here is a simple example of booleans:

#import <Foundation/Foundation.h>

int main (int argc, const char * argv[]) {
    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];

	BOOL trueOrFalse = YES;
	if (trueOrFalse)
		NSLog(@"trueOrFalse is true.");
	if (1)
		NSLog(@"1 is considered to be true.");
    [pool drain];
    return 0;
}

The output is:

trueOrFalse is true.
1 is considered to be true.

Simple enough, and quite logical.

Obviously, if the condition was false, the statements following would not be executed. The following example demonstrates:

#import <Foundation/Foundation.h>

int main (int argc, const char * argv[]) {
    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];

	BOOL trueOrFalse = YES;
	if (trueOrFalse)
		NSLog(@"trueOrFalse is true.");
	if (1)
		NSLog(@"1 is considered to be true.");	// If false, statement following is not executed
	trueOrFalse = NO;
	if (trueOrFalse)
		NSLog(@"I lied. trueOrFalse is not true.");
	if (0)
		NSLog(@"This line should not appear.");
    [pool drain];
    return 0;
}

Unsurprisingly, the results are the same as above.

One important point to make here: if you only have one statement after the if(), you can just leave it like it is above. But if you have more than one statement after the if(), you must enclose them within braces:

if (trueOrFalse) {
	NSLog(@"trueOrFalse is true.");
	NSLog(@"This second line must be within the braces.");
}

Otherwise, the second (or additional) statements will be executed, regardless of if the condition was true or not.

Extending the if() Statement

In real life though, there are often alternatives: if something is true, do “action1“; else, do “action2“. Objective-C lets you model that quite simply:

trueOrFalse = YES;
if (trueOrFalse == YES)          // The double-equals sign is a comparison; versus a single equals, which is an assignment. More on this in the next Extension.
	NSLog(@"If true, print this");     // This gets printed
else
	NSLog(@"Else, print this");        // This does not get printed
trueOrFalse = NO;
if (trueOrFalse)
	NSLog(@"If true, print this");    // This does not get printed
else
	NSLog(@"Else, print this");       // This gets printed
 

Output is:

If true, print this
Else, print this

This makes logical sense.

You can also extend this by using else if(). This is easier to explain with code:

int value = 5;
	if (value > 0)
		NSLog(@"value is greater than zero.");
	else if (value == 0)
		NSLog(@"value is equal to zero.");
	else
		NSLog(@"value is less than zero.");

Output is:

value is greater than zero.

You can have as many else if()s as you want; they simply follow each other:

int value = 5;
if (value == 6)
	NSLog(@"value is equal to 6.");
else if (value == 0)
	NSLog(@"value is equal to 0.");
else if (value == 2)
	NSLog(@"value is equal to 2.");
else if (value == 10)
	NSLog(@"value is equal to 10.");
else
	NSLog(@"value does not equal 6, 0, 2, or 10");     // This line is the output.

Pitfalls

There are a few issues that may arise with if()statements.

  • Forgetting braces: If you have more than one statement that you want to execute given a certain condition, you must enclose them within curly braces.
  • Using too many instances of if(): If you want to have a collection of related paths (if…else if…else), you must remember to use else if(). Using a chain of if()s is a completely different thing, logically. Think about it.
  • Forgetting the last else: The final else is a “catchall” statement that is executed if none of the previous if() or else if() statements are true. Don’t forget the else; otherwise, you may never get any output. For example, in the last code example, the last else statement was needed; otherwise, it might have appeared that the code was broken.

Conclusion

As you can see, the if() statement is quite simple, but very powerful—it defines “paths” down which your code can travel, based on the value of a condition. In the next Extension, we will be looking at what these conditions can be.

Extension 3: ASCII, Booleans, Characters


Type char

A variable of type char is used to store a single character. It is denoted as a character, flanked by two single quotes. (Be careful—single quotes are used for characters, double quotes signify a string.) ‘a’, ‘;’, and ‘8’ all represent character types. The first is simply the letter a. The second is the semicolon symbol; it is not the same as the one used to mark the end of a line. The last example is the character 8, not the integer 8.

This Photograph is created using only the ASCI...

ASCII Art—Image via Wikipedia

Escape sequences, when enclosed in single quotes, are also considered to be char, even though they are composed of more than one symbol.

To print a character or escape sequence through NSLog, use %c.

ASCII Values

In C, chars are represented as 8-bit ASCII values. Internally, characters are stored as numbers, with a range from 0-127. This makes for interesting uses, including the following simple cypher program:

#import 

int main (int argc, const char * argv[]) {
    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];    // A simple cypher program
    NSLog(@"Hello");	// Original message
	NSLog(@"%c%c%c%c%c", ('H' + 1), ('e' + 1), ('l' + 1), ('l' + 1), ('o' + 1));		// Cypher 1
	NSLog(@"%c%c%c%c%c", (('H' * 2) % 127), (('e' * 2) % 127), (('l' * 2) % 127), (('l' * 2) % 127), (('o' * 2) % 127));	 /* Cypher 2...
																															 note the use of the modulus operator
																															 to limit the domain */
	[pool drain];
    return 0;
}

The output of this program is:


Hello
Ifmmp
 KYY_

One thing to note before we analyze this program—the last output only displays four characters because the ASCII value of capital H is 72. The operation results in an ASCII value of 17, which is a “special”, non-printing character (see Wikipedia link above).

Code, Demystified

The first important line prints out the NSString constant @”Hello”. Not much to it. The next line prints out five characters, as represented by the escape sequences. Looking at the arguments to NSLog, we see that we are simply taking the characters in @”Hello” and adding one to their ASCII values. If you check the output, you’ll find that Ifmmp are just the letters of Hello, but shifted “over” by one. Note that ASCII values define all capitals before lowercase, not all letters in alphabetical order; the letters A-Z come numerically before a-z.

We do the same thing on the Cypher 2 line, except that this time there is a little bit more involved. We take the ASCII value and multiply it by 2. To keep our code neat and prevent warnings, we use the modulus operator to limit the range of the result—in this case, the result can only be between 0 and 127, exactly the range of ASCII. This is another practical use of the modulus operator—to limit the range of a result to a specific set of numbers.

Note that when you write chars in your code, you must delineate them with single quotes. Those quotes do not get printed in the final output.

Type BOOL

Boolean values are very simple—they are literally a YES or NO. In other languages, including Java and plain C, they are represented as true or false. Although initially the latter may seem more reasonable, in usage the former makes more grammatical sense. For example, in the following method call,

[self presentModalViewController:mvc animated:YES];

using the value YES makes much more sense from a reader’s perspective than true.

Booleans are simple true or false values; they are usually used to determine if a condition is true or not, and used to determine whether some code should be executed (for() statements). In Objective-C, the integer values 0 and 1 are synonymous, and can be used interchangeably (with a few exceptions). Their usage will be detailed in the next Lesson.

Over 1000


We are now over 1000 hits…

As a first-time blogger, this is a milestone for me. Thanks to everyone who’s dropped by, and I hope to see you back again!

Spread to word to all your friends—if this site has helped you, it will help someone else. And if it hasn’t helped you yet, don’t worry—it will sooner or later.

Thanks for dropping by! I’m going celebrating…

😀

999


We’re at 999 views

Just…one…more…

😀

Extension 2: Floating-Point Operations


Not all numbers are integers. Therefore, Objective-C lets you define floating-point values—numbers with a fractional portion. There are two basic types—float and double.

Floating-point values do not follow the rules of integer division—that is, dividing by floating-point values produces floating-point results.

Type float

In certain programming languages (Java comes to mind) the float type is almost never used. In Objective-C, it is the more commonly used of the two—both for practical and memory reasons.

A floating point number must contain a decimal portion, but you can omit digits before or after the decimal point—obviously, not both. The entire number ca be prefixed by a negative sign. Therefore, 3., 1.8, .295, and -.59 are all valid floating point numbers. To display floats in an NSLog call, use %f.

Scientific Notation

As you may recall from a high-school math class, scientific notation is a method of writing absurdly large or small numbers. It takes the form 5.925×102, where the general notation is of a floating-point value followed by a multiplication, a number (generally a power of 10), and an exponent. This number is written in code with the form 5.925e4. The e, formally known as the mantissa, can be written as a capital or lowercase. The mantissa can be either positive or negative; a negative value, such as 2.25e-3, would correspond to a value of 2.25×10-3, or 0.00225.

To display scientific notation, use %e. Alternatively, you can use %g to have NSLog decide whether to display the usual value or the scientific notation—if the exponent is less than -4 or greater than 5, the scientific notation is used; otherwise, the standard floating point notation is used.

Type double

A double value is a more precise float value—the former stores twice as many digits, and on most systems it uses 64 bits.

Like Java, all floating point constants in Objective-C are double. To force a float, append either f or F to the end of the floating point value. Unlike Java, however, floats are used as a general data type for floating-point variables, due to the fact that they require less memory. The distinction is that of constants versus that of variables.

The same format specifiers apply to doubles, as well as scientific notation.

  • Welcome

    My goal is to make CupsOfCocoa into a beautiful source for beginners to the iPhone platform to get started. Subscribe below for more, and stay tuned!

  • Contact Me

    If you need to contact me for any reason, feel free to send me an email.
  • The Giving Spirit

    If you've found this site helpful, would you consider donating a little sum? Any amount is appreciated...Thanks so much!

  • Roadmap

  • Enter your email address to follow this blog and receive notifications of new posts by email.

    Join 220 other followers

  • Back to the Past

    May 2020
    S M T W T F S
     12
    3456789
    10111213141516
    17181920212223
    24252627282930
    31  
  • Time Machine

  • You count!

    • 622,650 views
  • Worldwide Stats

    free counters
%d bloggers like this: