Amazon.com Widgets Nov. 16th
Welcome, Guest. Please login or register.
Did you miss your activation email?
September 30, 2014, 10:52:45 AM
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
| |-+ Webcast Series Part I, Oct. 29 - Dec. 1
| | |-+ Assignments
| | | |-+ Nov. 16th
Pages: [1] Go Down
Print
Author Topic: Nov. 16th (Read 16010 times)
skochan
Administrator
Hero Member
*****
Posts: 3114







on: November 16, 2009, 05:40:57 PM

  • Read Chapters 9-10
  • Take the quizzes for these 3 chapters  
  • Exercises: Page 203, ex. 1, 2, 3
  • Add this initializer to your Rectangle
    class:

    -(id) initWithWidth: (int) w Height: (int) h andOrigin: (XYPoint *) pt;


    Be sure to have init and initWithWidth:andHeight: use this method.

    Also, look at this thread: http://classroomm.com/objective-c/index.php?topic=688.msg1996#msg1996.  Be sure to read the threads referenced by this thread as well.
Last Edit: November 17, 2009, 04:29:34 AM by skochan Logged
tmekeel
Newbie
*
Posts: 18


WWW




Reply #1 on: November 19, 2009, 09:45:09 PM

Steve--

I'm having trouble understanding this initialize concept.   

If we do exercise 1 from chapter 10 (I posted it to the forum here under our 10/29 webinar class), we have an initializer that returns a Rectangle pointer.

We can't then use this: -(id) initWithWidth: (int) w Height: (int) h andOrigin: (XYPoint *) pt; unless we start a subclass of our Rectangle class?

I am failing to understand how to get the same class to have these two initializers together. Below is some code I started but does not work, maybe it will shed some light on what I'm trying to explain in text. 
The uncommented code initializes a proper instance, and works fine when invoked.  The commented code is ~trial 50 of things I was working on.  I stopped when I felt my brain frying. 

As you will probably immediately notice, I'm missing some important something  Undecided
Code: (Objective-C)
#import "Rectangle.h"

@implementation Rectangle

@synthesize width, height;

/*-init
{
    return [self initWithWidth: (int)w andHeight: (int)h andOrigin: NULL: "default"];
}
-(Rectangle *) initWithWidth: (int) w andHeight: (int) h
{
{
self = [self init];
if (self)
{
[self setWidth: w andHeight: h];
}
return self;
}
}*/

-(Rectangle *) initWithWidth: (int) w andHeight: (int) h andOrigin: (XYPoint *) pt
{
self = [super init];
if (self)
{
[self setWidth: w andHeight: h];
[self setOrigin: pt];
}
return self;
}
Logged
rgronlie
Global Moderator
Full Member
*****
Posts: 212







Reply #2 on: November 20, 2009, 03:31:08 AM

I think the concept you are having trouble with is the designated initializer. There is a particular way you need to cascade multiple initializers in a class.

From Apple's Developer Documents:
Designated Initializer

Examples from the Chapter Study thread:
Designated Initializer examples

Ryan
Logged

Sanity: Minds are like parachutes. Just because you've lost yours doesn't mean you can borrow mine.
tmekeel
Newbie
*
Posts: 18


WWW




Reply #3 on: November 20, 2009, 11:11:02 AM

Ryan--

Thanks for the reply.  It would seem then that I have the designated initializer written fine, it is the subclasses, such as square that would need to call [self = super initWithWidth: andHeight: andOrigin: ]?
This is where I'm stumbling I guess.  I had read the link already at Apple's site, but your example I hadn't found.  Thanks for that. 

It seems in your example, you have a subclass of NSObjext called line, then a subclass of line as Rectangle, followed by another subclass called Square. 

If I read it correctly, Line overrides NSObject's init, which calls it's own initWithWidth.  Rectangle, the next subclass, would override it's parent class Line's designated initializer (initWithWidth) by calling it, but using this line inside the method:
Code: (Objective-C)
 return [self initWithWidth:w andHeight:1];

Since it returns to self, and you use a default value, it looks for this method inside it's own class, which it finds here:
Code: (Objective-C)
-(id)initWithWidth:(int)w andHeight:(int)h  

   if (self = [super initWithWidth:w])         // call the super 
   { 
     height = h; 
   } 
   return self; 
 } 


And this is where the designated initializer is, calling it's parent class Line's initializer, but then also accepting the argument for height, which overrides the default value.  So Rectangle has it's override and it's single initializer.  There need not be more than one in the class, then?

My confusion persists, in that the code for my Rectangle is a direct subclass of NSObject.  I need only what I have already written, to override NSObject's init, and my method looks like so:
Code: (Objective-C)
-(Rectangle *) initWithWidth: (int) w andHeight: (int) h andOrigin: (XYPoint *) pt  

     self = [super init]; 
     if (self) 
     { 
         [self setWidth: w andHeight: h]; 
         [self setOrigin: pt]; 
     } 
     return self; 

 


However, we are supposed to "Be sure to have init and initWithWidth:andHeight: use this method."  init comes from NSOBject, [initWithWidth: and Height:] would be in the same class, which is Rectangle.  Would we then just have [init] and [initWithWidth:andHeight:] set up like below?

Code: (Objective-C)
-init 
{
    return [self initWithWidth: (int)w andHeight: (int)h andOrigin: NULL];
}

-(Rectangle *) initWithWidth: (int) w andHeight: (int) h
{
        return  [self initWithWidth: w andHeight: h andOrigin: NULL];
}

Much appreciated,
Tom
Last Edit: November 20, 2009, 11:18:00 AM by tmekeel Logged
rgronlie
Global Moderator
Full Member
*****
Posts: 212







Reply #4 on: November 20, 2009, 02:00:39 PM

Tom,

Quote
My confusion persists, in that the code for my Rectangle is a direct subclass of NSObject.  I need only what I have already written, to override NSObject's init, and my method looks like so:
Code: (Objective-C)
 -(Rectangle *) initWithWidth: (int) w andHeight: (int) h andOrigin: (XYPoint *) pt    
 {    
      self = [super init];    
      if (self)    
      {    
          [self setWidth: w andHeight: h];    
          [self setOrigin: pt];    
      }    
      return self;    
 }
You would still need to override NSObject's designated initializer init.
Code: (Objective-C)
 -(id)init   
 {  
     return [self initWithWidth: 0 andHeight: 0 andOrigin: NULL];  
 }
You can have more than one initialization method as long as they call the designated initializer for the class. In this case initWithWidth:andHeight:andOrigin: is Rectangle's designated initializer. Your assumption is almost correct. Make sure you return type id from your initializers and use default values when argument variables aren't being supplied.

So the initializers for the Rectangle class would look like this:
Code: (Objective-C)
//
// Override parent class (NSObject) designated initializer
//
-(id)init  
{  // you can use values other than zero for the defaults
    return [self initWithWidth: 0 andHeight: 0 andOrigin: NULL];  
}  
      
-(id) initWithWidth: (int) w andHeight: (int) h  
{  
    return  [self initWithWidth: w andHeight: h andOrigin: NULL];  
}  

//
// Designated initializer for Rectangle class
//
-(id) initWithWidth: (int) w andHeight: (int) h andOrigin: (XYPoint *) pt    
{    
    self = [super init];    
    if (self)    
    {    
        [self setWidth: w andHeight: h];    
        [self setOrigin: pt];    
    }    
    return self;    
}
Ryan
Logged

Sanity: Minds are like parachutes. Just because you've lost yours doesn't mean you can borrow mine.
skochan
Administrator
Hero Member
*****
Posts: 3114







Reply #5 on: November 20, 2009, 02:11:51 PM

If you're going to pass NULL as the origin (and by the way, nil is more commonly used for null objects), I would modify the setOrigin: method to test for it.  I'd rather this was programmed into the code than taking advantage of the fact that it's okay to send a message to a nil object.  For one reason, the setOrigin: should be called with a non-nil argument (otherwise, what's its purpose?).  A better approach would be to allocate an origin in the initializer, set it to (0,0), pass that in as the argument, and then release it.  While that's a little more work, it's cleaner, IMHO.

Cheers,

Steve Kochan
Last Edit: November 20, 2009, 02:14:50 PM by skochan Logged
tmekeel
Newbie
*
Posts: 18


WWW




Reply #6 on: November 20, 2009, 04:56:17 PM

Thanks so much for the help guys. 

@Steve: " A better approach would be to allocate an origin in the initializer, set it to (0,0), pass that in as the argument, and then release it."
I was trying to figure out how to make that work. My original code  ended up just initializing an Origin in my main{} program, then passing it as an argument.  How do you initialize an Origin in the method when the method's argument needs to be passed one first?  Or, do you mean in an initializer that doesn't have an Origin, such as initWithWidth:andHeight:? 
 
Logged
tmekeel
Newbie
*
Posts: 18


WWW




Reply #7 on: November 20, 2009, 05:43:52 PM

Ok, here is my code now, corrected per your advice (mostly).  At least now I think I understand what the heck I'm doing with the designated initializer; 12 hours ago I was sure I had no clue  Grin

How would I create an instance of the class with an Origin directly in the initialization without having to create one separately?
For instance,
Code: (Objective-C)
Rectangle *myRectWithO = [[Rectangle alloc] initWithWidth: 5 andHeight: 6 andOrigin: (myRectWithO.origin.x, myRectWithO.y) ];


Lastly, my initWithWidth doesn't seem to set an origin this way. I'm sure it isn't proper anyway, so if you could clarify my thinking a bit it would be appreciated. 


Alas, here are my files for Rectangle.h, .m, and the Main program I used to test it.

Rectangle.h:
Code: (Objective-C)
#import <Foundation/Foundation.h>
#import "XYPoint.h"

@interface Rectangle : NSObject
{
int width;
int height;
XYPoint *origin;
}

@property int width, height;
-(id) initWithWidth: (int) w andHeight: (int) h;
-(id) initWithWidth: (int) w andHeight: (int) h andOrigin: (XYPoint *) pt;

-(void) setOrigin: (XYPoint *) pt;
-(void) setWidth: (int) w andHeight: (int) h;
-(XYPoint *) origin;
-(int) area;
-(int) perimeter;

-(void)sidesPrint: (int) rectHeight;
-(void)topBottomPr: (int) rectWidth;
-(void) translate: (XYPoint *)transPt;
@end

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

@implementation Rectangle

@synthesize width, height;

-init
{
    if (origin)
[origin release];

origin = [[XYPoint alloc] init];

[origin setX: 0 andY: 0];

return [self initWithWidth: 640 andHeight: 480 andOrigin: origin];
}
-(id) initWithWidth: (int) w andHeight: (int) h
{
{
if (origin)
[origin release];

origin = [[XYPoint alloc] init];

[origin setX: 15 andY: 20];

return [self initWithWidth: w andHeight: h andOrigin: origin];
}
}
-(id) initWithWidth: (int) w andHeight: (int) h andOrigin: (XYPoint *) pt
{
self = [super init];
if (self)
{
[self setWidth: w andHeight: h];
[self setOrigin: pt];
}
return self;
}

-(void) setWidth:(int) w andHeight: (int) h
{
width = w;
height = h;
}

-(void) setOrigin: (XYPoint *) pt
{
if (origin)
[origin release];

origin = [[XYPoint alloc] init];

[origin setX: pt.x andY: pt.y];
}

-(int) area
{
int a = height * width;
return a;
}
-(int) perimeter
{
int p = (2*height) + (2*width);
return p;
}

-(XYPoint *) origin
{
return origin;
}

-(void) dealloc
{
if (origin)
[origin release];
[super dealloc];
}

/*-(Rectangle *) intersect: (Rectangle *)rect1;
{
Rectangle *overLap = [[Rectangle alloc] init];

}*/
-(void)topBottomPr: (int) rectWidth
{
int j = rectWidth;

for (j = 0; j <= (rectWidth +1); j++)
{
printf("_");

}

printf("\n");
}

-(void)sidesPrint: (int) rectHeight
{
int k;
int go = 0;

while (go < rectHeight)
{
printf("|");
for (k = 0; k < rectHeight; k++)
{

printf(" ");

}
printf("|\n");

go++;
}
}

-(void) translate: (XYPoint *) transPt
{
[origin setX:(origin.x + transPt.x) andY: (origin.y + transPt.y)];
}
@end

Main Program:
Code: (Objective-C)
#import "Rectangle.h"
#import "XYPoint.h"
 
 
 int main (int argc, const char * argv[]) {
 NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
//Origin for last rect
XYPoint *myPoint = [[XYPoint alloc] init];
[myPoint setX: 250 andY: 100];

//A test for each initializer, all should get an origin even if not declared here.
//myRectInit should get 640wx480h as those are defaults.
//myRectWithO should not have default (0,0), it should have myPoint's values
Rectangle *myRectInit = [[Rectangle alloc] init];
Rectangle *myRectWithWH = [[Rectangle alloc] initWithWidth: 10 andHeight: 12];
Rectangle *myRectWithO = [[Rectangle alloc] initWithWidth: 5 andHeight: 6 andOrigin: myPoint];



printf("myRectInit width: %i, height: %i, and origin: (%ix,%iy)  \n", myRectInit.width, myRectInit.height, myRectInit.origin.x, myRectInit.origin.y);
printf("myRectWithWH width: %i, height: %i, and origin: (%ix,%iy)  \n", myRectWithWH.width, myRectWithWH.height, myRectWithWH.origin.x, myRectWithWH.origin.y);
printf("myRectWithO width:%i, height = %i, and origin: (%ix, %iy)", myRectWithO.width, myRectWithO.height, myRectWithO.origin.x, myRectWithO.origin.y);

[myPoint release];

[myRectInit release];
[myRectWithWH release];
[myRectWithO release];




[pool drain];
return 0;
 }


Logged
skochan
Administrator
Hero Member
*****
Posts: 3114







Reply #8 on: November 30, 2009, 01:40:11 PM

Hi,

You should release the origins you allocate in your init and initWithWidth:andHeight: methods.

You can create an instance in the call (as you asked), by using nested alloc, init, and setOrigin: method calls, but that serves no real purpose, and you'd lose the handle on the object so you wouldn't be able to release it later (unless you also sent it an autorelease message as well in the nested method calls, but that's not very pretty).

Cheers,

Steve Kochan
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.