Accessing data across classes

Discussion in 'iOS Programming' started by jschulbach, Jun 29, 2010.

  1. jschulbach macrumors newbie

    Joined:
    Jun 29, 2010
    #1
    I'm learning Objective C via the online Stanford iPhone course and am on the 3rd assignment(drawing a polygon in a UIView, adjustable number of sides via user controls). It works just fine except for the redrawing part, I know why it is happening but conceptually am not getting how to fix it.

    I've got 3 classes, Controller, PolygonView(the class for the UIView and draw), & PolygonShape(defines & stores the polygon). The controller has an IBOutlet to the PolygonShape class and the PolygonView class has an IBOutlet to PolygonShape as well. Does that mean that if I access PolygonShape from either of those two classes that I'm talking to the same instance with the same data? It appears that they aren't the same instance and I'm confused as to how I would access the same data from both.

    With the whole MVC model in my case I suppose the PolygonView being a UIView would access PolygonShape(the model?) through the Controller? but since the controller already initialized the initial instance of the PolygonShape object what is the syntax for PolygonView to talk to access info from my Controller?

    I'm new to OO programming and I'm sure it's a simple solution just doesn't seem to be jumping out from reading forums and Google searches. Thanks for any input!

    Code:
    controller.h -->
    
    #import <UIKit/UIKit.h>
    #import <Foundation/Foundation.h>
    #import "PolygonShape.h"
    #import "PolygonView.h"
    
    @interface Controller : NSObject {
        IBOutlet UIButton *decreaseButton;
        IBOutlet UIButton *increaseButton;
        IBOutlet UILabel *numberOfSidesLabel;
    	IBOutlet UILabel *maxSidesLabel;
    	IBOutlet UILabel *minSidesLabel;
    	IBOutlet UILabel *shapeNameLabel;
    	IBOutlet UILabel *angleRadLabel;
    	IBOutlet UILabel *angleDegLabel;
    	IBOutlet PolygonShape *myPoly;
    	IBOutlet PolygonView *view;
    }
    - (IBAction)decrease:(id)sender;
    - (IBAction)increase:(id)sender;
    - (void)updateInterface;
    @end
    
    controller.m -->
    
    #import "Controller.h"
    
    @implementation Controller
    - (IBAction)decrease:(id)sender {
    	--myPoly.numberOfSides;
    	NSLog(@"I’m in the decrease method %i", myPoly.numberOfSides);
    	[self updateInterface];
    }
    
    - (IBAction)increase:(id)sender {
    	++myPoly.numberOfSides;
    	NSLog(@"I’m in the increase method");
    	[self updateInterface];
    }
    
    -(void)awakeFromNib {
    	NSUserDefaults *prefs = [NSUserDefaults standardUserDefaults];
        NSInteger savedSides = [prefs integerForKey:@"integerKey"];
        NSLog(@"SavedSides: %d",savedSides);	
    	if (savedSides) {
            myPoly.numberOfSides = (int)savedSides;
    		numberOfSidesLabel.text = [NSString stringWithFormat:@"%d", (int)savedSides];
        } else {
            myPoly.numberOfSides = numberOfSidesLabel.text.integerValue;
        } 
    	myPoly = [[PolygonShape alloc] initWithNumberOfSides:numberOfSidesLabel.text.integerValue minimumNumberOfSides:3 maximumNumberOfSides:12];
    	NSLog (@"My polygon: %@", myPoly);
    	numberOfSidesLabel.text = [NSString stringWithFormat:@"%i", myPoly.numberOfSides];
    	[self updateInterface];
    }
    
    -(void)updateInterface {
    	NSUserDefaults *prefs = [NSUserDefaults standardUserDefaults];
        [prefs setInteger:myPoly.numberOfSides forKey:@"integerKey"];
    	if(myPoly.numberOfSides == myPoly.minimumNumberOfSides) {
    		decreaseButton.enabled = NO;
    	} else {
    		decreaseButton.enabled = YES;
    	}
    	if(myPoly.numberOfSides == myPoly.maximumNumberOfSides) {
    		increaseButton.enabled = NO;
    	} else {
    		increaseButton.enabled = YES;
    	}
    	numberOfSidesLabel.text = [NSString stringWithFormat:@"%i", myPoly.numberOfSides];
    	shapeNameLabel.text = [myPoly name];
    	angleDegLabel.text = [NSString stringWithFormat:@"%f", [myPoly angleInDegrees]];
    	angleRadLabel.text = [NSString stringWithFormat:@"%f", [myPoly angleInRadians]];
    	maxSidesLabel.text = [NSString stringWithFormat:@"%i", myPoly.maximumNumberOfSides];
    	minSidesLabel.text = [NSString stringWithFormat:@"%i", myPoly.minimumNumberOfSides];
    	
    	[view setNeedsDisplay];
    }
    
    
    @end
    
    PolygonView.h -->
    
    #import "PolygonShape.h"
    
    @interface PolygonView : UIView {
    
    	IBOutlet PolygonShape *myPoly;
    	
    }
    
    -(void)drawRect:(CGRect)rect;
    
    @end
    
    PolygonView.m -->
    
    #import "PolygonView.h"
    
    
    @implementation PolygonView
    
    + (NSArray *)pointsForPolygonInRect:(CGRect)rect numberOfSides:(int)numberOfSides {
    	CGPoint center = CGPointMake(rect.size.width / 2.0, rect.size.height / 2.0);
    	float radius = 0.9 * center.x; NSMutableArray *result = [NSMutableArray array];
    	float angle = (2.0 * M_PI) / numberOfSides;
    	float exteriorAngle = M_PI - angle;
    	float rotationDelta = angle - (0.5 * exteriorAngle);
    	for (int currentAngle = 0; currentAngle < numberOfSides; currentAngle++) {
    		float newAngle = (angle * currentAngle) - rotationDelta;
    		float curX = cos(newAngle) * radius;
    		float curY = sin(newAngle) * radius;
    		[result addObject:[NSValue valueWithCGPoint:CGPointMake(center.x + curX, center.y + curY)]];
    	}
    	return result;
    }
    
    - (void)drawRect:(CGRect)rect {
    	CGContextRef context = UIGraphicsGetCurrentContext();
        CGRect bounds = [self bounds];
        [[UIColor darkGrayColor] set];
        UIRectFill (bounds);
        [[UIColor lightGrayColor] setFill];
        [[UIColor blueColor] setStroke];
        CGContextDrawPath (context, kCGPathFillStroke);
        NSArray *pts;
        int i;
        NSValue *theValue;
        CGPoint thePoint;
    
        pts = [PolygonView pointsForPolygonInRect:bounds numberOfSides:myPoly.numberOfSides];
        CGContextBeginPath (context);
        theValue = [pts objectAtIndex:(NSInteger)0];
        thePoint = [theValue CGPointValue];
        CGContextMoveToPoint (context, thePoint.x, thePoint.y);
        for (i = 1; i < myPoly.numberOfSides; i++) {
            theValue = [pts objectAtIndex:(NSInteger)i];
            thePoint = [theValue CGPointValue];
            CGContextAddLineToPoint (context, thePoint.x, thePoint.y);
        }
        theValue = [pts objectAtIndex:(NSInteger)0];
        thePoint = [theValue CGPointValue];
        CGContextAddLineToPoint(context, thePoint.x, thePoint.y);
    
        CGContextDrawPath (context, kCGPathFillStroke);
        return;
    }
    
    
    @end
    
    PolygonShape.h -->
    
    #import <Foundation/Foundation.h>
    
    
    @interface PolygonShape : NSObject {
    	int numberOfSides;
    	int minimumNumberOfSides;
    	int maximumNumberOfSides;
    }
    
    @property int numberOfSides;
    @property int minimumNumberOfSides;
    @property int maximumNumberOfSides;
    @property (readonly) float angleInDegrees;
    @property (readonly) float angleInRadians;
    @property (readonly) NSString *name;
    @property (readonly) NSString *description;
    
    - (id) init;
    - (id)initWithNumberOfSides:(int)sides minimumNumberOfSides:(int)min maximumNumberOfSides:(int)max;
    - (void) dealloc;
    
    @end
    
    PolygonShape.m -->
    
    #import "PolygonShape.h"
    
    
    @implementation PolygonShape
    
    @synthesize numberOfSides, minimumNumberOfSides, maximumNumberOfSides;
    
    
    - (void) setNumberOfSides:(int) numSides {	
    	
    	if(numSides < minimumNumberOfSides) {
    		NSLog(@"Invalid number of sides: %d is less than the minimum of %d allowed.", numSides, minimumNumberOfSides);
    	} else if(numSides > maximumNumberOfSides) {
    		NSLog(@"Invalid number of sides: %d is greater than the maximum of %d allowed.", numSides, maximumNumberOfSides);
    	} else {
    		numberOfSides = numSides;
    	}
    }
    
    - (void) setMinimumNumberOfSides:(int) minSides {
    	if(minSides > 2) {
    		minimumNumberOfSides = minSides;
    	} else {
    		NSLog(@"Invalid number of sides: %d is less than the minimum of 3 allowed.", minSides);
    	}
    }
    
    - (void) setMaximumNumberOfSides:(int) maxSides {
    	if(maxSides <= 12) {
    		maximumNumberOfSides = maxSides;
    	} else {
    		NSLog(@"Invalid number of sides: %d is greater than the maximum of 12 allowed.", maxSides);
    	}
    }
    
    - (id)initWithNumberOfSides:(int)sides minimumNumberOfSides:(int)min maximumNumberOfSides:(int)max {
    	if (self = [super init]) {
    		[self setMinimumNumberOfSides:min];
    		[self setMaximumNumberOfSides:max];
    		[self setNumberOfSides:sides];
    	}
    	return self;
    }
    
    - (id)init {
    	return [self initWithNumberOfSides: 5 minimumNumberOfSides: 3 maximumNumberOfSides: 10 ];
    }
    
    - (float) angleInDegrees {
    	return (180 * (numberOfSides - 2) / numberOfSides);
    }
    
    - (float) angleInRadians {
    	return (M_PI * (numberOfSides - 2) / numberOfSides);
    }
    
    - (NSString *) name {
    	NSDictionary *names = [NSDictionary dictionaryWithObjectsAndKeys: @"Triangle", [NSNumber numberWithInt:3], @"Square", [NSNumber numberWithInt:4],
    						   @"Pentagon", [NSNumber numberWithInt:5],
    						   @"Hexagon", [NSNumber numberWithInt:6],
    						   @"Heptagon", [NSNumber numberWithInt:7],
    						   @"Octagon", [NSNumber numberWithInt:8],
    						   @"Nonagon", [NSNumber numberWithInt:9],
    						   @"Decagon", [NSNumber numberWithInt:10],
    						   @"Hendecagon", [NSNumber numberWithInt:11],
    						   @"Dodecagon", [NSNumber numberWithInt:12], nil];
    	return [names objectForKey:[NSNumber numberWithInt:[self numberOfSides]]];
    }
    
    - (NSString *) description {
    	return [NSString stringWithFormat:@"Hello I am a %d-sided %@ with angled of %f degrees (%f radians).", [self numberOfSides], [self name], [self angleInDegrees], [self angleInRadians]];
    }
    
    - (void) dealloc {
    	NSLog(@"Deallocating...");
    	[super dealloc];
    }
    
    @end
    
     
  2. ritsard macrumors regular

    ritsard

    Joined:
    Jun 18, 2009
    Location:
    SF Bay Area, CA
    #2
    I think in your setup, you don't need to have the IBOutlet PolygonShape *myPoly in your Controller class since it is already in the PolygonView. You need to setup the PolygonView to directly work with the PolygonShape model, unless your professor says differently.

    Another issue I see is this:

    Code:
    controller.m
    -(void)awakeFromNib {
    	NSUserDefaults *prefs = [NSUserDefaults standardUserDefaults];
        NSInteger savedSides = [prefs integerForKey:@"integerKey"];
        NSLog(@"SavedSides: %d",savedSides);	
    	if (savedSides) {
            myPoly.numberOfSides = (int)savedSides;
    		numberOfSidesLabel.text = [NSString stringWithFormat:@"%d", (int)savedSides];
        } else {
            myPoly.numberOfSides = numberOfSidesLabel.text.integerValue;
        } 
    	myPoly = [[PolygonShape alloc] initWithNumberOfSides:numberOfSidesLabel.text.integerValue minimumNumberOfSides:3 maximumNumberOfSides:12];
    	NSLog (@"My polygon: %@", myPoly);
    	numberOfSidesLabel.text = [NSString stringWithFormat:@"%i", myPoly.numberOfSides];
    	[self updateInterface];
    }
    
    I am not sure if the first call to myPoly would work since it has not been instantiated yet. Unless, you will access the PolygonShape in the PolygonView.

    Why do you have the PolygonShape in PolygonView as an IBOutlet?
     
  3. jschulbach thread starter macrumors newbie

    Joined:
    Jun 29, 2010
    #3
    I think my confusion is coming from the IBOutlets and how data is shared between the classes. If I am understanding correctly, you think that the PolygonShape(myPoly) should only exist and be instantiated within the PolygonView class. Because I have an IBOutlet from the controller to the PolygonView does that mean I can access the PolygonShape(myPoly) that has been instantiated in the PolygonView class? Would I need to @synthesize myPoly in the PolygonView class then access myPoly from controller like this:

    [[myPolygonView myPoly] methodToCallOnMyPoly]

    Assuming myPolygonView in the polygonView instantiated in controller? Thanks for the help. I'm sure I'll have the "click" moment where it will all make sense but I'm still missing a few pieces on how all the classes link up and share data.
     
  4. ritsard macrumors regular

    ritsard

    Joined:
    Jun 18, 2009
    Location:
    SF Bay Area, CA
    #4
    The IBOutlets are used by InterfaceBuilder so you can connect the items. If there is no need for an item to be connected via InterfaceBuilder, then you do not need that keyword. You are correct that you just have to instantiate a PolygonShape and have its setters and getters created using @synthesize. Make sure that you define them as a property in the .h.
     

Share This Page