ObjC: Can't access ivar of custom class from outside - objective-c

I'm attempting to make a basic game in cocos2d, and I've gotten to the point where I'm attempting to scroll the background depending on the hero sprite's position. The hero's created alongside the controls in a class called GameplayLayer, and all works fine for non-scrolling backgrounds.
The book I'm following has given me some sample code to get the scrolling working based on when my character passes the half-way point, which seems perfect, but it's not executing, I believe this is because it's creating another instance of my Hero class, and there's no link between that instance, and the one that's displayed onscreen.
I'm assuming that I can fix this by making the working instance of my hero accessible from within the background scrolling class (which is called YrrasCoastBackgroundLayer), but I'm having a brain-block and can't get it to see it. I've tried a #property, but Xcode just won't see it in the other class.
Here's the .h file from the GameplayLayer class, where the hero is created / hooked up to controls, etc.:
#import "CCLayer.h"
#import "cocos2d.h"
#import "CommonProtocols.h"
#import "SneakyJoystick.h"
#import "SneakyButton.h"
#import "SneakyJoystickSkinnedBase.h"
#import "SneakyButtonSkinnedBase.h"
#import "HeroMale.h"
#import "GameCharacter.h"
#interface GameplayLayer : CCLayer <GameplayLayerDelegate> {
CCSprite *playerSprite;
SneakyJoystick *playerJoystick;
SneakyButton *jumpButton;
CCSpriteBatchNode *sceneSpriteBatchNode;
HeroMale *heroMale;
}
#property (nonatomic, readonly) SneakyJoystick *playerJoystick;
#property (nonatomic, readonly) SneakyButton *jumpButton;
#property (nonatomic, assign) HeroMale *heroMale;
#end
The YrrasCoastBackgroundLayer.h file definitely imports GameplayLayer.h, and here's the contents of the method in YrrasCoastBackgroundLayer.m file which I want to be able to access that *heroMale ivar:
- (void) adjustLayer {
float heroXPosition = heroMale.position.x;
CGSize screenSize = [[CCDirector sharedDirector] winSize];
float halfOfTheScreen = screenSize.width / 2.0f;
CGSize levelSize = [[GameManager sharedGameManager] getDimensionsOfCurrentScene];
if ((heroXPosition > halfOfTheScreen) && (heroXPosition < (levelSize.width - halfOfTheScreen))) {
float newXPosition = halfOfTheScreen - heroXPosition;
[self setPosition:ccp(newXPosition, self.position.y)];
}
}
I'm getting an Xcode error on the float heroXPosition = heroMale.position.x line, stating that heroMale is an undeclared identifier. How can I make it usable here, and will that even solve the problem?
UPDATE:
Here's the .h file for YrrasCoastBackgroundLayer:
#import "CCLayer.h"
#import "cocos2d.h"
#import "HeroMale.h"
#import "GameplayLayer.h"
#interface YrrasCoastBackgroundLayer : CCLayer {
// Web Tutorial
CCParallaxNode *backgroundNode;
CCSprite *backgroundImage;
// Book Tutorial
CCSpriteBatchNode *sceneSpriteBatchNode;
CCParallaxNode *parallaxNode;
}
#property (nonatomic, assign) GameplayLayer *gameplayLayer;
#end
And here's the YrrasCoastBackgroundLayer.m:
#import "YrrasCoastBackgroundLayer.h"
#implementation YrrasCoastBackgroundLayer
#synthesize gameplayLayer;
- (id) init {
self = [super init];
if (self != nil) {
// Web Tutorial
backgroundNode = [CCParallaxNode node];
[self addChild:backgroundNode z: -1];
backgroundImage = [CCSprite spriteWithFile:#"yrras-coast-ipad-hd.png"];
CGPoint dustSpeed = ccp(0.1, 0.1);
[backgroundNode addChild:backgroundImage z:0 parallaxRatio:dustSpeed positionOffset:ccp(1024, [[CCDirector sharedDirector]winSize].height / 2)];
self.gameplayLayer = gameplayLayer;
[self scheduleUpdate];
}
return self;
}
- (void)update:(ccTime)deltaTime {
// Web Tutorial
// CGPoint backgroundScrollVel = ccp(-1000, 0);
// backgroundNode.position = ccpAdd(backgroundNode.position, ccpMult(backgroundScrollVel, deltaTime));
CCArray *listOfGameObjects = [sceneSpriteBatchNode children];
for (GameCharacter *tempChar in listOfGameObjects) {
[tempChar updateStateWithDeltaTime:deltaTime andListOfGameObjects:listOfGameObjects];
}
[self adjustLayer];
}
// Book Tutorial
- (void) adjustLayer {
float heroXPosition = gameplayLayer.heroMale.position.x;
CCLOG(#"heroXPosition is %f", gameplayLayer.heroMale.position.x);
CGSize screenSize = [[CCDirector sharedDirector] winSize];
float halfOfTheScreen = screenSize.width / 2.0f;
CGSize levelSize = [[GameManager sharedGameManager] getDimensionsOfCurrentScene];
if ((heroXPosition > halfOfTheScreen) && (heroXPosition < (levelSize.width - halfOfTheScreen))) {
float newXPosition = halfOfTheScreen - heroXPosition;
[self setPosition:ccp(newXPosition, self.position.y)];
}
}
#end

You need an instance of your GameplayLayer to be passed to the YrrasCoastBackgroundLayer layer.
You can declare an assignable property in YrrasCoastBackgroundLayer :
#property (nonatomic, assign) GameplayLayer gamplayLayer;
and when you initialize your YrrasCoastBackgroundLayer pass the instance of the game play layer and in your adjustLayer method do :
float heroXPosition = gameplayLayer.heroMale.position.x;
EDIT :
assuming this is how you create your scene :
MyScene *scene = [MyScene scene];
gameplayLayer = [[GameplayLayer alloc] init];
bgLayer = [[YrrasCoastBackgroundLayer alloc] init];
bgLayer.gameplayLayer = gameplayLayer; // This is where you assign the gameplay Layer to the background layer;
[scene addChild:bgLayer];
[scene addChild:gameplayLayer];
// Release both layers if you dont need them anymore here (scene addChild retains them when they are added)
[gameplayLayer release];
[bgLayer release];

I am not sure how can you access heroMale as it is not member of YrrasCoastBackgroundLayer but of GameplayLayer. You would have to have object/instance of class GameplayLayer in order for you to access heroMale. That is the reason why you are getting undeclared identifier (heroMale is not property of class YrrasCoastBackgroundLayer).
Kind regards,
Bo

Related

Polyline for MKMapView not working

I've been trying and trying to get this poly line to work in Objective C. I've been through every tutorial I can find and gotten nowhere, I cant see whats wrong with it.
CLLocationCoordinate2D coordinateArray2[2];
coordinateArray2[1].longitude = 176.8773669;
coordinateArray2[0].longitude = 176.88151896;
coordinateArray2[0].latitude = -39.668593;
coordinateArray2[1].latitude = -39.67018069;
_route1Line = [MKPolyline polylineWithCoordinates:coordinateArray2 count:2];
[_GPSView setDelegate:self];
[_GPSView addOverlay:_route1Line];
_testlabel.text = [NSString stringWithFormat:#"%f", coordinateArray2[0].longitude];
can anyone see what is wrong?
header:
#import <UIKit/UIKit.h>
#import <MapKit/MapKit.h>
extern int routenumber; //holds current route ID
extern BOOL inRoute; //holds if on route or not
extern int followYou; //holds if the app should follow the user or predefined coordinates
extern NSArray *routeHolder; //holds array of routes
#interface ViewController : UIViewController <MKMapViewDelegate>
#property (weak, nonatomic) IBOutlet MKMapView *GPSView; //adding the map view to the controller
#property (nonatomic, retain) MKPolyline *route1Line; //line for this route
#property (weak, nonatomic) IBOutlet UILabel *testlabel;
#end
You should implement the following method of MKMapViewDelegate:
- (MKOverlayRenderer *)mapView:(MKMapView *)mapView rendererForOverlay:(id<MKOverlay>)overlay
{
MKOverlayPathRenderer *theOverlayPathRenderer;
{
theOverlayPathRenderer = [[MKPolylineRenderer alloc] initWithPolyline:overlay];
theOverlayPathRenderer.lineWidth = ...;
theOverlayPathRenderer.fillColor = ...;
theOverlayPathRenderer.strokeColor = ...;
}
return theOverlayPathRenderer;
}
I'm not at a Mac at the moment so I can't run your code, but it looks like you've created your MKPolyline alright, but you're missing the MKPolylineView.
_polylineView = [MKPolylineView alloc] initWithPolyline:route1Line]; // Declare it in your header file or in the implementation's interface.
_polylineView.strokeColor = [UIColor redColor];
_polylineView.lineWidth = 5.0
Then make sure you conform to the MKMapViewDelegate and implement mapView:viewForOverlay
- (MKOverlayView *)mapView:(MKMapView *)mapView viewForOverlay:(id<MKOverlay>)overlay {
return _polylineView;
}

Scope between methods

Another newbie question. I am trying to understand how to use scope effectively to organise my projects using classes to hold the data instead of having everything on the view controller. So, I am working on a couple of versions of a simple project to understand how scope works.
I have a view controller hooked to a view. In that view there are buttons that when clicked show images. I want to add another button that randomizes the images. I also have a class called "Cards" to hold the cards and the methods for creating and shuffling the cards. I have duplicated the project, so I have one that works and one that doesn't.
First project. These are the files:
view controller h file:
#import <UIKit/UIKit.h>
#import "Cards.h"
#interface ViewController : UIViewController
- (IBAction)buttonPressed:(id)sender;
#end
view contoller m file:
#import "ViewController.h"
#interface ViewController ()
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
Cards *instance = [[Cards alloc] init];
instance.images = [instance createImages];
NSLog(#"I've got %lu Images", (unsigned long)instance.images.count);
instance.shuffled = [instance shuffleImages];
NSLog(#"Image numbers shuffled: %#", instance.shuffled);
}
- (IBAction)buttonPressed:(id)sender {
//Nothing hooked to this yet
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#end
Cards h file:
#import <UIKit/UIKit.h>
#import <Foundation/Foundation.h>
#interface Cards : NSObject
// Creating Images
#property NSMutableArray *images;
- (NSMutableArray*) createImages;
//Shuffling Images
#property NSMutableArray *shuffled;
- (NSMutableArray*) shuffleImages;
#end
Cards m file:
#import "Cards.h"
#implementation Cards
- (NSMutableArray*) createImages{
self.images = [[NSMutableArray alloc] initWithObjects:
[UIImage imageNamed:#"Image1.png"],
[UIImage imageNamed:#"Image2.png"],
[UIImage imageNamed:#"Image3.png"],
[UIImage imageNamed:#"Image4.png"], nil];
return self.images;
}
- (NSMutableArray*) shuffleImages{
NSUInteger imageCount = [self.images count];
NSMutableArray *localvar = [[NSMutableArray alloc]init];
for (int tileID = 0; tileID < imageCount; tileID++){
[localvar addObject:[NSNumber
numberWithInt:tileID]];
}
for (NSUInteger i = 0; i < imageCount; ++i) {
NSInteger nElements = imageCount - i;
NSInteger n = (arc4random() % nElements) + i;
[localvar exchangeObjectAtIndex:i
withObjectAtIndex:n];
}
return localvar;
}
#end
This works and I get the expected output on the console:
2015-12-31 23:43:44.885 VCScope[2138:533369] I've got 4 Images
2015-12-31 23:43:44.886 VCScope[2138:533369] Image numbers shuffled: (
0,
2,
3,
1
)
Second project:
What I want to do, is put a button to randomize the images only when the button is pressed and not as part of viewDidLoad. So, in my second project, I have the same files for the view controller.h and for both the Cards.h and Cards.m, but on the view controller.m I move the calling of the method for the shuffling of the cards to a UIButton method, like so:
new View controller m file:
#import "ViewController.h"
#interface ViewController ()
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
Cards *instance = [[Cards alloc] init];
instance.images = [instance createImages];
NSLog(#"I've got %lu Images", (unsigned long)instance.images.count);
}
- (IBAction)buttonPressed:(id)sender {
Cards *instance = [[Cards alloc] init];
instance.shuffled = [instance shuffleImages];
NSLog(#"Image numbers shuffled: %#", instance.shuffled);
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#end
This outputs to the console the following:
2015-12-31 23:32:07.495 4StackVCScope[2029:486608] I've got 4 Images
2015-12-31 23:32:11.924 4StackVCScope[2029:486608] Image numbers: (
)
So it's not working and I am guessing it's to do with scope. Can someone throw some light into this? thanks
Welcome to Stack Overflow. You mention you're a "newbie", but it would be helpful to know what background you have so I know how much detail is needed here.
Cards *instance = [[Cards alloc] init];
creates a fresh Cards instance in a local variable. You are doing this separately inside -viewDidLoad and in -buttonPressed:.
If you want one Cards object per ViewController, then the view controller needs to have per-instance storage for it. There are several possible ways to do this. Which one you pick is a question of code style and API design.
If the Cards instance is for internal use only, you can declare an ivar in your #implementation block:
#implementation ViewController {
Cards *_cards;
}
- (void)viewDidLoad { _cards = ... }
- (IBAction)buttonPressed:(id)sender { access _cards }
#end
(Ivars can be declared in the public #interface as well, but I wouldn't recommend that as it leaks implementation details.)
Or you can use a property in the public interface:
// in your .h file:
#interface ViewController
#property (nonatomic) Cards *cards;
#end
// in your #implementation:
- (void)viewDidLoad { self.cards = ... }
- (IBAction)buttonPressed:(id)sender { access self.cards }
A property can also be privately declared in a class extension:
// in your .m file:
#interface ViewController ()
#property (nonatomic) Cards *cards;
#end

Create a subclass of a SKSpriteNode subclass

Let's say I want to create a bunch of different types of Spaceships. I want to setup a base spaceship class that I can use to create other spaceships with minor differences.
My base class looks like this.
// BaseSpaceship.h
#interface SpaceshipNode : SKSpriteNode
#property NSColor color;
#property CGFloat engineThrust;
+ (id)baseSpaceshipWithImageNamed:(NSString *)name;
#end
// BaseSpaceship.m
#implementation BaseSpaceship
+ (id)baseSpaceshipWithImageNamed:(NSString *)name {
BaseSpaceship *ship = [BaseSpaceship spriteNodeWithImageNamed:name];
ship.color = [NSColor redColor];
ship.engineThrust = 2.0;
return ship;
}
#end
I can create a ship in MyScene.m like this just fine.
BaseSpaceship *baseClass = [BaseSpaceship baseSpaceshipWithImageNamed:#"BaseShip"];
However, I'm not sure how to create a subclass of BaseSpaceship, for example, DestroyerSpaceship. I'm not sure if I should be using static methods or not. The examples I've seen online use static methods to instantiate SKSpriteNodes. This is what I came up with, but it's wrong.
// DestroyerSpaceship.h
#interface DestroyerSpaceship : BaseSpaceship
#property CGFloat missileThrust;
- (id)makeDestroyerSpaceship;
#end
// DestroyerSpaceship.m
#implementation DestroyerSpaceship
- (id)makeDestroyerSpaceship{
DestroyerSpaceship *ship = [DestroyerSpaceship baseSpaceshipWithImageNamed:#"DestroyerShip"];
ship.engineThrust = 2.0;
// ship doesn't have missileThrust, program crashes
ship.missileThrust = 3.0;
return ship;
}
#end
Ultimately, I want to be able to do something like this.
DestroyerSpaceship* a = [DestroyerSpaceship makeDestroyerSpaceship];
EvilSpaceship* b = [EvilSpaceship makeEvilSpaceship];
NiceSpaceship* c = [NiceSpaceship makeNiceSpaceship];
And have them all inherit basic properties and methods from BaseSpaceship.
The answer is less complex than you think. Well, the code might be a bit more complex, but once you have the structure it is most flexible. Creating the different types of spaceships will also be a lot more readable.
You can override the initializer method in the subclass. As a sidenote, use (instancetype) instead of (id) (source: instancetype # NSHipster).
As you are adding custom body sprites to the object, I would opt to subclass SKNode instead of SKSpriteNode (so #interface SpaceshipNode : SKNode instead of #interface SpaceshipNode : SKSpriteNode).
#interface SpaceshipNode : SKNode
#property SKColor * color; // Use SKColor instead of NSColor
#property CGFloat engineThrust;
#end
// ...
#implementation SpaceshipNode
- (instancetype) init {
if (self == [super init]) {
NSLog(#"A new SpaceshipNode was just init'ed.");
// set some default initial values here that all brand-new SpaceshipNodes will inherit
// perhaps create and add a basic body sprite
// SKSpriteNode * body = ...;
// [self addChild:body];
// set thrust
self.engineThrust = 2.0;
}
return self;
}
Then you can subclass and create a new type of spaceship. Awesome!
#interface DestroyerSpaceship : SpaceshipNode
#property CGFloat missileThrust;
#end
#implementation DestroyerSpaceship
- (instancetype) init {
// note that [super init] will call the SpaceshipNode's init method
if (self = [super init]) {
NSLog(#"A new DestroyerSpaceship was just init'ed.");
// add a body sprite
// SKSpriteNode * body = ...;
// [self addChild:body];
// a Destroyer is much faster than your average spaceship
self.engineThrust = 10.0;
// set class specific variables
self.missileThrust = 5.f;
}
return self;
}
Now, you can just call:
SpaceshipNode * newSpaceShip = [SpaceshipNode new]; // short for [[SpaceshipNode alloc] init];
DestroyerSpaceship * newDestroyer = [DestroyerSpaceship new];
These two lines will log the following. The last two lines are caused by the Destroyer, which first calls the SpaceshipNode init, and then the Destroyer-specific init method.
A new SpaceshipNode was just init'ed.
A new SpaceshipNode was just init'ed.
A new DestroyerSpaceship was just init'ed.
And you can even use it like this:
SpaceshipNode * newUnidentifiedVessel = [DestroyerSpaceship new];
if ([newUnidentifiedVessel isKindOfClass:[DestroyerSpaceship class]]) {
NSLog(#"We are under attack! Route power to shields!");
}
- (instancetype)makeDestroyerSpaceship{
if (self = [super baseSpaceshipWithImageNamed:#"DestroyerShip"]) {
self.engineThrust = 2.0;
self.missileThrust = 3.0;
}
return self;
}

Objective-C can't tell where the instances of pointers are coming from

I'm a newb for Objective-C...hopefully the terminology in the title is correct...but anyhow. I am following a tutorial and was a bit confused where instances of certain pointers were showing up. I never saw them explicitly defined, and then later the tutorial would modify them. For an example, look below (I tried to include only the necessary code. I put stars * next to the lines that I am confused by the most. Basically I'm not understanding where _meta and _hud are coming from and how I can call methods from them. I guess I would be less confused if they were hud and meta, without the _). Thanks, sorry if it's an amateur question.
#interface PlayGameLayer()
#property (strong) CCTMXLayer *meta;
#property (strong) HudLayer *hud;
#end
+(CCScene *) scene
{
CCScene *scene = [CCScene node];
PlayGameLayer *layer = [PlayGameLayer node];
[scene addChild: layer];
HudLayer *hud = [HudLayer node];
[scene addChild:hud];
layer.hud = hud;
return scene;
}
-(id) init
{
if( (self=[super init]) ) {
....
self.meta = [_tileMap layerNamed:#"Meta"];
_meta.visible = NO; **********************************************
....
}
return self;
}
-(void)setPlayerPosition:(CGPoint)position {
CGPoint tileCoord = [self tileCoordForPosition:position];
int tileGid = [_meta tileGIDAt:tileCoord];
if (tileGid){
NSDictionary *properties = [_tileMap propertiesForGID:tileGid];
if (properties){
NSString *collectible = properties[#"Collectable"];
if (collectible && [collectible isEqualToString:#"True"])
{
[_meta removeTileAt:tileCoord]; ****************************************
self.numCollected++;
[_hud numCollectedChanged:_numCollected];*********************************
}
}
}
_player.position = position;
}
#implementation HudLayer
{
CCLabelTTF *_label;
}
- (id)init
{
self = [super init];
if (self) {
....
}
return self;
}
#end
The instance variables _meta and _hud are implicitly generated by the compiler, as a result of your property definitions:
#property (strong) CCTMXLayer *meta;
#property (strong) HudLayer *hud;
This is a fairly recent addition to Objective-C. You used to need to use #synthesize in your .m file in order to create corresponding instance variables. However, starting from Xcode 4.4, if you don't include a #synthesize for a property, the compiler will automatically generate one for you. For your properties, it's implicitly generating:
#synthesize meta = _meta;
#synthesize hud = _hud;
Here's an article with more details if you're interested.

Calling classes from seperate class in a program

I have an xcode project which has 2 classes - Stem & Player, I'm trying to ensure my code is solid from an object-orientated perspective, I believe it's acceptable programming practice for my Player Class to access information in my Stem Class.
I want to access indices from an array in stem - I can do this from my view controller using
stem.index[i]
when I try to do this from player I'm not allowed as stem is undeclared. I've tried importing Stem.h into my Player.m file & declaring stem in player (similar to how one does this in the view controller), only to get errors (expected specifier-qualifier-list before 'Stem').
What's the correct way to do this? Please excuse any loose use of terminology as I'm relatively new to this. Thanks in advance :)
Edit
Here is some code that might shed some light on things, In the viewController I declare stem & player
#import <UIKit/UIKit.h>
#import <AVFoundation/AVAudioPlayer.h>
#import "Stem.h"
#import "Player.h"
#interface TestApp_v1ViewController : UIViewController {
Stem *stem;
Player *player;
I alloc & init my two objects stem & player in viewController.m
- (void)viewDidLoad {
[super viewDidLoad];
NSLog(#"Init Successful");
[self loadMOV];
[self setupInterface];
stem = [[Stem alloc] init];
player = [[Player alloc] init];
}
I then move to Stem.h where I declare stem again (so that stem is accessible to player when stem.h is imported to player.h - as per glogic's comment)
#import <Foundation/Foundation.h>
#interface Stem : NSObject {
int *index;
int numberOfStems;
Stem *stem;
}
#property(nonatomic,readwrite) int *index;
#property(nonatomic, retain) Stem *stem;
Player.h looks like this:
// Player.h
#import <Foundation/Foundation.h>
#import "Stem.h"
#interface Player : NSObject {
NSMutableArray *player1;
}
#property(nonatomic,retain) NSMutableArray *player1;
-(void) playAudio;
#end
Finally in Player.m I try to access the index array
#import "Player.h"
#implementation Player
#synthesize player1;
-(void)playAudio {
NSLog(#"play audio called");
NSLog(#"index[0] is: %i", stem.index[0]);
}
#end
I'm still being told that stem is undeclared, any ideas?
Edit #2 - adding bare-bones program
I hope this is considered ok but I've decided to post my program (pared down to the bare essentials). I think it may be the only way that the issue might be figured out - since a lot is going on across classes. I've been trying to get this to work for hours now arrrgh...
I alloc'd & initialised my stem & player objects in the viewController - i thought this was the best way to go about this, but maybe there is a better method.
//Part (i)
// TestApp_v1ViewController.h
#import <UIKit/UIKit.h>
#import <AVFoundation/AVAudioPlayer.h>
#import "Stem.h"
#import "Player.h"
#interface TestApp_v1ViewController : UIViewController {
Stem *stem;
Player *player;
}
#property(nonatomic, retain) Stem *stem;
#property(nonatomic, retain) Player *player;
#end
//Part (ii)
// TestApp_v1ViewController.m
#import "TestApp_v1ViewController.h"
#import <MediaPlayer/MediaPlayer.h>
#implementation TestApp_v1ViewController
#synthesize stem;
#synthesize player;
// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
- (void)viewDidLoad {
[super viewDidLoad];
NSLog(#"Init Successful");
stem = [[Stem alloc] init];
[stem loadURLs];
player = [[Player alloc] init];
[player playAudio];
int index = stem.value;
NSLog(#"r is: %i", index); //checking to see if I can get a value from the index array - this works fine, so 'value' can be accessed from the viewController
}
Here I declare an int array & the int "value" which I want to access later from my player (this is what turns out to be the problem)
//Part (iii)
// Stem.h
#import <Foundation/Foundation.h>
#interface Stem : NSObject {
NSMutableArray *urlArray;
int *index;
int value;
int numberOfStems;
Stem *stem;
}
- (void)loadURLs;
- (void)randomiseAudioForInitialPlay;
#property(nonatomic,retain) NSMutableArray *urlArray;
#property(nonatomic,readwrite) int *index;
#property(nonatomic,readwrite) int numberOfStems;
#property(nonatomic,readwrite) int value;
#property(nonatomic, retain) Stem *stem;
#end
//Part (iv)
// Stem.m
#include <stdio.h>
#import "Stem.h"
#implementation Stem
#synthesize numberOfStems;
#synthesize urlArray;
#synthesize index;
#synthesize stem;
#synthesize value;
- (void)loadURLs
{
NSLog(#"Loading URLs");
numberOfStems = 20;
urlArray = [[NSMutableArray alloc] init];
for ( int i = 1; i <= numberOfStems; i++ ) {
NSString *soundName = [NSString stringWithFormat:#"stem-%i", i];
NSString *soundPath = [[NSBundle mainBundle] pathForResource:soundName ofType:#"mp3"];
NSURL *soundFile = [[NSURL alloc] initFileURLWithPath:soundPath];
[urlArray addObject:soundFile];
[soundFile release];
}
[self randomiseAudioForInitialPlay];
}
- (void)randomiseAudioForInitialPlay
{
index = malloc(numberOfStems*sizeof(int));
for (int i = 0; i < numberOfStems; i++)
{
index[i] = i;
}
for (int i = (numberOfStems - 1); i > 0; i--)
{
int randomIndex = arc4random() % i;
int tmp = index[i];
index[i] = index[randomIndex];
index[randomIndex] = tmp;
}
value = self.index[10]; //this is what needs to be accessed later, from player
NSLog(#"value at index 10 is:%i", value);
}
#end
Here I include 'Stem.h' since player will require stem in order to return stem.value
//Part (v)
// Player.h
#import <Foundation/Foundation.h>
#import "Stem.h"
#interface Player : NSObject {
Player *player;
}
#property(nonatomic, retain) Stem *stem;
#property(nonatomic, retain) Player *player;
-(void) playAudio;
#end
This is where things go wrong, my NSLog statement tells me that value is 0, even though I can see that it's (e.g.) 14 in stem. The compiler gives no errors either.
//Part (vi)
// Player.m
#import "Player.h"
#implementation Player
#synthesize player;
#synthesize stem;
-(void)playAudio {
int value = stem.value;
NSLog(#"value is:%i", value );
}
#end
This is my first proper go at an object-orientated project so I'm learning on the job, any suggestions as to why I can't access stem.value in my Player class?
My ideas on how the various objects in such a program interact with one another (& the correct syntax) are still hazy so please forgive me for crazy n00b errors in my code :)
where are you declaring stem within player? if you are declaring it within the player.h then you will need the import of stem.h within the player.h and not player.m.
edit: yeah its still undeclared because you have stem declared in the view controller not the player. hmm seems to be afew things out of whack here. it really depends on how your code will actually work
#import Stem.h
#interface Player : NSObject {
NSMutableArray *player1;
}
#property(nonatomic,retain) NSMutableArray *player1;
#property(nonatomic,retain) Stem *stem;
-(void) playAudio;
#end
#
import "Player.h"
#implementation Player
#synthesize player1, stem = _stem;
-(void)playAudio {
NSLog(#"play audio called");
NSLog(#"index[0] is: %i", _stem.index[0]);//stem.index[0] will be a problem here as its not a c array
}
#end
and then in ur controller
player.stem = stem;
and im not sure why ur creating a stem pointer within the stem class.
#interface Stem : NSObject {
int *index;
int numberOfStems;
}
#property(nonatomic,readwrite) int *index;
and if its an array of stems you want then create that in the controller
edit : after you have the lines
player = [[Player alloc] init];
[player playAudio];
add
player.stem = stem;
you have to assign the pointer within player to the stem that you created in the view controller
The best way is to create a method in the Stem class like:
value = [stem valueAtIndex:i];
That way there is less coupling and the way the values are held in the Stem class is not exposed and can be changed later if necessary without preaching the access calls.