Programming in Objective-C

 

Download Program Examples

The program examples are archived in tar format. The file should be self-extracting, or you should be able to double-click it after it downloads to extract the files. 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

Following is errata from the 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@mac.com



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;

}

Answers to Odd-Numbered Exercises


I hope you are enjoying Programming in Objective-C.  This page contains updated resources, errata, a link to download the program examples, and the answers to the odd-numbered exercises. 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


Steve Kochan

NOTE: This is the original web page for the first edition of Programming  in Objective-C.  If you have Programming in Objective-C 2.0 (Second edition), go to the forum for that book:


www.classroomM.com/objective-c


If you own the first edition, the forum will also be helpful for you.