down the rabbit hole of objects

Discussion in 'iPhone/iPad Programming' started by IDMah, Feb 7, 2012.

  1. IDMah, Feb 7, 2012
    Last edited: Feb 7, 2012

    macrumors regular

    #1
    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
    Code:
    @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
    Code:
    
    @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
    Code:
    // blah blah.. @interface FooRow: NSObject{
    
    NSMutableArray * arrayOfFoo;
    }
    
    @property (nonatomic, retain) NSMutableArray *arrayOfFoo;
    
    now FooRow.m
    Code:
    #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
    Code:
    // @interface FooCard: NSObject {
       NSMutableArray *fooRowArray;
       UIImage *fooImage; 
    }
    // and the appropriate property stuff //
    
    
    FooCard.m
    Code:
    #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
    Code:
    #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
    Code:
    
    - (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..

    Code:
    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. 
    
     
  2. chown33, Feb 7, 2012
    Last edited: Feb 7, 2012

    macrumors 603

    #2
    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:
    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:
    Code:
    -(id) initFooWithPos: (NSValue *)position fooName:(NSString *)stringy fooValue:(NSInteger) valeww
    {
      kungFoo = position;
      fooString = stringy;
      someFoo = valeww;
    return self;
    }
    
    needs to be something like this:
    Code:
    -(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.
     
  3. Moderator

    robbieduncan

    Staff Member

    #3
    You seem to confuse objects (instances of classes) with classes. Foo is a class. Not an object.
     
  4. macrumors regular

    #4
    Yeap I am Dumb.

    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:

    Code:
    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.
     
  5. Moderator

    dejo

    Staff Member

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

    MattInOz

    #6
    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
     
  7. macrumors regular

    #7
    copy that.

    Yeap it is and so I will..

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

    thanks.
     
  8. macrumors 68030

    MattInOz

    #8
    If you haven't found one already...
    There are some really good Coding Style Guides around. Even if your the only person who reads your code.
     

Share This Page