- •C and Objective-C
- •How this book works
- •How the life of a programmer works
- •Installing Apple’s developer tools
- •Getting started with Xcode
- •Where do I start writing code?
- •How do I run my program?
- •So what is a program?
- •Don’t stop
- •Types
- •A program with variables
- •Challenge
- •Boolean variables
- •When should I use a function?
- •How do I write and use a function?
- •How functions work together
- •Local variables, frames, and the stack
- •Recursion
- •Looking at the frames in the debugger
- •return
- •Global and static variables
- •Challenge
- •printf()
- •Integer operations
- •Integer division
- •Operator shorthand
- •Floating-point numbers
- •Tokens for displaying floating-point numbers
- •The while loop
- •The for loop
- •break
- •continue
- •The do-while loop
- •Challenge
- •Getting addresses
- •Storing addresses in pointers
- •Getting the data at an address
- •How many bytes?
- •NULL
- •Stylish pointer declarations
- •Challenges
- •Writing pass-by-reference functions
- •Avoid dereferencing NULL
- •Creating and using your first object
- •Message anatomy
- •Objects in memory
- •Challenge
- •Nesting message sends
- •Multiple arguments
- •Sending messages to nil
- •Challenge
- •Challenge
- •NSMutableArray
- •Reference pages
- •Quick Help
- •Other options and resources
- •Accessor methods
- •Dot notation
- •Properties
- •self
- •Multiple files
- •Challenge
- •Overriding methods
- •super
- •Challenge
- •Object ownership and ARC
- •Creating the Asset class
- •Adding a to-many relationship to Employee
- •Challenge
- •Retain cycles
- •Weak references
- •Zeroing of weak references
- •For the More Curious: Manual reference counting and ARC History
- •Retain count rules
- •NSArray/NSMutableArray
- •Immutable objects
- •Sorting
- •Filtering
- •NSSet/NSMutableSet
- •NSDictionary/NSMutableDictionary
- •Preprocessor directives
- •#include and #import
- •#define
- •Global variables
- •enum
- •#define vs global variables
- •Writing an NSString to a file
- •Reading files with NSString
- •Writing an NSData object to a file
- •Reading an NSData from a file
- •Target-action
- •Helper objects
- •Notifications
- •Which to use?
- •Callbacks and object ownership
- •Challenge
- •Getting started with iTahDoodle
- •BNRAppDelegate
- •Adding a C helper function
- •Objects in iTahDoodle
- •Model-View-Controller
- •The application delegate
- •Setting up views
- •Running on the iOS simulator
- •Wiring up the table view
- •Adding new tasks
- •Saving task data
- •For the More Curious: What about main()?
- •Edit BNRDocument.h
- •A look at Interface Builder
- •Edit BNRDocument.xib
- •Making connections
- •Revisiting MVC
- •Edit BNRDocument.m
- •Writing init methods
- •A basic init method
- •Using accessors
- •init methods that take arguments
- •Deadly init methods
- •Property attributes
- •Mutability
- •Lifetime specifiers
- •copy
- •More about copying
- •Advice on atomic vs. nonatomic
- •Key-value coding
- •Non-object types
- •Defining blocks
- •Using blocks
- •Declaring a block variable
- •Assigning a block
- •Passing in a block
- •typedef
- •Return values
- •Memory management
- •The block-based future
- •Challenges
- •Anonymous block
- •NSNotificationCenter
- •Bitwise-OR
- •Bitwise-AND
- •Other bitwise operators
- •Exclusive OR
- •Complement
- •Left-shift
- •Right-shift
- •Using enum to define bit masks
- •More bytes
- •Challenge
- •char
- •char *
- •String literals
- •Converting to and from NSString
- •Next Steps
- •Index
Challenge
When employees is set to nil, the array no longer has an owner. So it is deallocated, which sets up an even larger chain reaction of memory clean-up and deallocation when, suddenly, none of the employees has an owner.
Tidy, right? As the objects become unnecessary, they are being deallocated. This is good. When unnecessary objects don’t get deallocated, you are said to have a memory leak. Typically a memory leak causes more and more objects to linger unnecessarily over time. The memory footprint of your application just gets bigger and bigger. On iOS, the operating system will eventually kill your application. On Mac OS X, the performance of the entire system will suffer as the machine spends more and more time swapping data out of memory and onto disk.
Challenge
Using the StockHolding class from a previous challenge, make a tool that creates an instance of a Portfolio class and fills it with stock holdings. A portfolio can tell you what its current value is.
123
This page intentionally left blank
20
Preventing Memory Leaks
It is pretty common to have relationships that go in two directions. For example, maybe an asset should know which employee is currently holding it. Let’s add that relationship. The new object diagram would look like this:
Figure 20.1 Adding holder relationship
From a design standpoint, you would say that we are adding a pointer from the child (an instance of Asset) back to its parent (the instance of Employee that is holding it).
In Asset.h, add a pointer instance variable to hold on to the holding employee:
#import <Foundation/Foundation.h>
@class Employee;
@interface Asset : NSObject
{
NSString *label;
Employee *holder; unsigned int resaleValue;
}
@property (strong) NSString *label;
@property (strong) Employee *holder;
125
Chapter 20 Preventing Memory Leaks
@property unsigned int resaleValue; @end
In Asset.m, synthesize the accessors and extend the description method to display the holder:
#import "Asset.h"
#import "Employee.h"
@implementation Asset
@synthesize label, resaleValue, holder;
- (NSString *)description
{
// Is holder non-nil? if ([self holder]) {
return [NSString stringWithFormat:@"<%@: $%d, assigned to %@>", [self label], [self resaleValue], [self holder]];
} else {
return [NSString stringWithFormat:@"<%@: $%d unassigned>", [self label], [self resaleValue]];
}
}
- (void)dealloc
{
NSLog(@"deallocing %@", self);
}
@end
This brings us to a style question: When people use the Asset class and Employee class together, how do we make sure that the two relationships are consistent? That is, an asset should appear in an employee’s assets array if and only if the employee is the asset’s holder. There are three options:
• Set both relationships explicitly:
[vicePresident addAssetsObject:townCar]; [townCar setHolder:vicePresident];
• In the method that sets the child’s pointer, add the child to the parent’s collection.
- (void)setHolder:(Employee *)e
{
holder = e;
[e addAssetsObject:self];
}
This approach is not at all common.
• In the method that adds the child to the parent’s collection, set the child’s pointer.
In this exercise, you will take this last option. In Employee.m, extend the addAssetsObject: method to also set holder:
126