Amazon.com Widgets attempted answer to exercise 17-3 with a question...always questions!!!
Welcome, Guest. Please login or register.
Did you miss your activation email?
November 25, 2014, 07:44:04 PM
Home Help Search chat Login Register 
News: Read this please.The Great Kangaroo Escape Looking for reviews of the 4th ed on Amazon!   Twitter:  @skochan
                     

+ Official Forum for Programming in Objective-C (the iPhone Programming Language) - Stephen Kochan
|-+ Old Stuff
| |-+ Answers to Exercises
| | |-+ Chapter 17
| | | |-+ attempted answer to exercise 17-3 with a question...always questions!!!
Pages: [1] Go Down
Print
Author Topic: attempted answer to exercise 17-3 with a question...always questions!!! (Read 2932 times)
mdeh
Full Member
***
Posts: 166






on: February 25, 2009, 12:52:36 AM

Fraction.h
Code: (Objective-C)
#import <Foundation/Foundation.h>


@interface Fraction : NSObject {
int numerator;
int denominator;
}

@property int numerator,  denominator;

-(void) print;
-(void) reduce;
-(void) setTo: (int) n over: ( int) d;
-(double) convertToNum;

@end

Fraction.m
Code: (Objective-C)
#import "Fraction.h"


@implementation Fraction

@synthesize numerator, denominator;

-(void) print
{
NSLog(@"%i/%i", numerator, denominator);
}

-(void) reduce
{
int u = numerator,  v = denominator, temp;
while (u) {
temp = v % u;
v = u;
u = temp;
}

numerator /= v;
denominator /= v;
}

-(void) setTo: (int) n over: ( int) d
{
self.numerator = n;
self.denominator = d;
}

-(double) convertToNum
{
        if ( denominator )
return (double) numerator/ denominator;
       else
        return 0.00;
}


@end

MathOps.h
Code: (Objective-C)
#import "Fraction.h"


@interface Fraction (MathOps)
-(Fraction *) add: (Fraction *) f;
-(Fraction *) mul: (Fraction *) f;
-(Fraction *) sub: (Fraction *) f;
-(Fraction *) div: (Fraction *) f;

@end

Mathops.m

Does it matter **where** the autorelease message is invoked? I saw that in the answer Steve gave for the first edition, it was with the return statement, like this:

Quote
return [result autorelease]

If I understand the book correctly, **when** the autorelease message is sent should not matter. Is it a matter of style, or is one correct and one incorrect?


Code: (Objective-C)
#import "Mathops.h"




@implementation Fraction (MathOps)
-(Fraction *) add: (Fraction *) f
{
Fraction  *result = [ [ [ Fraction alloc] init] autorelease];
int resNumerator = numerator * f.denominator + f.numerator* denominator;
int resDenominator = denominator * f.denominator;

[result setTo: resNumerator over:resDenominator];
[result reduce];
return result;
}

-(Fraction *) mul: (Fraction *) f
{
Fraction  *result = [ [ [ Fraction alloc] init] autorelease];
int resNumerator = numerator *  f.numerator;
int resDenominator = denominator * f.denominator;

[result setTo: resNumerator over:resDenominator];
[result reduce];
return result;
}

-(Fraction *) sub: (Fraction *) f
{
Fraction  *result = [ [ [ Fraction alloc] init] autorelease];
int resNumerator = numerator * f.denominator - f.numerator* denominator;
int resDenominator = denominator * f.denominator;
[result setTo: resNumerator over:resDenominator];
[result reduce];
return result;
}

-(Fraction *) div: (Fraction *) f
{
Fraction  *result = [ [ [ Fraction alloc] init] autorelease];
int resNumerator = numerator * f.denominator;
int resDenominator = denominator * f.numerator;
[result setTo: resNumerator over:resDenominator];
[result reduce];
return result;
}


@end

Test program main.m
Code: (Objective-C)
#import "Fraction.h"
#import "Mathops.h"



int main (int argc, const char * argv[]) {
    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];

int a = 1, b = 2, c = 1, d = 4;

NSLog(@"Given \"a = %i\", \"b = %i\", \"c = %i\", \"d = %i\"", a, b, c, d);
NSLog(@"Set \"myF to %i/%i\"", a, b);
NSLog(@" and \"myF2 to %i/%i\"", c, d);
Fraction *myF = [[[Fraction alloc] init ] autorelease];
Fraction *myF2 = [ [ [ Fraction alloc] init] autorelease];
NSLog(@"print \"myF\"");
[myF setTo:a over:b];
[myF print];
NSLog(@"reduce \"myF\"");
[myF reduce];
[myF print];
NSLog(@"convert myF To number");
NSLog(@"= %g", [myF convertToNum]);

[myF setTo: a over: b];
[myF2 setTo: c over: d];
NSLog(@"Perform \"[[myF add: myF2] print ]\"");
[[myF add: myF2] print ];

[myF setTo: a over: b];
[myF2 setTo: c over: d];
NSLog(@"Perform \"[[myF mul: myF2] print ]\"");
[[myF mul: myF2] print ];

[myF setTo: a over: b];
[myF2 setTo: c over: d];
NSLog(@"Perform \"[[myF div: myF2] print ]\"");
[[myF div: myF2] print ];

[myF setTo: a over: b];
[myF2 setTo: c over: d];
NSLog(@"Perform \"[[myF sub: myF2] print ]\"");
[[myF sub: myF2] print ];


[myF release];


NSLog(@"Release myF. If it crashes..which it should , proves it is already released???");
NSLog(@"I get: \"EXC_BAD_ACCESS\" if I continue program.");
    [pool drain];


    return 0;
}
Last Edit: February 25, 2009, 04:07:00 AM by mdeh Logged
esc
Global Moderator
Full Member
*****
Posts: 230






Reply #1 on: February 25, 2009, 01:26:32 AM

...
Does it matter **where** the autorelease message is invoked? I saw that in the answer Steve gave for the first edition, it was with the return statement, like this:
Code: (Objective-C)
return [result autorelease]
If I understand the book correctly, **when** the autorelease message is sent should not matter. Is it a matter of style, or is one correct and one incorrect?
...

When you send an autorelease message does not matter as long as you mark the object for deletion when you no longer need the object (but you need to return it).  Page 419 has a useful summary of object release and autorelease.  You already know this -- if you are totally done with the object, you send it a release message.  Smiley
Logged
mdeh
Full Member
***
Posts: 166






Reply #2 on: February 25, 2009, 02:29:47 AM

When you send an autorelease message does not matter as long as you mark the object for deletion when you no longer need the object (but you need to return it).  Page 419 has a useful summary of object release and autorelease.  You already know this -- if you are totally done with the object, you send it a release message.  Smiley

Thanks Wendy...

Ok...a few questions...some of which may be obvious.

1) The Autorelease Pool's whereabouts don't seem to be important. By this I mean the examples we have largely used have the autorelease pool in main, whereas mathOps, for example is in it's  own translation unit. ( I guess this is self-evident else it would not specifically be called upon when a Return statement is used.)

2) So, in my case, I used the autoRelease message in 2 places. One in mathOps, where it makes sense to use it ( Return needed) and also in main, with the creation of an instance of the Fraction class. What would a good programmer do here? There really is no need for myF to be returned anywhere, so one could easily do what we have been doing up to now, ie manually releasing the instance at the end with [myF release].  OR is it a matter of style?

3) Lastly, one confusing thing. I was looking at the documentation and noticed that "autorelease" has this note with it.
Quote
autorelease
Raises an exception.

- (id)autorelease

Return Value
self.

Discussion
In a reference-counted environment, this method raises an exception.


The commentary about autorelease pools is exactly what I have learnt from the book, but this makes no sense to me. What exception? etc.

Ok...thanks.


Last Edit: February 25, 2009, 03:01:31 AM by mdeh Logged
esc
Global Moderator
Full Member
*****
Posts: 230






Reply #3 on: February 25, 2009, 03:29:40 AM

Hi Michael,

Where is that documentation?  Back to your code...

When an autorelease pool is drained, if an object has X number of autorelease messages, then its retain count is reduced by X times.  If the object's retain count reaches zero, the object is destroyed.  Any further release message sent to the [destroyed] object would cause a crash (I get this -- FREED(id): message release sent to freed object=blah blah).  Since you sent myF an autorelease and later sent a release message, at the time of pool drain, the object is destroyed already.  I didn't run your program but did you get a crash?

Since I was posting program 10.1 so I changed the code a little to show the effects of autorelease/release/pool drain here.

Code: (Objective-C)
#import "Fraction.h"

int main (int argc, char * argv[]) {
    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];

Fraction *a, *b;

a = [[[Fraction alloc] initWith: 1: 3] autorelease];  <== MARK a for delete at pool drain.
b = [[Fraction alloc] initWith: 3: 7];

[a print];
[b print];

// [a release];  <== if I do not comment this out, a's retain count after this release will be zero and at pool drain later, the program will crash because a is no longer around.
[b release];

    [pool drain];

a = nil;   <== if I don't assign a pointing to nil, the following release      message will crash because we are trying to access a when a is no longer around (destroyed by pool drain).  sending a release message to nil is okay.

[a release];

    return 0;
}

This works:
Code: (Objective-C)
#import "Fraction.h"

int main (int argc, char * argv[]) {
    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];

Fraction *a, *b;

a = [[[Fraction alloc] initWith: 1: 3] autorelease];
b = [[Fraction alloc] initWith: 3: 7];

[a print];
[b print];

[a retain];
[a retain];
[a release];
[b release];

    [pool drain];

[a release];

    return 0;
}

But if you delete one of the retain message, the program will crash.
Hope this helps.
Last Edit: February 25, 2009, 06:56:47 AM by skochan Logged
mdeh
Full Member
***
Posts: 166






Reply #4 on: February 25, 2009, 03:40:48 AM

Hi Michael,

Where is that documentation? 

It's here..http://developer.apple.com/documentation/Cocoa/Reference/Foundation/Classes/NSAutoreleasePool_Class/Reference/Reference.html...but I think it's for something else.


Quote
Back to your code...

................  Since you sent myF an autorelease and later sent a release message, at the time of pool drain, the object is destroyed already.  I didn't run your program but did you get a crash?

Indeed ...as expected. I got an "Exception. Bad Access" which makes perfect sense, ( well, I think it does) as I am releasing an object that is no longer at the allocated memory address.

Quote
Since I was posting program 10.1 so I changed the code a little to show the effects of autorelease/release/pool drain here.

Code: (Objective-C)
         /........snip......../
a = [[[Fraction alloc] initWith: 1: 3] autorelease];  <== MARK a for delete at pool drain.



// [a release];  <== if I do not comment this out, a's retain count after this release will be zero and at pool drain later, the program will crash because a is no longer around.

Agreed...about the same that I did .
   
   
Code: (Objective-C)
	a = nil;   <== if I don't assign a pointing to nil, the following release message will cause a crash because we are trying to access a when a is no longer around (destroyed by pool drain).  sending a release message to nil is okay.

[a release];

agreed again.
   
 
So, Wendy, the question of style remains. Should one be using "autorelease" if there is not **return** involved, and we can easily release the instance as we have been doing up to now?
Last Edit: February 25, 2009, 06:52:50 AM by skochan Logged
esc
Global Moderator
Full Member
*****
Posts: 230






Reply #5 on: February 25, 2009, 03:54:02 AM

So, Wendy, the question of style remains. Should one be using "autorelease" if there is not **return** involved, and we can easily release the instance as we have been doing up to now?

Well, I think it's precaution more than style to autorelease right away because we are only going to be writing more complex and longer programs.  The number of objects will soon grow and to keep track of it all for when to release each object...translates to unnecessary headache  Grin
Logged
mdeh
Full Member
***
Posts: 166






Reply #6 on: February 25, 2009, 03:58:59 AM

Well, I think it's precaution more than style to autorelease right away because we are only going to be writing more complex and longer programs.  The number of objects will soon grow and to keep track of it all for when to release each object...translates to unnecessary headache  Grin

Good point......thanks.
Logged
skochan
Administrator
Hero Member
*****
Posts: 3114







Reply #7 on: February 25, 2009, 06:45:20 AM

Quote
So, Wendy, the question of style remains. Should one be using "autorelease" if there is not **return** involved, and we can easily release the instance as we have been doing up to now?

Excellent discussion and experiments guys!

If you've got an autorelease pool already set up (as we do in all the program examples), then it's okay to add any objects you own to the pool by sending them autorelease messages and then allowing the draining of the pool to clean them up.  From a pedagogical perspective, I used release instead because I wanted everyone to understand the concepts of allocating and subsequently releasing objects when they're no longer needed.  And this will likely occur inside your methods, not necessarily your main routine.  So, for example, if you needed to allocate some objects in a method but didn't need them to persist after the method completed execution, I would allocate them and release them.  If you added them to the autorelease pool instead, your memory usage would continue to grow until the autorelease pool was drained.

Cheers,

Steve
Last Edit: February 25, 2009, 07:06:46 AM by skochan Logged
mdeh
Full Member
***
Posts: 166






Reply #8 on: February 25, 2009, 06:58:30 AM

Thanks Steve.
Michael.
Logged
mdeh
Full Member
***
Posts: 166






Reply #9 on: February 25, 2009, 09:24:11 AM

In view of this and the discussion under the "category (help)"   Smiley I have changed the main routine as the autorelease in main now seems "gimmicky" as opposed to it's real intent.
Code: (Objective-C)
#import "Fraction_F.h"
#import "Mathops_F.h"



int main (int argc, const char * argv[]) {
    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];

int a = 1, b = 2, c = 1, d = 4;

NSLog(@"Given \"a = %i\", \"b = %i\", \"c = %i\", \"d = %i\"", a, b, c, d);
NSLog(@"Set \"myF to %i/%i\"", a, b);
NSLog(@" and \"myF2 to %i/%i\"", c, d);
Fraction *myF = [[Fraction alloc] init ];
Fraction *myF2 = [ [ Fraction alloc] init];
NSLog(@"print \"myF\"");
[myF setTo:a over:b];
[myF print];
NSLog(@"reduce \"myF\"");
[myF reduce];
[myF print];
NSLog(@"convert myF To number");
NSLog(@"= %g", [myF convertToNum]);

[myF setTo: a over: b];
[myF2 setTo: c over: d];
NSLog(@"Perform \"[[myF add: myF2] print ]\"");
[[myF add: myF2] print ];

[myF setTo: a over: b];
[myF2 setTo: c over: d];
NSLog(@"Perform \"[[myF mul: myF2] print ]\"");
[[myF mul: myF2] print ];

[myF setTo: a over: b];
[myF2 setTo: c over: d];
NSLog(@"Perform \"[[myF div: myF2] print ]\"");
[[myF div: myF2] print ];

[myF setTo: a over: b];
[myF2 setTo: c over: d];
NSLog(@"Perform \"[[myF sub: myF2] print ]\"");
[[myF sub: myF2] print ];


[myF release];
[myF2 release];
/* to show good programming: See discussion under help! */
[myF release]; /* myF now over-released */


NSLog(@"Release myF. If it crashes..which it should , proves it is already released???");
NSLog(@"I get: \"EXC_BAD_ACCESS\" if I continue program.");
    [pool drain];


    return 0;
}

 
Logged
Pages: [1] Go Up
Print
Jump to:



Login with username, password and session length

Powered by MySQL Powered by PHP Powered by SMF 1.1.11 | SMF © 2006-2009, Simple Machines LLC Valid XHTML 1.0! Valid CSS!
Entire forum contents (c) 2009 classroomM.com. All rights reserved.