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.
Related
I just started out programming in Objective C. This is very simple stuff but im wondering what im missing on my knowledge of properties, as far as I understand this should work but it gives me the error:
Property 'score' not found on object of type 'Player *'
I have a Player class and the code as follows below, each bolded is a separate file
Player.h has:
#import <Foundation/Foundation.h>
#interface Player : NSObject
#property int score;
#end
Player.m has:
#import "Player.h"
#implementation Player
- (id)init {
self = [super init];
if (self){
_score = 5000;
}
return self;
}
#end
main.m has
#import <Foundation/Foundation.h>
#import "Player.h"
int main(int argc, const char * argv[])
{
#autoreleasepool {
Player *firstPlayer = [[Player alloc] init];
NSLog(#"The default score is %i", [firstPlayer score]);
}
return 0;
}
Player.h is missing the following line which should go between the #import and #property lines:
#interface Player : NSObject
Where NSObject may be a different class, but needs to be whatever you intend to be subclassing.
Is it possible to extend an derived class from NSManagedObject? I'm asking this because I tried to do it. My entity looks like this:
So this means a class similar to the following code should be generated:
#import <Foundation/Foundation.h>
#interface Player : NSManagedObject
#property (nonatomic, copy) NSNumber* orderNumber;
#property (nonatomic, copy) NSString *name;
#end
.m file
#import "Player.h"
#implementation Player
#dynamic name, orderNumber;
#end
This two variables are saved to the SQLite database.
Now since I need some additional variables for the player I just added them to the class. It still worked.
#import "Player.h"
#implementation Player
#dynamic name, orderNumber;
- (id) init
{
self = [super init];
if (self != nil)
{
[self reset];
}
return self;
}
#synthesize isStillInGame = _isStillInGame;
- (void) reset
{
_isStillInGame = TRUE;
}
- (void) setOutOfGame
{
_isStillInGame = FALSE;
}
#end
But now when I change the isStillInGame bool, all instances of the Player Class are changed. Is this normal or do I have an error in my code?
A second question I can't answer is, why I can't access the object variables while debugging. When I try to watch an Player instance variable I just see this:
Is it possible to see more?
I have done the Collection View Programming Topics three times now. Step by step, but there is no way I am getting any content in the collection view.
The thing I have noted for the bindings of the NSText Labels when I bind them to representedObject. is that they get an exclamation mark.
I have tried to set model key paths, xcode identifier, and title to no avail.
I also get an extra view in addition to the collection view item.
I hope anybody has an idea.
I have asserted that the labels have fonts, and that the gridview has 0 rows and 1 column.
Here is AppDelegate.h
#import <Cocoa/Cocoa.h>
#interface AppDelegate : NSObject <NSApplicationDelegate>
#property NSMutableArray *personModelArray;
#property (assign) IBOutlet NSWindow *window;
// To see if personModelArray is populated.
- (IBAction) showElements:(id) sender ;
#end
Here is AppDelegate.m
//
// AppDelegate.m
// Occupations
#import "AppDelegate.h"
#import "PersonModel.h"
#implementation AppDelegate
#synthesize personModelArray;
- (void)awakeFromNib {
PersonModel * pm1 = [[PersonModel alloc] init];
pm1.name = #"John Appleseed";
pm1.occupation = #"Doctor";
PersonModel * pm2 = [[PersonModel alloc] init];
pm2.name = #"Jane Carson";
pm2.occupation = #"Teacher";
PersonModel * pm3 = [[PersonModel alloc] init];
pm3.name = #"Ben Alexander";
pm3.occupation = #"Student";
NSMutableArray * tempArray = [NSMutableArray arrayWithObjects:pm1, pm2, pm3, nil];
[self setPersonModelArray:tempArray];
/*
for (PersonModel *obj in personModelArray) {
NSLog(#"%# %#", obj.name, obj.occupation) ;
}
*/
// NSLog(#"Awoken from nib %#",personModelArray) ;
}
// Convenience: hooked up with a button to see that
// the contents of the array is still there!
-(void)showElements:(id) sender {
for (PersonModel *obj in personModelArray) {
NSLog(#"%# %#", obj.name, obj.occupation) ;
}
}
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
// Insert code here to initialize your application
}
-(void)insertObject:(PersonModel *)p inPersonModelArrayAtIndex:(NSUInteger)index {
[personModelArray insertObject:p atIndex:index];
}
-(void)removeObjectFromPersonModelArrayAtIndex:(NSUInteger)index {
[personModelArray removeObjectAtIndex:index];
}
-(void)setPersonModelArray:(NSMutableArray *)a {
personModelArray = a;
}
-(NSArray*)personModelArray {
return personModelArray;
}
#end
Here is PersonModel.h
//
// PersonModel.h
// Occupations
//
#import <Foundation/Foundation.h>
#interface PersonModel : NSObject {
NSString * name;
NSString * occupation;
}
#property NSString * name;
#property NSString * occupation;
#end
Here is PersonModel.m
//
// PersonModel.m
// Occupations
#import "PersonModel.h"
#implementation PersonModel
#synthesize name;
#synthesize occupation;
#end
The answer to my greatest blunder in 2013 was that I didn't completely understood how the control (NSContentsView) was supposed to be assembled.
I just stumbled into the tutorial from Cocoa Bindings Programming Topics, and just couldn't make it work. To my defense, first I fickled a little with the bindings, so I supsected the error to still be there somewhere, but nada. I had placed the controls I had bound into the contentsview, and not into the "gridview".
I am having trouble accessing an int property from another class. I know this question has been asked quite a few times however none of the solutions posted in previous questions seem to work. My knowledge in xcode is basic, and I am using this project to develop my skills.
The two classes I have are: HelloWorldLayer and ClassOne. Where ClassOne states the value of int. Both are Cocos2d CCLayer classes (probably not the best class to practice inter-class value access).
ClassOne.h
#interface ClassOne : CCLayer {
int ageClass;
}
#property (nonatomic, readwrite)int ageClass;
#end
ClassOne.m
#implementation ClassOne
#synthesize ageClass = _ageClass;
-(id)init{
if((self=[super init])){
_ageClass = 10;
}
return self;
}
#end
HelloWorldLayer.h
#import "ClassOne.h"
#interface HelloWorldLayer : CCLayer <...> {
ClassOne *agePointer;
}
#property (nonatomic,assign)ClassOne *agePointer;
+(CCScene*)scene;
#end
HelloWorldLayer.m
#import "HelloWorldLayer.h"
#import "AppDelegate.h"
#import "ClassOne.h"
#implementation HelloWorldLayer
#synthesize agePointer = _agePointer;
+(CCScene*)scene...
-(id)init{
if((self=[super init])){
_agePointer.ageClass = self;
NSLog(#"ClassOne int = %#",_agePointer);
}
return self;
}
...
#end
Output Result:
"ClassOne int = (null)"
or "0" if i use "%d" token and "int = x", where the line "int x =_agePointer.ageClass;"
is used.
The result I am after is for the HelloWorldLayer NSLog to display "10", the int value defined in ClassOne.
Any wisdom and corrections on my use of language is greatly appreciated.
Ok Try This:
-(id)init
{
if((self=[super init])){
_agePointer = [[ClassOne alloc] init];
NSLog(#"ClassOne int = %d",_agePointer.ageClass);
}
return self;
}
First of all, when outputting int, always use %d instead of %# in your NSLog.
Second of all, if you are expecting to output 10, you should've instantiated the class first in your HelloWorldLayer.m:
-(id)init{
if (self = [super init]) {
_agePointer = [[ClassOne alloc] init];
NSLog(#"ClassOne int = %#",_agePointer);
}
return self;
}
this is a follow-up question to my last one here: iOS: Initialise object at start of application for all controllers to use .
I have set my application up as follows (ignore the DB Prefix):
DBFactoryClass // Built a DataManaging Object for later use in the app
DBDataModel // Is created by the factory, holds all data & access methods
DBViewControllerA // Will show some of the data that DBDataModel holds
moreViewControllers that will need access to the same DBDataModel Object
i will go step by step through the application, and will then in the end post the error message i get when building.
AppDelegate.h
#import "DBFactoryClass.h"
AppDelegate.m
- (BOOL)...didFinishLaunching...
{
DBFactoryClass *FACTORY = [[DBFactoryClass alloc ]init ];
return YES;
}
DBFactoryClass.h
#import <Foundation/Foundation.h>
#import "DBDataModel.h"
#interface DBFactoryClass : NSObject
#property (strong) DBDataModel *DATAMODEL;
#end
DBFactoryClass.m
#import "DBFactoryClass.h"
#implementation DBFactoryClass
#synthesize DATAMODEL;
-(id)init{
self = [super init];
[self setDATAMODEL:[[DBDataModel alloc]init ]];
return self;
}
#end
ViewControllerA.h
#import <UIKit/UIKit.h>
#import "DBDataModel.h"
#class DBDataModel;
#interface todayViewController : UIViewController
#property (strong)DBDataModel *DATAMODEL;
#property (weak, nonatomic) IBOutlet UILabel *testLabel;
#end
ViewControllerA.m
#import "todayViewController.h"
#implementation todayViewController
#synthesize testLabel;
#synthesize DATAMODEL;
- (void)viewDidLoad
{
todaySpentLabel.text = [[DATAMODEL test]stringValue];
}
#end
DBDataModel.h
#import <Foundation/Foundation.h>
#interface DBDataModel : NSObject
#property (nonatomic, retain) NSNumber* test;
#end
DBDataModel.m
#import "DBDataModel.h"
#implementation DBDataModel
#synthesize test;
-(id)init{
test = [[NSNumber alloc]initWithInt:4];
return self;
}
#end
when i build it, i get the following error: EXC_BAD_ACCESS in this line:
#synthesize DATAMODEL;
of DBFactoryClass.m
What #synthesize does is to automatically generate implementations of the accessors for a property. EXC_BAD_ACCESS there means that you're accessing garbage when one of the accessors is executed.
That's probably happening here:
[self setDATAMODEL:[[DBDataModel alloc]init ]];
Make sure that DBDataModel's implementation of init actually returns a legitimate object.
As far as I can tell, your DBFactoryClass class is never stored anywhere, and therefore released right after the allocation if you use ARC (Since you use the strong keyword I assumed you do).
- (BOOL)...didFinishLaunching... {
DBFactoryClass *FACTORY = [[DBFactoryClass alloc ]init ];
// If you use ARC this might be released right afterwards
return YES;
}
If you want the factory to be a singleton, use something like this
+ (id)sharedInstance {
static dispatch_once_t once;
static MyFoo *instance;
dispatch_once(&once, ^{
instance = [[self alloc] init];
});
return instance;
}