|
|
I hope you are enjoying Programming in Objective-C. I welcome your feedback! Feel free to email your comments to me. Of course, your feedback on Amazon.com would also be appreciated!
Regards,
Steve Kochan
|
|
Updated Resources
|
Updated resources are listed here to supplement those listed in Appendix E of Programming in Objective-C. Please email me with any resources you think should be listed here. Thanks!
|
1. This is from Alex Perez, who is a co-maintainer of the GNUstep.org website:
As co-maintainer of the GNUstep.org website, I noticed that in the
Resources section of your book, there are three URLs to the GNUstep
website, one on page 535 and two on 536. Due to a recent redesign of the
website (check it out, if you haven't, it looks quite nice :), two of the
three URLs are no longer valid. I am working with our server maintainer to
get pernament HTTP redirects set up so they continue to be valid in light
of the fact that it's not very easy to update URLs in books ;-)
On another note, I wanted to let you know that there is a very handy
GNUstep development environment installer for Windows which is available
at
ftp://ftp.gnustep.org/pub/gnustep/windows/Install-GNUstep-Development-Environment-0.5.1-1.9.0.exe
(There's a link on the front page of our site, as well as our download
section). This significantly simplifies the building of GNUstep on Win32.
|
2. This is from André Brière:
The latest versions (1.5.X) of Cygwin support Objective-C. Their FAQ states the
opposite, but it seems outdated. I have 1.5.7 and gcc compiles Objective-C code just fine.
|
|
Download Program Examples
|
Return to top
|
The program examples are archived in tar format. To extract the archive, first download the file to your disk, then run tar on the archive. Note that some browsers will automatically extract the archive into a folder for you. Otherwise, you can run tar like this
tar xvf examples.tar
Click here to download examples
Please let me know if you need the examples in some other format.
|
|
Errata
|
Return to top
|
Following is errata from the first and second printings of Programming in Objective-C.
If you spot any other errors, please send me an email and let me know. Thanks!
|
Page | Errata |
-- |
The following
applies to readers using Xcode for the first part of the book: "If you
use Xcode instead of the command-line tools, you will need to delete
the contents of the automatically-generated ..._Prefix.pch file as well
as the #import line at the top of main.m each time you start a project
(the book only specifies the latter)." [Thanks to KIeth Blount] |
1 |
The statement about GCC being in the public domain is
false. The copyrights for all Free Software Foundation products are owned
by the FSF. It is released under the GNU General
Public License. [Thanks to Alex Perez] |
9 |
In the first gcc example, the comment "Compile main.c and call it prog1" should be in italics and not bold [Thanks to David Bayendor] |
56 |
In line 10, change "Objective-C (25) would take place." to read "c (25) would take place." [Thanks to John Flanigan] |
68 |
There are two extra lines of output shown for Program 4.7.
[Thanks to Ryan Govostes] |
88 |
For Program 5.7, the greatest common divisor of 1026 and 540 is 54 (not 27).
[Thanks to Alex Eagar] |
89 |
In lines 6 and 7, change the ÷ character to a % character.
[Thanks to Ryan Govostes] |
92 |
Exercise 4 should refer to Program 5.3A. [Thanks to John Flanigan] |
145 |
Exercises 6 and 7 should refer to Exercise 7 from Chapter 4. [Thanks to John Flanigan] |
145 |
Exercise 6: add: method should read -(Complex *) add: (Complex *) complexNum; Also, the sum for the example shoud be 8.0 + 11i [Thanks to John Flanigan] |
159 |
Program 8.6: In -(void) setX: (int) xVal; andY: (int) yVal remove the embedded semicolon to read
-(void) setX: (int) xVal andY: (int) yVal |
174 |
Exercise
6: In the example, the origin of the intersecting rectangle should be
(400, 420) and not (400, 380). [Thanks to Matthew Woolums] |
233 |
The brackets are wrong in the MakeFract macro definition. Change it to read #define MakeFract(x,y) ([[Fraction alloc] initWith: x over: y])
[Thanks to Ingo Paulsen] |
355 |
(2nd printing only) Program 15.14: Add a semicolon to the end of the line that reads AddressCard *myCard |
367 |
Program 15.18: Change the line that reads if ([set1 isEqualToSet: set2] == NO) to read if ([set1 isEqualToSet: set2] == YES)
[Thanks to Alex Eagar] |
390 |
(2nd printing only) Program 16.6: Add a declaration to the program: BOOL fileExists;
|
533 |
My email address is incorrect. It should be steve@kochan-wood.com |
Below is listed errata from the first printing of the book.
|
Page | Errata |
-- |
There
are many examples that were not formatted correctly due to a problem
with the publisher's typsetting software. The programs will still run
correctly and the formatting will be corrected in the next printing.
I'm sorry about that. |
92 |
Exercise 3: 5! is 120, not 1 as shown |
120, 123, 339 |
In
all three places the number 2 should be displayed as the first prime
number (the publisher hasn't been able to explain this one to me!) |
141 |
Delete the third line of output from Program 7.5. [Thanks to Ingo Paulsen] |
149 |
Figure 8.3: There should be a directed line from the first x to the second x; There should be a directed line from the first initVar to the second initVar |
152 |
Correct method name is -(void) setWidth: (int) w andHeight: (int) h in two places. [Thanks to Francisco Garuti] |
158 |
In Program 8.6, change the first line from #include "Point.h" to #import "Point.h" |
180 |
Program 9.2: remove the line [dataValue free]; from the end of main |
198 |
Inside method allocF the statement should read ++gCounter; and not ++counter;
|
202 |
Program 10.3: Change the line enum month aMonth; to read enum month amonth;
|
214 |
Program 11.1: Inside method mul: a [ is missing at the beginning of the line that starts result setTo: numerator * ... |
225 |
Exercise 5: The initWithside: method should return a Square object and the setSide: method no value (that is, type void) |
229 |
Change the line that reads return TWO_PI * r; to read return TWO_PI * radius; [Thanks to Ingo Paulsen] |
248 |
Change the line about Fibonacci numbers to read: Thereafter, each successive Fibonacci number Fi is defined to be the sum of the two preceding Fibonacci numbers Fi-2 and Fi-1. |
278 |
Program 13.10: In the line that reads printf ("Today's date is %i/%i/.2%i.\n", change .2%i to %.2i
|
342 |
Program 15.9: Change NSAutoreleasepool to NSAutoreleasePool |
345 |
Program 15.10: Insert #import <Foundation/NSAutoreleasePool.h> at the beginning of the program. Change NSAutoreleasepool to NSAutoreleasePool in the program. |
347 |
Insert a closing } at the end of the list method.
|
354 |
(BOOL) isEqual should be -(BOOL) isEqual |
355 |
Program 15.14: Change the line that reads AddressCard *myCard = [AddressBook alloc]; to read AddressCard *myCard; |
370 |
Exercise 7 is really part of Exercise 6. |
383 |
Program 16.4: Add a closing > after #import <NSAutoreleasePool.h |
390 |
Program 16.6: Change the line NSArray *args = [NSProcessInfo arguments]; to read NSArray *args = [proc arguments];
In the statement [NSFm fileExistsAtPath: dest isDirectory: &isDir]; the result returned from the method should also be tested in the if that follows to see if the file exists and is a directory (the value of isDir is meaningless if the file does not exist) |
402 |
Program 17.1: Remove the [ from in front of the printf. |
410-411 |
Change the "Foo dealloc" message in the dealloc method to "ClassA dealloc". The output from Program 17.5 should then be changed acordingly, as well as the reference in the text on page 411. |
448 |
Program 19.12: Insert the line #import <Foundation/NSArray.h> after the line #import <Foundation/NSArchiver.h> |
|
Answers to Odd-Numbered Exercises
|
Return to top
|
As a result of the feedback I received, I am posting the answers to the
odd-numbered exercises. So far I have posted all but one answer (from
Chapter 15). |
Chapter 2
Chapter 3
Chapter 4
Chapter 5
Chapter 6
Chapter 7
Chapter 8
Chapter 9
Chapter 10
Chapter 11
Chapter 12
Chapter 13
Chapter 14
Chapter 15
Chapter 16
Chapter 17
Chapter 18
Chapter 19
|
Chapter 2
2-3
Testing.......1...2..3
2-5
1. Semicolon should not appear at the end of the first line
2. Code for main should start with a { and not a (
3. Keyword INT should be int
4. Comment /* COMPUTE RESULT should be terminated with a */
5. Missing semicolon at end of statement sum = 25 + 37 - 19
6. Comment for DISPLAY RESULTS is wrong; either use a /* .. */ pair or being the line with //
7. String inside printf should be enclosed in double quotes, not single quotes
8. Missing a comma before the second argument to printf
Chapter 3
3-1
6_05 is invalid because it starts with a number
A$ is invalid because it contains an invalid character (the $)
3-5
The advantages are that you can apply the same method name to verhicles
from different classes. In other words, you can send the "prep" message
to a vehicle, and that vehicle could be a Car, a Motorcycle, or a Boat.
You don't have to figure out what vehicle type is first. This feature is
known as polymorphism, and is discussed in greater detail in Chapter 9.
3-7
#include <objc/Object.h>
@interface Point: Object
{
int x;
int y;
}
-(void) setX: (int) xVal;
-(void) setY: (int) yVal;
-(int) x;
-(int) y;
@end
@implementation Point;
-(void) setX: (int) xVal
{
x = xVal;
}
-(void) setY: (int) yVal
{
y = yVal;
}
-(int) x
{
return x;
}
-(int) y
{
return y;
}
@end
int main (int argc, char *argv[])
{
Point *pt1, *pt2;
pt1 = [[Point alloc] init];
pt2 = [[Point alloc] init];
// set first point to (100, 200)
[pt1 setX: 100];
[pt1 setY: 200];
// set second point to (-20, 55)
[pt2 setX: -20];
[pt2 setY: 55];
// retrieve and display values
printf ("Pt1 = (%i, %i)\n", [pt1 x], [pt1 y]);
printf ("Pt2 = (%i, %i)\n", [pt2 x], [pt2 y]);
// release their memory
[pt1 free];
[pt2 free];
return 0;
}
Chapter 4
4-1
0996 '9' is not a valid octal digit
0x10.5 An exponent is required for a hexadecimal floating constant
1.2Fe-7 Can't use 'F' and 'e' together
98.7U 'U' is not a valid suffix for a floating constant
0X0G1 'G' is not a valid hexadecimal digit
17777s 's' is not a valid qualifier
15,000 Commas are not permitted in numbers
4-3
d = d
4-5
#import <stdio.h>
int main (int argc, char *argv[])
{
double result;
result = (3.31e-8 * +2.01e-7) / (7.16e-6 + 2.01e-8);
printf ("result = %g\n", result);
return 0;
}
4-7
#import <objc/Object.h>
#import <stdio.h>
@interface Rectangle: Object
{
int width;
int height;
}
-(void) setWidth: (int) w;
-(void) setHeight: (int) h;
-(int) width;
-(int) height;
-(int) area;
-(int) perimeter;
@end
@implementation Rectangle;
-(void) setWidth: (int) w
{
width = w;
}
-(void) setHeight: (int) h
{
height = h;
}
-(int) width
{
return width;
}
-(int) height
{
return height;
}
-(int) area
{
return width * height;
}
-(int) perimeter
{
return (width + height) * 2;
}
@end
int main (int argc, char *argv[])
{
Rectangle *myRect = [[Rectangle alloc] init];
[myRect setWidth: 5];
[myRect setHeight: 8];
printf ("Rectangle: w = %i, h = %i\n", [myRect width], [myRect height]);
printf ("Area = %i, Perimeter = %i\n", [myRect area], [myRect perimeter]);
[myRect free];
return 0;
}
4-9
#import <objc/Object.h>
#import <stdio.h>
@interface Calculator: Object
{
double accumulator;
}
// accumulator methods
-(void) setAccumulator: (double) value;
-(void) clear;
-(double) accumulator;
// arithmetic methods
-(double) add: (double) value;
-(double) subtract: (double) value;
-(double) multiply: (double) value;
-(double) divide: (double) value;
-(double) changeSign;
-(double) reciprocal;
-(double) xSquared;
@end
@implementation Calculator;
-(void) setAccumulator: (double) value
{
accumulator = value;
}
-(void) clear
{
accumulator = 0;
}
-(double) accumulator
{
return accumulator;
}
-(double) add: (double) value
{
accumulator += value;
return accumulator;
}
-(double) subtract: (double) value
{
accumulator -= value;
return accumulator;
}
-(double) multiply: (double) value
{
accumulator *= value;
return accumulator;
}
-(double) divide: (double) value
{
accumulator /= value;
return accumulator;
}
-(double) changeSign
{
accumulator = -accumulator;
return accumulator;
}
-(double) reciprocal
{
accumulator = 1 / accumulator;
return accumulator;
}
-(double) xSquared
{
accumulator *= accumulator;
return accumulator;
}
@end
int main (int argc, char *argv[])
{
Calculator *myCalc;
myCalc = [[Calculator alloc] init];
[myCalc clear];
[myCalc setAccumulator: 10.0]; // acc = 10.
[myCalc xSquared]; // acc = 100.
[myCalc reciprocal]; // acc = 1/100.
[myCalc changeSign]; // acc = -1/100
printf ("The result is %g\n", [myCalc accumulator]);
[myCalc free];
return 0;
}
Chapter 5
5-1
// Program to generate a table of triangular numbers
#import <stdio.h>
int main (int argc, char *argv[])
{
int n, nSquared;
printf ("TABLE OF SQUARESn\n");
printf (" n n squared\n");
printf ("--- ---------------\n");
nSquared = 1;
for ( n = 1; n <= 10; ++n ) {
nSquared = n * n;
printf ("%2i %i\n", n, nSquared);
}
return 0;
}
5-3
// Program to generate a table of factorials
#import <stdio.h>
int main (int argc, char *argv[])
{
int n, nFactorial;
printf ("TABLE OF FACTORIALS\n");
printf (" n n!\n");
printf ("--- ---------------\n");
nFactorial = 1;
for ( n = 1; n <= 10; ++n ) {
nFactorial *= n;
printf ("%2i %8i\n", n, nFactorial);
}
return 0;
}
5-5
#import <stdio.h>
int main (int argc, char *argv[])
{
int n, number, triangularNumber, counter, numReps;
printf ("How many triangular numbers do you want? ");
scanf ("%i", &numReps);
for ( counter = 1; counter <= numReps; ++counter ) {
printf ("What triangular number do you want? ");
scanf ("%i", &number);
triangularNumber = 0;
for ( n = 1; n <= number; ++n )
triangularNumber += n;
printf ("Triangular number %i is %i\n\n", number, triangularNumber);
}
return 0;
}
5-7
Each digit would be preceded by a minus sign.
A number like -123 would display as -3-2-1.
Chapter 6
6-1
#import <stdio.h>
int main (int argv, char *argc[])
{
int n1, n2;
printf ("Enter your two integers: ");
scanf ("%i %i", &n1, &n2);
if ( n1 % n2 == 0 )
printf ("%i is evenly divisible by %i\n", n1, n2);
else
printf ("%i is not evenly divisible by %i\n", n1, n2);
return 0;
}
6-3
// This goes a little further than the exercise
// called for by also display fractions like 10/2 as 5.
-(void) print
{
if (numerator == 0)
printf (" 0 ");
else if (numerator % denominator == 0)
printf (" %i ", numerator / denominator);
else
printf (" %i/%i ", numerator, denominator);
}
6-5
// Program to reverse the digits of a number
// Modified to handle negative numbers
#import <objc/Object.h>
#import <stdio.h>
int main (int argc, char *argv[])
{
int number, right_digit;
BOOL isNeg;
printf ("Enter your number: ");
scanf ("%i", &number);
// set flag and negate number if negative
if (number < 0 ) {
isNeg = YES;
number = -number;
}
else
isNeg = NO;
do {
right_digit = number % 10;
printf ("%i", right_digit);
number /= 10;
}
while ( number != 0 );
// display minus sign if number was negative
if (isNeg == YES)
printf ("-");
printf ("\n");
return 0;
}
6-7
// Program to generate a table of prime numbers
#import <stdio.h>
#import <objc/Object.h>
int main (int argc, char *argv[])
{
int p, d;
BOOL isPrime;
printf (" 2 "); // first prime is 2
for ( p = 3; p <= 50; p += 2 ) {
isPrime = YES;
for ( d = 3; d < p && isPrime == YES; ++d )
if ( p % d == 0 )
isPrime = NO;
if ( isPrime == YES )
printf ("%i ", p);
}
printf ("\n");
return 0;
}
Chapter 7
7-1
-(Fraction *) subtract: (Fraction *) f
{
// To sub two fractions:
// a/b - c/d = ((a*d) - (b*c)) / (b * d)
Fraction *result = [[Fraction alloc] init];
int resultNum, resultDenom;
resultNum = (numerator * [f denominator]) -
(denominator * [f numerator]);
resultDenom = denominator * [f denominator];
[result setTo: resultNum over: resultDenom];
[result reduce];
return result;
}
-(Fraction *) multiply: (Fraction *) f
{
Fraction *result = [[Fraction alloc] init];
[result setTo: numerator * [f numerator]
over: denominator * [f denominator]];
[result reduce];
return result;
}
-(Fraction *) divide: (Fraction *) f
{
Fraction *result = [[Fraction alloc] init];
[result setTo: numerator * [f denominator]
over: denominator * [f numerator]];
[result reduce];
return result;
}
7-3
Just add the message expression
[sum print];
to the program after the sum has been calculated
7-5
-(void) print
{
if (numerator >= denominator)
printf (" %i", numerator / denominator);
if (numerator % denominator != 0)
printf (" %i/%i ", numerator % denominator, denominator);
}
Chapter 8
8-1
// Simple example to illustrate inheritance
#import <objc/Object.h>
#import <stdio.h>
// ClassA declaration and definition
@interface ClassA: Object
{
int x;
}
-(void) initVar;
@end
@implementation ClassA;
-(void) initVar
{
x = 100;
}
@end
// Class B declaration and definition
@interface ClassB : ClassA
-(void) printVar;
@end
@implementation ClassB;
-(void) printVar
{
printf ("x = %i\n", x);
}
@end
// Class C declaration and definition
@interface ClassC : ClassB
-(void) initVar;
@end
@implementation ClassC;
-(void) initVar
{
x = 300;
}
@end
int main (int argc, char *argv[])
{
ClassA *a = [[ClassA alloc] init];
ClassB *b = [[ClassB alloc] init];
ClassC *c = [[ClassC alloc] init];
[a initVar]; // sets a's instance var to 100
[b initVar]; // sets b's instance var to 100
[c initVar]; // sets c's instance var to 300
// Note ClassA has no printVar method
[b printVar]; // displays 100
[c printVar]; // displays 300
[a free];
[b free];
[c free];
return 0;
}
8-3
// Class B2 declaration and definition
@interface ClassB2: ClassA
-(void) printVar;
@end
@implementation ClassB;
-(void) printVar
{
printf ("x = %i\n", x);
}
@end
1. ClassB and ClassB2 are both subclasses of Class A
2. Object (root)
|
ClassA
|
___________
| |
ClassB ClassB2
3. The superclass of ClassB is ClassA
4. The superclass of ClassB2 is ClassA
5. A class can have any number of subclasses, but only one
superclass
8-5
// Note that this exercise uses the sqrt function from the standard
// math library <math.h> to calculate the area of a triangle.
// To link this routine with gcc, you may need to use the following
// command line:
//
// gcc prog.m -lobjc -lm
//
// I apologize for not supplying the formula to calculate the area of
// of a triangle.
//
#import <objc/Object.h>
#import <math.h>
// ************ GraphicObject Class
@interface GraphicObject : Object
{
int fillColor; // 32-bit color
BOOL filled; // Is the object filled?
int lineColor; // 32-bit line color
}
-(void) setFillColor: (int) theColor;
-(void) setFilled: (int) isFilled;
-(void) setLineColor: (int) theLineColor;
-(int) fillColor;
-(BOOL) filled;
-(int) lineColor;
@end
@implementation GraphicObject;
-(void) setFillColor: (int) theColor
{
fillColor = theColor;
}
-(void) setFilled: (int) isFilled
{
filled = isFilled;
}
-(void) setLineColor: (int) theLineColor
{
lineColor = theLineColor;
}
-(int) fillColor
{
return fillColor;
}
-(BOOL) filled
{
return filled;
}
-(int) lineColor
{
return lineColor;
}
@end
// ************ Point class
@interface Point: Object
{
int x;
int y;
}
-(void) setX: (int) xVal;
-(void) setY: (int) yVal;
-(void) setX: (int) xVal andY: (int) yVal;
-(int) x;
-(int) y;
@end
@implementation Point;
-(void) setX: (int) xVal
{
x = xVal;
}
-(void) setY: (int) yVal
{
y = yVal;
}
-(void) setX: (int) xVal andY: (int) yVal
{
x = xVal;
y = yVal;
}
-(int) x;
{
return x;
}
-(int) y;
{
return y;
}
@end
// ************ Rectangle subclass
@interface Rectangle : GraphicObject
{
int width;
int height;
Point *origin;
}
-(void) setWidth: (int) w;
-(void) setHeight: (int) h;
-(void) setWidth: (int) w andHeight: (int) h;
-(void) setOrigin: (Point *) pt;
-(Point *) origin;
-(int) width;
-(int) height;
-(int) area;
-(int) perimeter;
@end
@implementation Rectangle;
-(void) setWidth: (int) w
{
width = w;
}
-(void) setHeight: (int) h
{
height = h;
}
-(void) setWidth: (int) w andHeight: (int) h
{
width = w;
height = h;
}
-(void) setOrigin: (Point *) pt
{
origin = pt;
}
-(int) width
{
return width;
}
-(int) height
{
return height;
}
-(int) area
{
return width * height;
}
-(int) perimeter
{
return (width + height) * 2;
}
-(Point *) origin
{
return origin;
}
@end
// ************ Circle subclass
@interface Circle : GraphicObject
{
int radius; // this can be stored as a float if you like
Point *center;
}
-(void) setRadius: (int) r;
-(int) radius;
-(float) area;
-(float) circumference;
@end
@implementation Circle;
-(void) setRadius: (int) r
{
radius = r;
}
-(int) radius
{
return radius;
}
-(float) area
{
return 3.141592654 * radius * radius;
}
-(float) circumference
{
return 2 * 3.141592654 * radius;
}
@end
// ************ Triangle class
@interface Triangle : GraphicObject
{
int side1;
int side2;
int side3;
}
-(void) setSide1: (int) s1 andSide2: (int) s2 andSide3: (int) s3;
-(int) side1;
-(int) side2;
-(int) side3;
-(float) area;
-(int) perimeter;
@end
@implementation Triangle;
-(void) setSide1: (int) s1 andSide2: (int) s2 andSide3: (int) s3
{
side1 = s1;
side2 = s2;
side3 = s3;
}
-(int) side1
{
return side1;
}
-(int) side2
{
return side2;
}
-(int) side3
{
return side3;
}
-(float) area
{
float s;
s = (side1 + side2 + side3) / 2.0;
return sqrt (s * (s - side1) * (s - side2) * (s - side3));
}
-(int) perimeter
{
return side1 + side2 + side3;
}
@end
// Small test program follows
int main (int argc, char *argv[])
{
Rectangle *rect = [[Rectangle alloc] init];
Circle *circ = [[Circle alloc] init];
Triangle *tri = [[Triangle alloc] init];
[rect setWidth: 15 andHeight: 12];
[circ setRadius: 5];
[tri setSide1: 6 andSide2: 8 andSide3: 10];
// You could also take advantage of any of
// the inherited methods from the GraphicObject
// class, for example:
[rect setFilled: YES];
[circ setLineColor: 0];
[tri setFillColor: 0xFFFFFF];
printf ("Area of rectangle, width = %i, height = %i is %i\n\n",
[rect width], [rect height], [rect area]);
printf ("Circumference of circle with radius %i is %g\n",
[circ radius], [circ circumference]);
printf ("Area is %g\n\n", [circ area]);
printf ("Perimeter of triangle with sides %i, %i, and %i is %i\n",
[tri side1], [tri side2], [tri side3], [tri perimeter]);
printf ("Area is %g\n", [tri area]);
[rect free];
[circ free];
[tri free];
return 0;
}
8-7
-(void) draw
{
int w, h;
if (height == 0)
return;
// top line
for (w = 1; w <= width; ++w)
printf ("-");
printf ("\n");
// draw the sides
for (h = 1; h <= height; ++h) {
for (w = 1; w <= width; ++w)
if (w == 1 || w == width)
printf ("|");
else
printf (" ");
printf ("\n");
}
// bottom line
for (w = 1; w <= width; ++w)
printf ("-");
printf ("\n");
}
Chapter 9
9-1
The Complex class does not have a "reduce" method. So the compiler will
give you a warning message. If you run the program anyway, you will also
get a runtime error when the system tries to find the method at runtime.
9-3
// Added print method for Point class
-(void) print
{
printf (" (%i, %i) ", x, y);
}
// Test program
#import "Fraction.h"
#import "Complex.h"
#import "Point.h"
int main (int argc, char *argv[])
{
id dataValue;
Fraction *f1 = [[Fraction alloc] init];
Complex *c1 = [[Complex alloc] init];
Point *p1 = [[Point alloc] init];
[f1 setTo: 2 over: 5];
[c1 setReal: 10.0 andImaginary: 2.5];
[p1 setX: 100 andY: 200];
// first dataValue gets a fraction
dataValue = f1;
[dataValue print];
printf ("\n");
// now dataValue gets a complex number
dataValue = c1;
[dataValue print];
printf ("\n");
// now dataValue gets a point
dataValue = p1;
[dataValue print];
printf ("\n");
[c1 free];
[f1 free];
[p1 free];
return 0;
}
9-5
The first two results are "NO" and the remaining are "YES"
Chapter 10
10-3
static int gFractionAdds;
-(Fraction *) add: (Fraction *) f
{
// To add two fractions:
// a/b + c/d = ((a*d) + (b*c)) / (b * d)
// result will store the result of the addition
Fraction *result = [[Fraction alloc] init];
int resultNum, resultDenom;
resultNum = (numerator * [f denominator]) +
(denominator * [f numerator]);
resultDenom = denominator * [f denominator];
[result setTo: resultNum over: resultDenom];
[result reduce];
++gFractionAdds; // Number of fractions added
return result;
}
// Method to return the number of additions
-(int) numAdditions
{
return gFractionAdds;
}
10-5
typedef Fraction *FractionObj;
10-7
// See if sign extension occurs
// Assumes an 8-bit char
int main (int argc, char *argv[])
{
char c1 = 255; // all 8 bits on
int i1;
// See if sign extension occurs
i1 = c1;
// Will print 255 if no sign extension,
// -1 otherwise
printf ("%i\n", i1);
return 0;
}
Chapter 11
11-1
#import "Fraction.h"
@interface Fraction (MathOps)
-(Fraction *) add: (Fraction *) f;
-(Fraction *) mul: (Fraction *) f;
-(Fraction *) sub: (Fraction *) f;
-(Fraction *) div: (Fraction *) f;
-(Fraction *) invert;
@end
@implementation Fraction (MathOps)
// include previous add:, mul:, sub:, and div: methods
-(Fraction *) invert
{
Fraction *result = [[Fraction alloc] init];
[result setTo: denominator over: numerator];
return result;
}
@end
11-3
#import "Calculator.h"
#import <math.h>
// Note: These methods really should not take arguments but instead
// should work on the contents of the accumulator. But here is the
// solution as the problem was stated in the text.
@interface Calculator (Trig)
-(void) sin: (double) angle;
-(void) cos: (double) angle;
-(void) tan: (double) angle;
@end
@implementation Calculator (Trig)
-(void) sin: (double) angle
{
accumulator = sin (angle);
}
-(void) cos: (double) angle
{
accumulator = cos (angle);
}
-(void) tan: (double) angle
{
accumulator = tan (angle);
}
@end
11-5
#import "Square.h"
@implementation Square
{
Rectangle *rect;
}
-(Square *) initWithSide: (int) s
{
self = [super init];
if (self) {
rect = [[Rectangle alloc] init];
[rect setWidth: s andHeight: s];
}
return self;
}
-(void) setSide: (int) s
{
[rect setWidth: s andHeight: s];
}
-(int) side
{
return [rect width];
}
-(int) area
{
return [rect area];
}
-(int) perimeter
{
return [rect perimeter];
}
-(id) free
{
[rect free];
return [super free];
}
@end
// Simple test program follows
#import <stdio.h>
int main (int argc, char *argv[])
{
Square *mySquare = [[Square alloc] initWithSide: 7];
printf ("Square with side: %i, perimeter = %i, area = %i\n",
[mySquare side], [mySquare perimeter], [mySquare area]);
[mySquare free];
return 0;
}
Chapter 12
12-3
#define MAX(a,b,c) ( ((a) > (b)) ? \
((a) > (c) ? (a) : (c)) : \
((b) > (c) ? (b) : (c)) )
int main (int argc, char *argv[])
{
printf ("%i %i %i %i %i %i\n", MAX (1,2,3), MAX(1,3,2),
MAX(3,1,2), MAX(3,2,1), MAX(2,1,3), MAX(2,3,1));
return 0;
}
12-5
#define IS_ALPHABETIC(c) (IS_LOWER_CASE(c) || IS_UPPER_CASE(c))
12-7
#define ABSOLUTE_VALUE(x) ((x) < 0 ? -(x) : (x))
Chapter 13
13-1
float average (float data[])
{
int i;
float sum, average;
for (i = 0; i < 10; ++i)
sum += data[i];
average = sum / 10;
return average;
}
13-3
// Prime numbers generated with Sieve of Erasthothenes
int main (int argc, char *argv[])
{
int P[151], i, j;
int n = 150;
for (i = 2; i <= n; ++i)
P[i] = 0;
i = 2;
while (i <= n) {
if (P[i] == 0)
printf ("%i ", i);
j = 1;
while (i * j <= n) {
P[i * j] = 1;
++j;
}
++i;
}
return 0;
}
13-5
typedef struct date {
int month;
int day;
int year;
} Date;
13-7
They are all valid and each printf from a set produces the same output.
Chapter 14
14-3
Just make sure that the parent of the Fraction class is NSObject
and not Object, and that the header file <Foundation/NSObject.h> is
imported instead of <objc/Object.h>.
Chapter 15
15-1
// I apologize! This exercise is harder than I realized when I wrote it!
//
#import <Foundation/NSObject.h>
#import <Foundation/NSAutoreleasePool.h>
#import <Foundation/NSString.h>
#import <Foundation/NSCalendarDate.h>
@interface NSCalendarDate (ElapsedDays)
-(unsigned long) numberOfElapsedDays: (NSCalendarDate *) theDate;
@end
@implementation NSCalendarDate (ElapsedDays)
-(unsigned long) numberOfElapsedDays: (NSCalendarDate *) theDate
{
int elapsedDays;
[self years: 0 months: 0 days: &elapsedDays hours: 0
minutes: 0 seconds: 0 sinceDate: theDate];
if (elapsedDays >= 0)
return (unsigned long) elapsedDays;
else
return (unsigned long) -elapsedDays;
}
@end
int main (int argc, char *argv[])
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSCalendarDate *today = [NSCalendarDate calendarDate];
NSCalendarDate *threeWeeksAgo;
threeWeeksAgo = [today dateByAddingYears: 0 months: 0
days: -21 hours: 0 minutes: 0 seconds: 0];
NSLog (@"%@\n", today);
NSLog (@"%@\n", threeWeeksAgo);
printf ("elapsed days is %i\n",
[today numberOfElapsedDays: threeWeeksAgo]);
[pool release];
return 0;
}
15-3
// lookup address card by name -- assumes an exact match
-(NSMutableArray *) lookup: (NSString *) theName
{
AddressCard *nextCard;
NSMutableArray *matches = nil; // to hold the matches
int i, elements;
elements = [book count];
for ( i = 0; i < elements; ++i) {
nextCard = [book objectAtIndex: i];
// if we find a match, add it to the array matches
if ( [[nextCard name] caseInsensitiveCompare: theName]
== NSOrderedSame ) {
if (matches == nil) // create the array if its nil
matches = [NSMutableArray arrayWithCapacity: 10];
[matches addObject: nextCard];
}
}
return matches;
}
15-5
// lookup any string contained in any field of all address cards
-(NSMutableArray *) lookup: (NSString *) search
{
AddressCard *nextCard;
NSMutableArray *matches = nil; // to hold the matches
int i, elements;
elements = [book count];
for ( i = 0; i < elements; ++i) {
nextCard = [book objectAtIndex: i];
// search both fields for a match and add to the array
// matches if found
// note: if you completed ex. 3, then you would also
// add tests here for the new fields you added
if ( [[nextCard name] caseInsensitiveCompare: search]
== NSOrderedSame || [[nextCard email]
caseInsensitiveCompare: search] == NSOrderedSame) {
if (matches == nil) // create the array if its nil
matches = [NSMutableArray arrayWithCapacity: 10];
[matches addObject: nextCard];
}
}
return matches;
}
For the last part of the question, one approach is to redesign your
AddressCard so the fields are stored inside a dictionary. In that way,
an AddressBook method like "lookup" can sequence through all of the
fields in an AddressCard by enumerating the dictionary.
15-7
// Note: This is labeled as Exercise 8 in the book, but is really 7 (see errata)
#import "Fraction.h"
#import <Foundation/NSAutoreleasePool.h>
#import <Foundation/NSArray.h>
int main (int argc, char *argv[])
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
Fraction *f1 = [[Fraction alloc] init];
Fraction *f2 = [[Fraction alloc] init];
Fraction *f3 = [[Fraction alloc] init];
Fraction *f4 = [[Fraction alloc] init];
NSArray *fractions = [NSArray arrayWithObjects: f1, f2, f3, f4, nil];
Fraction *sum, *sum2;
int i, nFracts;
[f1 setTo: 1 over: 4];
[f2 setTo: 1 over: 2];
[f3 setTo: 1 over: 8];
[f4 setTo: 1 over: 16];
nFracts = [fractions count];
// set the sum to the first fraction
sum = [fractions objectAtIndex: 0];
// add up the remaining fractions
for (i = 1; i < nFracts; ++i) {
sum2 = [sum add: [fractions objectAtIndex: i]];
[sum release];
sum = sum2; // we use sum2 to avoid memory leakage
}
// Display the final sum
printf ("The sum is "); [sum print]; printf ("\n");
[sum release];
// f1-f4 get released from the array when the autorelease pool
// gets released
[pool release];
return 0;
}
15-9
//
// Answer to this exercise is forthcoming!!
//
Chapter 16
16-1
// Implement a copy command for multiple file copying
#import <Foundation/NSString.h>
#import <Foundation/NSArray.h>
#import <Foundation/NSFileManager.h>
#import <Foundation/NSAutoreleasePool.h>
#import <Foundation/NSPathUtilities.h>
#import <Foundation/NSProcessInfo.h>
int main (int argc, char *argv[])
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSFileManager *NSFm;
NSString *source, *dest;
BOOL destExists, isDir;
NSProcessInfo *proc = [NSProcessInfo processInfo];
NSArray *args = [proc arguments];
int numArgs = [args count];
int i;
NSFm = [NSFileManager defaultManager];
// Check for at least two arguments on the command line
if (numArgs < 2 || numArgs < 3) {
printf ("Usage: %s s1 [s2 ...] dest\n", [[proc processName] cString]);
return 1;
}
dest = [args objectAtIndex: numArgs - 1];
// See if the destination file is a directory and make
// sure it already exists (note that copyPath:toPath:handler
// will create directories in a path if they don't exist
destExists = [NSFm fileExistsAtPath: dest isDirectory: &isDir];
if (numArgs > 3 && (destExists == NO || isDir == NO)) {
printf ("A destination dir is needed for multiple files\n");
return 2;
}
// Now copy the files
for (i = 1; i < numArgs - 1; ++i) {
source = [args objectAtIndex: i];
// Make sure the source file can be read
if ([NSFm isReadableFileAtPath: source] == NO) {
printf ("Can't read %s\n", [source cString]);
continue; // try the next file
}
dest = [args objectAtIndex: numArgs - 1];
destExists = [NSFm fileExistsAtPath: dest isDirectory: &isDir];
// If destination is a directory, add the source name to the
// end of the destination
if (destExists == YES && isDir == YES)
dest = [dest stringByAppendingPathComponent:
[source lastPathComponent]];
[NSFm removeFileAtPath: dest handler: nil];
// Okay, time to perform the copy
if ([NSFm copyPath: source toPath: dest handler: nil] == NO)
printf ("%s: copy failed!\n", [source cString]);
else
printf ("%s: copy succeeeded\n", [source cString]);
}
[pool release];
return 0;
}
16-3
// Duplicate basic function of Unix basename command
// Note: this does not handle the optional suffix argument
#import <Foundation/NSString.h>
#import <Foundation/NSArray.h>
#import <Foundation/NSFileManager.h>
#import <Foundation/NSAutoreleasePool.h>
#import <Foundation/NSPathUtilities.h>
#import <Foundation/NSProcessInfo.h>
int main (int argc, char *argv[])
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSFileManager *NSFm;
NSString *path;
NSProcessInfo *proc = [NSProcessInfo processInfo];
NSArray *args = [proc arguments];
int numArgs = [args count];
NSFm = [NSFileManager defaultManager];
// Check for one argument on the command line
if (numArgs != 2) {
printf ("Usage: %s path\n", [[proc processName] cString]);
return 1;
}
path = [args objectAtIndex: numArgs - 1];
printf ("%s\n", [[path lastPathComponent] cString]);
[pool release];
return 0;
}
// Duplicate basic function of Unix dirname command
#import <Foundation/NSString.h>
#import <Foundation/NSArray.h>
#import <Foundation/NSFileManager.h>
#import <Foundation/NSAutoreleasePool.h>
#import <Foundation/NSPathUtilities.h>
#import <Foundation/NSProcessInfo.h>
int main (int argc, char *argv[])
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSFileManager *NSFm;
NSString *path;
NSProcessInfo *proc = [NSProcessInfo processInfo];
NSArray *args = [proc arguments];
NSMutableArray *components;
int numArgs = [args count];
NSFm = [NSFileManager defaultManager];
// Check for one argument on the command line
if (numArgs != 2) {
printf ("Usage: %s path\n", [[proc processName] cString]);
return 1;
}
path = [args objectAtIndex: numArgs - 1];
// pathComponents returns an NSArray object, so we'll copy
// it into an NSMutableArray so we can remove its last element
components = [NSMutableArray arrayWithArray: [path pathComponents]];
// remove the last component of the array if more than one entry
if ([components count] > 1)
[components removeObjectAtIndex: [components count] - 1];
// now reconstruct it back into a path
path = [NSString pathWithComponents: components];
printf ("%s\n", [path cString]);
[pool release];
return 0;
}
16-5
#include <Foundation/NSString.h>
#include <Foundation/NSProcessInfo.h>
#include <Foundation/NSPathUtilities.h>
@interface NSString (TempFiles)
+(NSString *) temporaryFileName;
@end
@implementation NSString (TempFiles)
+(NSString *) temporaryFileName
{
NSProcessInfo *proc = [NSProcessInfo processInfo];
NSString *tempdir = NSTemporaryDirectory ();
return [tempdir stringByAppendingPathComponent:
[proc globallyUniqueString]];
}
16-7
// Copy the contents of file typed on command line to terminal
#import <Foundation/NSObject.h>
#import <Foundation/NSString.h>
#import <Foundation/NSFileHandle.h>
#import <Foundation/NSProcessInfo.h>
#import <Foundation/NSAutoreleasePool.h>
#import <Foundation/NSData.h>
int main (int argc, char *argv[])
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSFileHandle *inFile, *outFile;
NSData *buffer;
NSString *path;
NSProcessInfo *proc = [NSProcessInfo processInfo];
NSArray *args = [proc arguments];
int numArgs = [args count];
BOOL endOfFile;
// Check for one argument on the command line
if (numArgs != 2) {
printf ("Please specify a file name!\n");
return 1;
}
path = [args objectAtIndex: 1];
// Open the file for reading
inFile = [NSFileHandle fileHandleForReadingAtPath: path];
if (inFile == nil) {
NSLog (@"Open of file for reading failed\n");
return 2;
}
// Open the terminal as standard output
outFile = [NSFileHandle fileHandleWithStandardOutput];
// Read inFile and write its contents to outFile 128 bytes at a time
endOfFile = NO;
while (endOfFile == NO) {
buffer = [inFile readDataOfLength: 128];
if ([buffer length] != 0)
[outFile writeData: buffer];
else
endOfFile = YES;
}
// Close files
[inFile closeFile];
[outFile closeFile];
[pool release];
return 0;
}
Chapter 17
17-1
// Small test program to see the effects on the retain count of
// adding and removing entries to a dictionary
//
// As you will see (and as the documentation for NSMutableDictionary explains)
//
// 1. Adding an object increases the object's retain count
// 2. Deleting an object decreases the object's retain count
// 3. Adding a key does not affect the key's retain count, because the key
// is copied into the dictionary and not retained.
// 4. Deleting a key does not affect the original key's retain count for the
// reason previously described.
//
#import <Foundation/NSObject.h>
#import <Foundation/NSString.h>
#import <Foundation/NSDictionary.h>
#import <Foundation/NSAutoreleasePool.h>
#import <Foundation/NSArray.h>
#import <Foundation/NSValue.h>
int main (int argc, char *argv[])
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSMutableDictionary *dict;
NSMutableString *str1 = [NSMutableString stringWithString: @"test"];
NSMutableArray *arr1 = [NSMutableArray arrayWithCapacity: 100];
NSString *key1 = [NSString stringWithString: @"myKey"];
NSNumber *int1 = [NSNumber numberWithInt: 100];
dict = [NSMutableDictionary dictionary];
printf ("Retain counts: str1 = %i, arr1 = %i, key1 = %i, int1= %i\n",
[str1 retainCount], [arr1 retainCount], [key1 retainCount],
[int1 retainCount]);
[dict setObject: int1 forKey: key1];
[dict setObject: arr1 forKey: @"Array"];
[dict setObject: @"case" forKey: str1];
printf ("Retain counts: str1 = %i, arr1 = %i, key1 = %i, int1= %i\n",
[str1 retainCount], [arr1 retainCount], [key1 retainCount],
[int1 retainCount]);
[dict removeObjectForKey: key1];
[dict removeObjectForKey: @"Array"];
[dict removeObjectForKey: str1];
printf ("Retain counts: str1 = %i, arr1 = %i, key1 = %i, int1= %i\n",
[str1 retainCount], [arr1 retainCount], [key1 retainCount],
[int1 retainCount]);
[pool release];
}
17-3
Just add an autorelease message to the result fraction in each method
before the return is made. In the simplest way, this can be done by
changing the line
return result;
at the end of each method to
return [result autorelease];
given that autorelease returns the object (which I realize I overlooked
mentioning that in the text...oh well, next printing!)
And yes, expressions such as
[[fractionA add: fractionB] print];
could then be written without memory leakage because the fraction returned
by the add: method would have been added to the autorelease pool and
therefore will get released when the pool is released.
Chapter 18
18-1
See Page 531 for the answer to this exercise.
You don't need a mutableCopy method, since it probably doesn't
make sense to distinguish mutable vs. immutable address books. You
generally want to add and remove entries from an address book, so you'll
likely always want a mutable copy.
18-3
// This program stores an array as an object into a dictionary
// It then makes immutable and mutable copies. Next, the first
// element of the original array is changed and the output
// verifies whether a shallow or deep copy was performed
#import <Foundation/NSObject.h>
#import <Foundation/NSArray.h>
#import <Foundation/NSDictionary.h>
#import <Foundation/NSString.h>
#import <Foundation/NSAutoreleasePool.h>
int main (int argc, char *argv[])
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSMutableArray *dataArray = [NSMutableArray arrayWithObjects:
@"one", @"two", @"three", @"four", nil];
NSDictionary *dict;
NSDictionary *imdict;
NSMutableDictionary *mdict;
NSMutableArray *arr;
int i;
// Create the dictionary with one entry
dict = [NSDictionary dictionaryWithObject: dataArray
forKey: @"array"];
// make immutable and mutable copies of the dictionary
arr = [dict objectForKey: @"array"];
printf ("\nArray in original dictionary before change: ");
for (i = 0; i < [arr count]; ++i)
printf ("%s ", [[arr objectAtIndex: i] cString]);
// Make copies
imdict = [dict copy];
mdict = [dict mutableCopy];
// change the first element of the array in dataArray
[dataArray replaceObjectAtIndex: 0 withObject: @"zero"];
// see the effects on the three dictionaries now
// (the original and the two copies
arr = [dict objectForKey: @"array"];
printf ("\nArray in original dictionary after change: ");
for (i = 0; i < [arr count]; ++i)
printf ("%s ", [[arr objectAtIndex: i] cString]);
printf ("\nArray in immutable copy of dictionary: ");
arr = [imdict objectForKey: @"array"];
for (i = 0; i < [arr count]; ++i)
printf ("%s ", [[arr objectAtIndex: i] cString]);
printf ("\nArray in mutable copy of dictionary: ");
arr = [mdict objectForKey: @"array"];
for (i = 0; i < [arr count]; ++i)
printf ("%s ", [[arr objectAtIndex: i] cString]);
printf ("\n");
[pool release];
return 0;
}
Chapter 19
19-1
Simply insert the line
[primes writeToFile: @"primes.pl" atomically: YES];
at the end of the program after all the prime numbers have been generated
(but before the pool gets released).
19-3
#import <Foundation/NSObject.h>
#import <Foundation/NSString.h>
#import <Foundation/NSDictionary.h>
#import <Foundation/NSEnumerator.h>
#import <Foundation/NSArchiver.h>
#import <Foundation/NSAutoreleasePool.h>
#import <Foundation/NSURL.h>
int main (int argc, char *argv[])
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSDictionary *glossary;
NSEnumerator *keyEnum;
NSString *url = @"http://www.kochan-wood.com/examples/glossary.pl";
id key;
glossary = [NSDictionary dictionaryWithContentsOfURL:
[NSURL URLWithString: url]];
keyEnum = [glossary keyEnumerator];
while ( (key = [keyEnum nextObject]) != nil )
printf ("%s: %s\n", [key cString],
[[glossary objectForKey: key] cString]);
[pool release];
return 0;
}
19-5
#import <Foundation/NSObject.h>
#import <Foundation/NSAutoreleasePool.h>
#import <Foundation/NSString.h>
#import <Foundation/NSKeyedArchiver.h>
#import <Foundation/NSCoder.h>
#import <Foundation/NSData.h>
#import <Foundation/NSProcessInfo.h>
#import "AddressBook.h"
int main (int argc, char *argv[])
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSData *dataArea;
NSKeyedUnarchiver *unarchiver;
AddressBook *myBook;
NSProcessInfo *proc = [NSProcessInfo processInfo];
NSArray *args = [proc arguments];
int numArgs = [args count];
NSString *search;
AddressCard *match;
// Check for an argument on the command line
if (numArgs != 2) {
printf ("Usage: %s name\n", [[proc processName] cString]);
return 1;
}
search = [args objectAtIndex: 1];
// Read in the archive and connect an
// NSKeyedUnarchiver object to it
dataArea = [NSData dataWithContentsOfFile: @"myArchive"];
unarchiver = [[NSKeyedUnarchiver alloc]
initForReadingWithData: dataArea];
// Decode the address book we previously stored in the archive
myBook = [unarchiver decodeObjectForKey: @"myaddrbook"];
[unarchiver finishDecoding];
[unarchiver release];
// Now lookup the entry
match = [myBook lookup: search];
if (match == nil)
printf ("%s not found!\n", [search cString]);
else
[match print];
[pool release];
return 0;
}
|
|
 |