- •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
Deadly init methods
Thus, we arrive at the rules that all stylish Objective-C programmers follow when writing initializers:
•If a class has several initializers, only one should do the real work. That method is known as the designated initializer. All other initializers should call, either directly or indirectly, the designated initializer.
•The designated initializer will call the superclass’s designated initializer before initializing its instance variables.
•If the designated initializer of your class has a different name than the designated initializer of its superclass, you must override the superclass’s designated initializer so that it calls the new designated initializer.
•If you have several initializers, clearly document which is the designated initializer in the header.
Deadly init methods
Every once in a while, however, you can’t safely override the superclass’s designated initializer. Let’s say that you are creating a subclass of NSObject called WallSafe, and its designated initializer is initWithSecretCode:. However, having a default value for secretCode is not secure enough for your application. This means that the pattern we have been using – overriding init to call the new class’s designated initializer with default values – is not acceptable.
So what do you do? An instance of WallSafe will still respond to an init message. Someone could easily do this:
WallSafe *ws = [[WallSafe alloc] init];
The best thing to do is to override the superclass’s designated initializer in a way that lets developers know that they have made a mistake and tells them how to fix it:
- (id)init
{
@throw [NSException exceptionWithName:@"WallSafeInitialization" reason:@"Use initWithSecretCode:, not init"
userInfo:nil];
}
215
This page intentionally left blank
30
Properties
In the last chapter, you created a class called Appliance that had two properties: productName and voltage. Let’s review how those properties work.
In Appliance.h, you declared two instance variables to hold the data:
{
NSString *productName; int voltage;
}
You also declared accessor methods for them. You could have declared the accessors like this:
-(void)setProductName:(NSString *)s;
-(NSString *)productName;
-(void)setVoltage:(int)x;
-(int)voltage;
However, you used the @property construct instead:
@property (copy) NSString *productName; @property int voltage;
In Appliance.m, you could have implemented the accessor methods explicitly like this:
-(void)setProductName:(NSString *)s
{
productName = [s copy];
}
-(NSString *)productName
{
return productName;
}
-(void)setVoltage:(int)x
{
voltage = x;
}
-(int)voltage
{
return voltage;
}
217