- •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 21 Collection Classes
[employees removeObjectAtIndex:5];
NSLog(@"allAssets: %@", allAssets);
NSPredicate *predicate = [NSPredicate predicateWithFormat: @"holder.valueOfAssets > 70"];
NSArray *toBeReclaimed = [allAssets filteredArrayUsingPredicate:predicate]; NSLog(@"toBeReclaimed: %@", toBeReclaimed);
toBeReclaimed = nil;
NSLog(@"Giving up ownership of arrays");
allAssets = nil; employees = nil;
}
return 0;
}
Build and run the program. You should see a list of assets:
toBeReclaimed: (
"<Laptop 1: $17, assigned to <Employee 6: $119 in assets>>", "<Laptop 3: $51, assigned to <Employee 5: $136 in assets>>", "<Laptop 5: $85, assigned to <Employee 5: $136 in assets>>", "<Laptop 6: $102, assigned to <Employee 6: $119 in assets>>", "<Laptop 8: $136, assigned to <Employee 9: $136 in assets>>", "<Laptop 9: $153, assigned to <Employee 1: $153 in assets>>"
)
The format string used to create the predicate can be very complex. If you do a lot of filtering of collections, be sure to read Apple’s Predicate Programming Guide.
NSSet/NSMutableSet
A set is a collection that has no sense of order, and a particular object can only appear in a set once. Sets are primarily useful for asking the question “Is it in there?” For example, you might have a set of URLs that are not child-appropriate. Before displaying any web page to a child, you would want to do a quick check to see if the URL is in the set. Sets do this incredibly quickly.
An employee’s assets have no inherent order, and an asset should never appear twice in the same employee’s assets collection. Change your program to use an NSMutableSet instead of an NSMutableArray for the assets relationship.
138
NSSet/NSMutableSet
Figure 21.2 Using NSMutableSet for assets
In Employee.h, change the variable’s declaration:
#import "Person.h" @class Asset;
@interface Employee : Person
{
int employeeID;
NSMutableSet *assets;
}
@property int employeeID;
-(void)addAssetsObject:(Asset *)a;
-(unsigned int)valueOfAssets; @end
In Employee.m, create an instance of the correct class:
- (void)addAssetsObject:(Asset *)a
{
if (!assets) {
assets = [[NSMutableSet alloc] init];
}
[assets addObject:a]; [a setHolder:self];
}
Build and run the program. It should function the same.
You can’t access an object in a set by index because there is no sense of order in a set. Instead, all you can do is ask “Is there one of these in there?” NSSet has a method:
- (BOOL)containsObject:(id)x;
When you send this message to a set, it goes through its collection of objects looking for an object equal to x. If it finds one, it returns YES; otherwise it returns NO.
139
Chapter 21 Collection Classes
This brings us to a rather deep question: what does equal mean? The class NSObject defines a method called isEqual:. To check if two objects are equal, you use the isEqual: method:
if ([myDoctor isEqual:yourTennisPartner]) {
NSLog(@"my doctor is equal to your tennis partner");
}
NSObject has a simple implementation of isEqual:. It looks like this:
- (BOOL)isEqual:(id)other
{
return (self == other);
}
Thus, if you haven’t overridden isEqual:, the code snippet is equivalent to:
if (myDoctor == yourTennisPartner) {
NSLog(@"my doctor is equal to your tennis partner");
}
Some classes override isEqual:. For example, in NSString, isEqual: is overridden to compare the characters in the string. For these classes, there is a difference between equal and identical. Let’s say I have two pointers to strings:
NSString *x = ...
NSString *y = ...
x and y are identical if they contain the exact same address. x and y are equal if the strings they point to contain the same letters in the same order.
Thus, identical objects are always equal. Equal objects are not always identical.
Does this difference matter? Yes. For example, NSMutableArray has two methods:
-(NSUInteger)indexOfObject:(id)anObject;
-(NSUInteger)indexOfObjectIdenticalTo:(id)anObject;
The first steps through the collection asking each object “isEqual:anObject?” The second steps through the collection asking each object “== anObject”?
NSDictionary/NSMutableDictionary
As you know, arrays are indexed by a number; it is easy to ask “Give me object 10.” Dictionaries are indexed by a string; it is easy to ask “Give me the object stored under the key favoriteColor.” More precisely, a dictionary is a collection of key-value pairs. The key is typically a string, and the value can be any sort of object. These key-value pairs are not kept in any particular order.
Let’s make a dictionary of executives. The key will be an executive title, and the value will be an instance of Employee. The first employee will be put in the dictionary under @"CEO"; the second under @"CTO". Change your main.m to create and populate the NSMutableDictionary. Then, print out the dictionary of executives. Finally, set the pointer to the dictionary to nil so that you can see the dictionary being deallocated.
140
NSDictionary/NSMutableDictionary
// Create an array of Employee objects
NSMutableArray *employees = [[NSMutableArray alloc] init];
// Create a dictionary of executives
NSMutableDictionary *executives = [[NSMutableDictionary alloc] init]; for (int i = 0; i < 10; i++) {
// Create an instance of Employee
Employee *person = [[Employee alloc] init];
//Give the instance variables interesting values [person setWeightInKilos:90 + i];
[person setHeightInMeters:1.8 - i/10.0]; [person setEmployeeID:i];
//Put the employee in the employees array [employees addObject:person];
//Is this the first employee?
if (i == 0) {
[executives setObject:person forKey:@"CEO"];
}
// Is this the second employee? if (i == 1) {
[executives setObject:person forKey:@"CTO"];
}
}
…
NSLog(@"allAssets: %@", allAssets);
NSLog(@"executives: %@", executives); executives = nil;
NSPredicate *predicate = [NSPredicate predicateWithFormat: @"holder.valueOfAssets > 70"];
NSArray *toBeReclaimed = [allAssets filteredArrayUsingPredicate:predicate]; NSLog(@"toBeReclaimed: %@", toBeReclaimed);
toBeReclaimed = nil;
NSLog(@"Giving up ownership of arrays");
allAssets = nil; employees = nil;
}
return 0;
}
Build and run the program. The executives dictionary should log itself out:
executives = {
CEO = "<Employee 0: $0 in assets>"; CTO = "<Employee 1: $153 in assets>";
}
141
) "" %% %
( ) * ""$ & G % 5 @-= % 6 5
( * ) =) ! & ) @ ) & * " )!
> ? 2AP ? " I #2AP ? ?$,
C O G ? ' @ ' # N O ? Y ? [' @ '$,
X O 0 0 # N O O Y ? [' @ '$,
? G ? @ I O %
+ 2+ '
( " @ ! B & ) + &) ) L K ) + '' ' " @ ! ( +& & ) !N6N! )' !N6Z !' & !
, & ) + ) )' .-!< ) + ) )N6N! 7
2AP ? " D I ##2AP ?$ $, # D N O #2A2 ) / =$$, # D N O #2A2 ) @ 6 4$$,
&& ' " &
K ) + & + " " ! B & ) ) & Q R L ( N6N! ! ( ; &N6N! @ ! G ; ' 7
!)
%%
2AP ? " I ##2AP ?$ $,
D ? # N O ?$,
C # N O$,
; # N O #2A2$$,
B # N O$,
&&
:; & & N6L " N6%! L " N6' " N6%! ' "! K ) + ) " !
!
This page intentionally left blank