PDA

View Full Version : down the rabbit hole of objects




IDMah
Feb 7, 2012, 09:56 PM
Ok ok I know this should be easy but .. I just can't get it to work
basically passing an array of NSValues up several Objects..

I have several objects. let's say.

FooView
FooCard
FooRow
Foo

in Foo.h

@interface foo : NSObject {
NSValue *kungFoo; // a NSValue holding a CGPoint //
NSInteger someFoo;
NSString *fooString;

@property (nonatomic,retain) NSValue *kungFoo;
@property (nonatomic) NSInteger someFoo;
@property (nonatomic,retain) NSString *fooString;



in Foo.m


@implementation Foo
@synthesize kungFoo,someFoo,fooString;
-(id)init
{
fooString = [[NSString alloc]init];
kungFoo = [[NSValue alloc] init];
return self;
}
-(id) initFooWithPos: (NSValue *)position fooName:(NSString *)stringy fooValue:(NSInteger) valeww
{
kungFoo = position;
fooString = stringy;
someFoo = valeww;
return self;
}


ok in FooRow.h

// blah blah.. @interface FooRow: NSObject{

NSMutableArray * arrayOfFoo;
}

@property (nonatomic, retain) NSMutableArray *arrayOfFoo;


now FooRow.m

#import "FooRow.h"
#import "Foo.h"
-(id)init{

arrayOfFoo = [[NSMutableArray alloc]init];
return self;
}

-(id)initFooRowWith:(NSInteger)numberOfFoosRows
{
int numberOfFooRows = 7;
Foo *newFoo = [[Foo alloc] init];
for(int i = numberOfFoosRows; i>0;i--) {
CGPoint myFooPoint;
myFooPoint =CGPointMake(((numberOfFoo-i)*10), 45);
NSValue *tempFoo = [NSValue valueWithCGPoint:myFooPoint);
[tempFoo initFooWithPos: tempFoo fooName:@"test123" fooValue:12];
[arrayOfFoo addObject:tempFoo];
[tempFoo release];
}
return self;
}


getting there. Now FooCard.h

// @interface FooCard: NSObject {
NSMutableArray *fooRowArray;
UIImage *fooImage;
}
// and the appropriate property stuff //



FooCard.m

#import "FooCard.h"
#import "FooRow.h"

// implementation and synthesize stuff...//
-(id) init{
fooRowArray = [[NSMutableArray alloc]init];
fooImage = [[UIImage alloc]init];
return self;
}

-(id)initWithFooCardWith:(NSInterger )numberOfRows{

for (int i=numberOfRows;i>0; i--)
{
NSLog(@" creating row:%i",(numberOfRows-i));
FooRow *newRow =[[FooRow alloc] initFooRowWith:7];
[fooRowArray addObject:newRow];
[newRow release];
}
[self setFooImage:[UIImage imageNamed:@"fooImagePicture.png"]];
returns self;
}



Finally FooView.h

#import <UIKit/UIKit.h>
#import "FooCard.h"
#import "FooRow.h"
#import "Foo.h"

@interface FooView : UIView {
FooCard *currentCard;
}

@property (nonatomic,retain) FooCard *currentCard;

- (void)drawAFooCard:(FooCard *)cardToDraw;

@end

FooView.m


- (void)drawAFooCard:(FooCard *)cardToDraw
{
currentFooCard = [[[Card alloc]init]retain];
currentFooCard.fooImage = [[UIImage alloc] init];

NSLog(@"using DrawCard function");
currentCard = cardToDraw;

[self setNeedsLayout];
}

- (void)drawRect:(CGRect)rect {
// Drawing code.
CGRect bounds = [self bounds];
CGPoint topLeftCorner;
CGPoint centre;
topLeftCorner.x = bounds.origin.x + bounds.size.width * 0.10; // in percentage of screen size //
topLeftCorner.y = bounds.origin.y + bounds.size.height * 0.10; // in percentage of the screen size //

centre.x = bounds.origin.x + bounds.size.width / 2; // in percentage of screen size //
centre.y = bounds.origin.y + bounds.size.height/ 2; // in percentage of the screen size //
UIImageView *fooBackground = [[[UIImageView alloc]
initWithImage:[[currentFooCard fooImage]
stretchableImageWithLeftCapWidth:0.0
topCapHeight:0.0]]retain];

[cardBackground setFrame:CGRectMake(0, 0,bounds.size.width,bounds.size.height)];
[cardBackground setAlpha:1.0];
[self addSubview:cardBackground];
[self sendSubviewToBack:cardBackground];
[cardBackground release];


// ****** the above stuff works perfectly the image appears etc **** but !!! //

UIImage* uiimag = [UIImage imageNamed:@"YellowBlob.png"];
UIGraphicsBeginImageContext(mysize);
CGPoint fooPost;

// I was trying anything to get it to work here //
NSInteger currentRow = 0; // for testing sake //
FooRow *fooRowCurrent = [[FooRow alloc] init];
Foo *currentFoo = [[Foo alloc] init];
cardRowCurrent.arrayStamps = [[NSMutableArray alloc] init];

fooRowCurrent = [currentFooCard fooRowArray] objectAtIndex:currentRow];
NSValue *convertValue = [[NSValue alloc]init];

for (int i=7; i>0; i--) {
currentFoo = [[fooRowCurrent fooArray] objectAtIndex:(7-i)];
convertValue = [currentFoo fooPos];
fooPost =[convertValue CGPointValue];
NSLog(@"index: %i x=%f y=%f",(7-i),fooPost.x.,fooPost.y);
// cod for putting graphics down .. etc//
}



I get values of "index:0 x=0 y=0" ... seven times.. of course what I want is co-ordinates..


index: 0 x=0 y=45
index: 1 x=10 y=45
index: 2 x=20 y=45
index: 3 x=30 y=45
index: 4 x=40 y=45
ect.



chown33
Feb 7, 2012, 10:50 PM
Are you using ARC or not? Because if you're not, then you're leaking a lot of objects. Then again, if you are using ARC, your uses of release are wrong.

In this code:
-(id)initFooRowWith:(NSInteger)numberOfFoosRows
{
int numberOfFooRows = 7;
Foo *newFoo = [[Foo alloc] init];
for(int i = numberOfFoosRows; i>0;i--) {
CGPoint myFooPoint;
myFooPoint =CGPointMake(((numberOfFoo-i)*10), 45);
NSValue *tempFoo = [NSValue valueWithCGPoint:myFooPoint);
[tempFoo initFooWithPos: tempFoo fooName:@"test123" fooValue:12];
[arrayOfFoo addObject:tempFoo];
[tempFoo release];
}
return self;
}

How many distinct Foo objects are you creating, setting the position, then adding to arrayOfFoo?

If your answer "seven", you're wrong. Where is the alloc & init of a Foo object? It's not in the loop, so it's not being performed each time around the loop.

Also, that's a trick question, because you're not adding any Foo objects to arrayOfFoo.

That object named tempFoo isn't a Foo instance at all. So calling initFooWithPos: on it isn't going to work at all.

You then add tempFoo (which isn't a Foo object) to arrayOfFoo. So the array actually ends up holding NSValue objects, not Foo objects.


Frankly, you should start at the bottom, with the Foo class. Make that work. Which means writing a -description method for it that returns a useful and informative string, so you can NSLog it with the %@ formatter. Now you can also use the debugger on it.

Next, write a simple test that does nothing but make a few different (and distinct) instances of Foo, with different positions, then uses NSLog to show them. Confirm that everything works as expected.

Now move up one level. Write code that builds an array of Foo objects. Correctly. By making one Foo object, setting its position, then adding it to the array. Not adding the NSValue to the array. Confirm it works by writing a test, showing the class name of every object in the array (it's easy to do, but you need to think about how to get a class name for an object).

Every output value should be exactly what you expect. If it's not, debug it until there are no obvious errors.

And along the way, make sure you have all your memory management correct, either by using ARC or by using retain/release. You're currently leaking objects in your Foo methods, because you're accessing the instance variables directly, rather than as properties. For example:

-(id) initFooWithPos: (NSValue *)position fooName:(NSString *)stringy fooValue:(NSInteger) valeww
{
kungFoo = position;
fooString = stringy;
someFoo = valeww;
return self;
}

needs to be something like this:

-(id) initFooWithPos: (NSValue *)position fooName:(NSString *)stringy fooValue:(NSInteger) valeww
{
self.kungFoo = position;
self.fooString = stringy;
self.someFoo = valeww;
return self;
}

And you've failed to call [super init]. And you should never call an init method on the same object more than once.

And I didn't even get to the FooCard or FooView classes, which are also riddled with errors (including memory management errors).


You need to rethink your whole approach. Make the foundations work. Confirm they work by writing tests. Confirm the tests work by looking at their output and confirming it's all correct. Only when a foundation is properly built can you rely on it in other classes.

You're writing code as if testing and debugging is something performed after everything is already built. That's crazy. You have test and debug as you go along, so you have a reason to believe that what you have actually works. Without that, you have nothing to build on.

Right now, you're building on quicksand, with no testing of low-level things, no confirmation that anything works, and probably little or no attention paid to warnings that the compiler should be giving you (e.g. when you used initFooWithPos: on an NSValue object, the compiler should have warned about it).


EDIT
Or maybe you didn't post your real code. Because you use a variable named numberOfFoo that doesn't exist anywhere else in the code. Which means it can't possibly compile as posted.

In which case, either post your real code (the preferred option), or at least make sure that the fictional code you're posting will compile.

robbieduncan
Feb 8, 2012, 02:32 AM
You seem to confuse objects (instances of classes) with classes. Foo is a class. Not an object.

IDMah
Feb 8, 2012, 01:19 PM
Well took a while but. worked through every level as chown33 suggested..

I was:

a. not using [self setKungFoo: (NSValue*)];
b. not initializing the MutableArray in the right place.
c. trying to init something gawd knows what! Instead of something like this:

Stamp * newStamp = [[Stamp alloc]initStampWithPos:myPoint StampSize:mySize stampType:1];

d. Basically stupid.. XCode makes it so easy to do Hard stuff like graphics, buttons and stuff. it's easy to not get the fundamentals down.. still hazy on some of it but will work on it..

thanks everyone !!
Ian

ps. and Yes! Pseudo code is useless.. and a mess.

dejo
Feb 8, 2012, 01:31 PM
Stamp * newStamp = [[Stamp alloc]initStampWithPos:myPoint StampSize:mySize stampType:1];

By the way, common naming conventions would have your second parameter named stampSize and not StampSize (which would seem to be a class name).

MattInOz
Feb 8, 2012, 08:06 PM
By the way, common naming conventions would have your second parameter named stampSize and not StampSize (which would seem to be a class name).

I would have thought with message selectors being read in full that the extra stamp was redundant?

with the current message selector is
- initStampWithPos:stampSize:stampType.
would it be more readable as
- initStampType:atPosition:withSize

IDMah
Feb 9, 2012, 10:35 AM
Yeap it is and so I will..

hence forth .. lowercase-capital-capital colon..

thanks.

MattInOz
Feb 9, 2012, 11:32 PM
If you haven't found one already...
There are some really good Coding Style Guides (http://cocoadevcentral.com/articles/000082.php) around. Even if your the only person who reads your code.