- •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
Chapter 18 Inheritance
an employee is a kind of person – it can do anything a person can. That is, we can use an instance of Employee anywhere that the program expects an instance of Person.
Now, however, you’re going to use a method that is unique to Employee, so you must change the type of the pointer variable:
#import <Foundation/Foundation.h> #import "Employee.h"
int main(int argc, const char * argv[])
{
@autoreleasepool {
// Create an instance of Person
Employee *person = [[Employee alloc] init];
//Give the instance variables interesting values [person setWeightInKilos:96];
[person setHeightInMeters:1.8];
[person setEmployeeID:15];
//Call the bodyMassIndex method
float bmi = [person bodyMassIndex];
NSLog(@"Employee %d has a BMI of %f", [person employeeID], bmi);
}
return 0;
}
Overriding methods
To review, when a message is sent, the search for the method of that name starts at the object’s class and goes up the inheritance hierarchy. The first implementation that is found is the one that gets executed. Thus, you can override inherited methods with a custom implementation. Let’s say, for example, that you decided that employees always have a Body Mass Index of 19. In this case, you might override the bodyMassIndex method in Employee. Open Employee.m and do so:
#import "Employee.h" @implementation Employee
@synthesize employeeID;
- (float)bodyMassIndex
{
return 19.0;
}
@end
Build and run the program and note that your new implementation of bodyMassIndex is the one that gets executed – not the implementation from Person.
Notice that you implemented bodyMassIndex in Employee.m, but you didn’t declare it in Employee.h. Declaring a method in the header file advertises the method so that instances of other classes can
call it. However, because Employee inherits from Person, everyone already knows that instances of Employee have a bodyMassIndex method. There is no need to advertise it again.
112
super
super
What if you decided that all employees get an automatic 10% off their BMI as calculated in the Person’s implementation? You could, of course, retype the code in the Employee implementation, but it would be so much more convenient to call Person’s version of bodyMassIndex and multiply the result by 0.9 before returning it. To do this, you use the super directive. Try it in Employee.m:
#import "Employee.h" @implementation Employee
@synthesize employeeID;
- (float)bodyMassIndex
{
float normalBMI = [super bodyMassIndex]; return normalBMI * 0.9;
}
@end
Build and run the program.
To be precise, the super directive says “Run this method, but start the search for its implementation at my superclass.”
Challenge
This challenge builds on the challenge from the previous chapter.
Create a subclass of StockHolding called ForeignStockHolding. Give ForeignStockHolding an additional instance variable: conversionRate, which will be a float. (The conversion rate is what you need to multiply the local price by to get a price in US dollars. Assume the purchasePrice and currentPrice are in the local currency.) Override costInDollars and valueInDollars to do the right thing.
In main(), add a few instances of ForeignStockHolding to your array.
113
Chapter 18 Inheritance
Figure 18.3 StockHolding and ForeignStockHolding objects
114
19
Object Instance Variables
Thus far, the instance variables declared in your classes have been simple C types like int or float. It’s far more common for instance variables to be pointers to other objects. An object instance variable points to another object and describes a relationship between the two objects. Usually, object instance variables fall into one of three categories:
•Object-type attributes: a pointer to a simple, value-like object like an NSString or an NSNumber. For example, an employee’s last name would be stored in an NSString. Thus, an instance of Employee would have an instance variable that would be a pointer to an instance of NSString.
•To-one relationships: a pointer to a single complex object. For example, an employee might have a spouse. Thus, an instance of Employee would have an instance variable that would be a pointer to an instance of Person.
•To-many relationships: a pointer to an instance of a collection class, such as an NSMutableArray. (We’ll see other examples of collections in Chapter 21.) For example, an employee might have children. In this case, the instance of Employee would have an instance variable that would be a pointer to an instance of NSMutableArray. The NSMutableArray would hold a list of pointers to one or more Person objects.
(Notice that, in the above list, I refer to “an NSString.” NSString is the class, but “an NSString” is shorthand for an NSString instance. This usage is a little confusing but very common, so it’s good to get comfortable with it.)
115
Chapter 19 Object Instance Variables
Figure 19.1 An Employee with object instance variables
Notice that, as in other diagrams, pointers are represented by arrows. In addition, those pointers are named. So an Employee would have three new instance variables: lastName, spouse, and children. The declaration of Employee’s instance variables would look like this:
@interface Employee : Person
{
int employeeID; NSString *lastName; Person *spouse;
NSMutableArray *children;
}
With the exception of employeeID, these variables are all pointers. Object instance variables are always pointers. For example, the variable spouse is a pointer to another object that lives on the heap. The pointer spouse is inside the Employee object, but the Person object it points to is not. Objects don’t live inside other objects. The employee object contains its employee ID (the variable and the value itself), but it only knows where its spouse lives in memory.
There are two important side-effects to objects pointing to rather than containing other objects:
•One object can take on several roles. For example, it is likely that the employee’s spouse is also listed as the emergency contact for the children:
116