Showing posts with label classes. Show all posts
Showing posts with label classes. Show all posts

Monday, 11 May 2009

Chapter 7 - More on Classes

Comment

So far I'm liking the whole 'Synthesized Accessor Methods'. It is a process included since Objective-C 2.0 was implemented and basically allows you to have your 'setter' and 'getter' methods - a.k.a 'accessor methods' - automatically generated. Using this synthesized method is supposed to produce methods that are efficient regardless of the platform the program is eventually ran on.


@d. As you mentioned earlier, the dot operator is mentioned. I believe you told me its origins lie originally with C++

If I end up using interchanging notation between the two in the following examples, I'm just trying to get a feel for which one I prefer. The 'dot operator' way certainly looks cleaner when performing the same operation on two objects together.


For example:


-(void) addNumerators: (fraction *) f

{

numerator = numerator + f.numerator;

}


as opposed to:


{

numerator = numerator + [f numerator];

}


Examples

1. Add the following methods to the Fraction class to round out the arithmetic operations on fractions. Reduce the result within the method in each case:


//Subtract argument from receiver

-(Fraction *) subtract: (Fraction *) f;

//Multiply receiver by argument

-(Fraction *) multiply: (Fraction *) f;

//Divide receiver by argument

-(Fraction *) divide: (Fraction *) f;


ANS - Copy and Paste of implemented methods


-(Fraction *) subtract: (Fraction *) f

{

// To subtract two fractions:

// a/b - c/d = ((a*d) - (b*c)) / (b * d)

// result will store the result of the subtration

Fraction *result = [[Fraction alloc] init];

int resultNum, resultDenom;

resultNum = numerator * f.denominator - denominator * f.numerator;

resultDenom = denominator * f.denominator;

[result setNumerator: resultNum andDenominator: resultDenom];

[result reduce];

return result;

}


-(Fraction *) multiply: (Fraction *) f

{

// To multiply two fractions:

// a/b * c/d

//result will store the result of the multiplication

Fraction *result = [[Fraction alloc] init];

int resultNum, resultDenom

resultNum = numerator * f.numerator;

resultDenom = denominator * f.denominator;

[result setNumerator: resultNum andDenominator: resultDenom];

[result reduce];

return result;

}


-(Fraction *) divide: (Fraction *) f

{

// To divide two fractions:

// a/b * d/c

//result will store the result of the multiplication

Fraction *result = [[Fraction alloc] init];

int resultNum, resultDenom;

resultNum = numerator * f.denominator;

resultDenom = denominator * f.numerator;

[result setNumerator: resultNum andDenominator: resultDenom];

[result reduce];

return result;

}


Although not necessarily required, I produced a program to demonstrate these methods in use. Below are the copy and paste of the code and the console output:


#import

#import "Fraction.h"


int main (int argc, const char * argv[]) {

NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];


Fraction *aFraction = [[Fraction alloc] init];

Fraction *bFraction = [[Fraction alloc] init];

Fraction *resultFraction;

[aFraction setNumerator: 3 andDenominator: 4];

[bFraction setNumerator: 1 andDenominator: 2];

NSLog (@"Function | Expected Output |");

NSLog (@"Actual Output | |");

NSLog (@"---------------------------------");

resultFraction = [aFraction subtract: bFraction];

NSLog (@"subtract: | 1/4 |");

[resultFraction print];

resultFraction = [aFraction multiply: bFraction];

NSLog (@"multiply: | 3/8 |");

[resultFraction print];

resultFraction = [aFraction divide: bFraction];

NSLog (@"divide: | 3/2 |");

[resultFraction print];


[resultFraction release];

[pool drain];

return 0;

}


[Session started at 2009-05-11 03:41:07 +0100.]

Function | Expected Output |

Actual Output | |

---------------------------------

subtract: | 1/4 |

1/4

multiply: | 3/8 |

3/8

divide: | 3/2 |

3/2


The Debugger has exited with status 0.


2. Modify the print method from your Fraction class so that it takes an optional BOOL argument that indicates whether the fraction should be reduced for display. If it is to be reduced, be sure you don't make any permanent changes to the fraction itself.


ANS - Copy and Paste of implemented code and console output


-(void) print

{

BOOL reduce;

int temp, n, d;

Fraction *r = [[Fraction alloc] init];

n = numerator;

d = denominator;

temp = n % d;

if ( temp != 0 ) {

reduce = TRUE;

[r setNumerator: n andDenominator: d];

}

if ( reduce = TRUE ) {

[r reduce];

NSLog (@"This fraction was reduced to: %i/%i", r.numerator, r.denominator);

}

else {

NSLog (@"%i/%i", r.numerator, r.denominator);

}

}


#import

#import "Fraction.h"


int main (int argc, const char * argv[]) {

NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];


Fraction *aFraction = [[Fraction alloc] init];

[aFraction setNumerator: 6 andDenominator: 8];

NSLog (@"Actual value of aFraction: %i/%i", aFraction.numerator, aFraction.denominator);

[aFraction print];

[pool drain];

return 0;

}


The Debugger Debugger is attaching to process

[Session started at 2009-05-15 20:48:42 +0100.]

2009-05-15 20:48:42.197 FractionTest[633:10b] Actual value of aFraction: 6/8

2009-05-15 20:48:42.198 FractionTest[633:10b] This fraction was reduced to: 3/4


The Debugger has exited with status 0.


3. Modify Program 7.7 to also display the resulting sum as a fraction, not just as a real number.


ANS - Copy and Paste of the new code and console output of fraction


#import

#import "Fraction.h"


int main (int argc, const char * argv[]) {

NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];


Fraction *aFraction = [[Fraction alloc] init];

Fraction *sum = [[Fraction alloc] init], *sum2;

int i, n, pow2;

[sum setNumerator: 0 andDenominator: 1]; //Set 1st fraction to 0

NSLog (@"Enter your value for n:");

scanf ("%i", &n);

pow2 = 2;

for ( i = 1; i <= n; ++i ) {

[aFraction setNumerator: 1 andDenominator: pow2];

sum2 = [sum add: aFraction];

[sum release]; //release previous sum

sum = sum2;

pow2 *= 2;

}

NSLog (@"After %i iterations, the sum is %g", n, [sum convertToNum]);

NSLog (@"num/denom: %g/%g", [sum numerator], [sum denominator]);

[aFraction release];

[sum release];

[pool drain];

return 0;

}



[Session started at 2009-05-15 21:37:38 +0100.]

2009-05-15 21:37:38.738 FractionTest[992:10b] Enter your value for n:

5

2009-05-15 21:37:40.522 FractionTest[992:10b] After 5 iterations, the sum is 0.96875

2009-05-15 21:37:40.522 FractionTest[992:10b] num/denom: 6.95336e-310/5.29949e-315


The Debugger has exited with status 0.


4. Will your Fraction class work with negative fractions? For example, can you add -1/4 and -1/2 and get the correct result? When you think you have the answer, write a test program to try it.


ANS - I believe the outcome will be it can based on the merits we discussed earlier. With the addition algorithm the sign is never lost or changed and thus the calculation is completed successfully. This is similar to the subtract algorithm in that the two negatives - (-1/2) become 1/2. For multiplication the sign is lost, however this makes mathematical sense as two negatives result in a positive. This is also the case with division.


#import

#import "Fraction.h"


int main (int argc, const char * argv[]) {

NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];


Fraction *aFraction = [[Fraction alloc] init];

Fraction *bFraction = [[Fraction alloc] init];

Fraction *result = [[Fraction alloc] init];

[aFraction setNumerator: -1 andDenominator: 4];

[bFraction setNumerator: -1 andDenominator: 2];

[result setNumerator: 0 andDenominator: 0];

result = [aFraction add: bFraction];

NSLog (@"-1/4 + -1/2 = ");

[result print];


[aFraction release];

[bFraction release];

[result release];

[pool drain];

return 0;

}


[Session started at 2009-05-15 21:10:08 +0100.]

2009-05-15 21:10:08.321 FractionTest[761:10b] -1/4 + -1/2 =

2009-05-15 21:10:08.322 FractionTest[761:10b] This fraction was reduced to: -3/4


The Debugger has exited with status 0.


5. Modify the Fraction's print method to display fractions greater than 1 as mixed numbers. For example, the fraction 5/3 should be displayed as 1 2/3.


ANS - Copy and Paste of new print method and console output illustrating different testing data.


-(void) print

{

BOOL reduce;

int temp, n, d, whole;

float result;

Fraction *r = [[Fraction alloc] init];

n = numerator;

d = denominator;

[r setNumerator: n andDenominator: d];

temp = n % d;

if ( temp != 0 ) {

reduce = TRUE;

}

if ( n / d > 0 ) {

whole = n / d;

r.numerator -= r.denominator * whole;

if ( reduce = TRUE ) {

[r reduce];

}

result = (float) r.numerator / r.denominator;

if ( result != 0 ) {

NSLog (@"This fraction was simplified to: %i and %i/%i", whole, r.numerator, r.denominator);

}

else {

NSLog (@"This fraction was simplified to: %i", whole);

}

}

else {

if ( reduce = TRUE ) {

[r reduce];

}

NSLog (@"%i/%i", r.numerator, r.denominator);

}

[r release];

}


[Session started at 2009-05-17 12:23:19 +0100.]

2009-05-17 12:23:19.464 FractionTest[790:10b] Num: 5 Denom: 3

2009-05-17 12:23:19.465 FractionTest[790:10b] This fraction was simplified to: 1 and 2/3


The Debugger has exited with status 0.

[Session started at 2009-05-17 12:23:34 +0100.]

2009-05-17 12:23:34.361 FractionTest[805:10b] Num: 6 Denom: 2

2009-05-17 12:23:34.363 FractionTest[805:10b] This fraction was simplified to: 3


The Debugger has exited with status 0.

[Session started at 2009-05-17 12:23:47 +0100.]

2009-05-17 12:23:47.118 FractionTest[820:10b] Num: 12 Denom: 8

2009-05-17 12:23:47.120 FractionTest[820:10b] This fraction was simplified to: 1 and 1/2


The Debugger has exited with status 0.


6. Exercise 7 in Chapter 4, "Data Types and Expressions," defined a new class called Complex for working with complex imaginary numbers. Add a new method called add: that can be used to add two complex numbers. To add two complex numbers you simply add the real parts and the imaginary parts , as shown here:

(5.3 + 7i) + (2.7 + 4i) = 8 + 11i

Have the add: method store and return the result as a new Complex number, based on the following method declaration:

-(Complex *) add: (Complex *) ;

Make sure you address any potential memory leakage issues in your test program.


7. Given the Complex class developed in exercise 7 of Chapter 4 and the extension made in exercise 6 of this chapter, create separate Complex.h and Complex.m interface and implementation files. Create a separate test program file to test everything.


ANS - Copy and Paste of both exercise 6 and 7 and its console output. (it's a long one)


//

// Complex.h

// ComplexNum

//

// Created by Waqas Arshid on 17/05/2009.

// Copyright 2009 __MyCompanyName__. All rights reserved.

//


#import



@interface Complex : NSObject

{

int real;

int imaginary;

}


-(void) setReal: (double) a andImaginary: (double) b;

-(void) print; // display as a + bi

-(double) real;

-(double) imaginary;

-(Complex *) add: (Complex *) c;


@end


//

// Complex.m

// ComplexNum

//

// Created by Waqas Arshid on 17/05/2009.

// Copyright 2009 __MyCompanyName__. All rights reserved.

//


#import "Complex.h"



@implementation Complex


-(void) setReal: (double) a andImaginary: (double) b

{

real = a;

imaginary = b;

}


-(void) print

{

NSLog(@"Complex number equals: %d + %di", real, imaginary);

}


-(double) real

{

return real;

}


-(double) imaginary

{

return imaginary;

}


- (Complex *) add: (Complex *) c

{

Complex *result = [[Complex alloc] init];

double r, i;

r = real + c.real;

i = imaginary + c.imaginary;

[result setReal: r andImaginary: i];

return result;

}


@end


#import

#import "Complex.h"

int main (int argc, const char * argv[]) {

NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];

Complex *aComp = [[Complex alloc] init];

Complex *bComp = [[Complex alloc] init];

Complex *resultComp;

[aComp setReal: 5.3 andImaginary: 7];

[bComp setReal: 2.7 andImaginary: 11];

resultComp = [aComp add: bComp];

[resultComp print];


[aComp release];

[bComp release];

[resultComp release];

[pool drain];

return 0;

}


[Session started at 2009-05-17 16:33:06 +0100.]

2009-05-17 16:33:06.608 ComplexNum[2100:10b] Complex number equals: 7 + 18i


The Debugger has exited with status 0.


Sunday, 22 March 2009

Chapter 3 - Classes, Objects and Methods

Comment

So far this chapter has been conceptually difficult to understand but as the author moved on to coded examples and began to explain them it became much easier to pick up. Another neat feature of objective-c is the ability to allocate an order in which events are executed - in a similar way you would use brackets on your calculator.

The following exercises are quite theoretical and so as a result there is little example of code or syntax.


Exercises

1. Which of the following are invalid names? Why?

ANS- Int - reserved by the objective-c compiler

6_05 - cannot begin with a number (only underscore or letter)

A$ - '$' is an invalid character


_ - unsure if this is invalid but does not contain any letters or numbers so I reckon that it is


Valid names include;

_calloc,

Xx,

playNextSong,

alphaBetaRoutine,

clearScreen,

_1312,

z,

ReIntialise.


2. [...]Think of an object you use everyday. Identify a class for that object and write five actions you do with that object.


ANS - An object I use everyday is my mobile phone

A class for this could be 'Phone'

Actions:

Text

Call

Browse the web

Recharge

Take a picture


3. Given the list in exercise 2, use the following syntax to rewrite your list in this format: [instance method] ;


ANS - [myPhone text] ;

[myPhone call] ;

[myPhone browse] ;

[myPhone recharge] ;

[myPhone picture];


4. Imagine you owned a boat and a motorcycle in addition to a car. List the actions you would perform with each of these. Do you have any overlap between these actions?


ANS- actions Boat;

prepare it for use

sail it

clean it

get it serviced

dock it


actions Motorcycle

prepare to drive it

drive it

clean it

get it serviced

park it


actions Car

prepare to drive it

drive it

clean it

get it serviced

park it


There is a lot of overlap between the three sections, particularly;

prepare, clean, service and arguably sail/drive, dock/park


5. Based on question 4, imagine that you had a class called Vehicle and an object called myVehicle that could be either Car, Motorcycle, or Boat. Imagine that you wrote the following:


[myVehicle prep];

[myVehicle getGas];

[myVehicle service];


Do you see any advantage of being able to apply an action to an object that could be from one of several classes?


ANS - Yes, as no matter which vehicle is selected, they all can perform the same action which would make it simpler to compare different objects or apply the same action to all of these objects.


6. In a procedural language such as C, you think about actions and then write code to perform the action on various objects. Referring to the car example, you might write a procedure in C to wash a vehicle and then inside that procedure write code to handle washing a car, washing a boat, washing a motorcycle, and so on. If you took that approach and then wanted to add a new vehicle type (see the previous exercise), do you see advantages or disadvantages to using this procedural approach over an object-oriented approach?


ANS- An advantage would be the ability to slightly modify the procedure for washing the new vehicle type without affecting the others in place.

A disadvantage would be that the new vehicle type would not inherit the instances and methods of the previous ones and all of these would also need to be added to the new vehicle type which would be time-consuming.


7. Define a class called XYPoint that will hold a Cartesian coordinate (x, y), where x and y are integers. Define methods to individually set the x and y coordinates of a point and retrieve their values. Write an Objective-C program to implement your new class and test it.


ANS - When writing this program, I learnt a valuable lesson about invalid names. At first I tried to use the '-' character in between X or Y and 'coordinate' which threw up a multitude of errors from the compiler. After resolving this issue, the program compiled and ran error free. The program has been copied and pasted from Xcode and the Console output;


#import


@interface XYPoint: NSObject

{

int Xcoordinate;

int Ycoordinate;

}


-(void) setX: (int) X;

-(void) setY: (int) Y;

-(int) Xcoordinate;

-(int) Ycoordinate;


@end


@implementation XYPoint


-(void) setX: (int) X

{

Xcoordinate = X;

}


-(void) setY: (int) Y

{

Ycoordinate = Y;

}


-(int) Xcoordinate;

{

return Xcoordinate;

}


-(int) Ycoordinate;

{

return Ycoordinate;

}


@end



int main (int argc, const char * argv[]) {

NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];

XYPoint *cartCoord = [[XYPoint alloc] init];

[cartCoord setX: 1];

[cartCoord setY: 2];

NSLog (@"The value of cartCoord is: (%i,%i)", [cartCoord Xcoordinate], [cartCoord Ycoordinate]);

[cartCoord release];

[pool drain];

return 0;

}


[Session started at 2009-03-23 00:16:12 +0000.]

2009-03-23 00:16:12.857 Chap3_Ex7_XYPoint[472:10b] The value of cartCoord is: (1,2)


The Debugger has exited with status 0.