Singleton function not retaining value - iphone

I'll preface this question by saying that I am a total noob when it comes to Objective-C. So please, be patient with my question. :)
So here is my issue. I am basically allowing the user to 'rub out' an image by using alpha blending and such, and then converting the created texture to a CCSprite. I am then able to store the CCSprite in a function within my singleton class. Like so:
erasedTextureSprite = [CCSprite spriteWithTexture:darknessLayer.sprite.texture];
[[MySingleton sharedMySingleton] setRevealTexture:erasedTextureSprite];
Here is the setRevealTexture & getRevealTexture function as well as the revealTexture variable initialisation in my MySingleton.h file:
#interface MySingleton : NSObject
{
CCSprite *revealTexture;
}
...
-(void) setRevealTexture: (CCSprite *) texture;
-(CCSprite *) getRevealTexture;
And here are both functions in my MySingleton.m file:
-(void) setRevealTexture: (CCSprite *) texture
{
NSLog(#"set reveal texture.");
revealTexture = texture;
NSLog(#"%f", [revealTexture boundingBox].size.width);
}
-(CCSprite *) getRevealTexture
{
NSLog(#"got reveal texture.");
NSLog(#"%f", revealTexture.contentSize.width);
return revealTexture;
}
If I set the reveal texture, and then get it right away, it seems to return the sprite correctly. However, if I set the texture and then transition to another scene, it seems to lose it's value, and throws me an error when I try and call the getRevealTexture function.
Question: Why is my function not retaining it's value when I transition between scenes?
If any more clarification is needed please let me know!

Practically there is no point in using your own setter and getter if your not doing anything fancy.
What you are doing is using an iVar which should have been a strong property.
you could achieve the same by doing:
#property (nonatomic, strong) CCSprite *revealTexture;
in your header file.
You would then get the following 2 functions by default:
[[MySingleton sharedMySingleton] revealTexture];
[[MySingleton sharedMySingleton] setRevealTexture:texture];
My next point of failure that I would presume if this doesn't work is that your singleton function is not working properly and your actually getting a new instance each time.
You can easily find this out by doing in the debugger:
po [MySingleton sharedMySingleton]
And seeing the instance that is returned each time.
example for a basic singleton code:
static MySingleton *__sharedMySingleton = nil;
+ (id)sharedMySingleton {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
__sharedMySingleton = [MySingleton new]; // or a specific alloc init function
});
return __sharedMySingleton;
}
Due to the request - here is a short image to explain how to enter debugger commands in xcode 5:

Related

Call a method from another class when shake is detected

HERE IS THE CODE: http://min.us/mWdMO0n14
I'm a Obj C newbie, so I've searched quite a bit, but haven't found anything that can solve my problem.
I have CalculatorViewController.h and .m and then CalculatorBrain.h and.m (Stanford Lectures)
in CalculatorBrain.m, I have the following method, with all of the variables defined as private in the CalculatorBrain header.
- (void)clearEverythingOnShakeGesture{
operand = 0;
waitingOperation = #"";
waitingOperand = 0;
}
Then in CalculatorBrain.m , I have everything set up to detect shakes, as follows. I've included some of the code above the shake detection just so you have a general idea.
#interface CalculatorViewController()
#property(nonatomic, retain) CalculatorBrain *brain;
#end
#implementation CalculatorViewController
#synthesize brain;
- (CalculatorBrain *)brain {
if (!brain) {
brain = [[CalculatorBrain alloc] init];
}
return brain;
}
-(BOOL)canBecomeFirstResponder{
return YES;
}
-(void)viewDidAppear: (BOOL) animated{
[super viewDidAppear:animated];
[self becomeFirstResponder];
}
- (void)motionBegan:(UIEventSubtype)motion withEvent:(UIEvent *)event {
if (event.subtype == UIEventSubtypeMotionShake)
{
NSLog(#"SHAKE IT!");
[brain clearEverythingOnShakeGesture]; //********** not sure how to call this.
}
}
I'm not sure how to call [brain clearEverythingOnShakeGesture]; , because I get the error "Class method +clearEverythingOnShakeGesture not found, defaults to return type id". However, if I make it a class method, the variables inside are instance variables, which provides another error. Any help greatly appreciated.
The project's AppDelegate posted in the comment above is building the calculator view controller from a nib, then releasing it immediately. The app functions partially, but the UILabel property to be cleared on the shake gesture is nulled at that point.
Also, it's a good practice to declare private properties in the private category, synthesize them with _underscore aliases, and refer to them as self.property outside of synthesized methods.
Are you #import-ing the CalculatorBrain.h? Also, you're using a nice lazy initialization pattern by building the CalculatorBrain in the getter, but you're not calling the getter in the motionBegan: method. Try [self.brain clearEverything ...] to get the brain instance.
I don't see anything in the code that would make the compiler think you have a class method. So that's mysterious. Please double check about the header import. You are correct that the clearEverything... should be an instance method.

Initializing a static singleton object with NSCoder

I'm working on an iPhone app and facing some troubles with my shared singleton class.
I'm using a shared singleton to store two variables
int gameRuns and int totalScore
'gamRuns' just increments every time the user loads the app, and 'totalScore' is obvious :D
the issue is as follows, I load the singleton and init using my own method when the app loads using this code:
+ (SingletonLevelState*)sharedLevelStateInstance {
static SingletonLevelState *sharedLevelStateInstance;
#synchronized(self) {
if(!sharedLevelStateInstance) {
//Init a singleton
sharedLevelStateInstance = [[SingletonLevelState alloc] init];
sharedLevelStateInstance->gameRuns = 1;
sharedLevelStateInstance->totalScore = 0;
}
}
return sharedLevelStateInstance;
}
This is working great as I can reference this class from any other class and always get a pointer to the same object, so this works fine from other objects:
sharedLevelState = [SingletonLevelState sharedLevelStateInstance];
sharedLevelStateInstance.gameRuns++;
Now I added the NSCoder protocol, and added the two methods initWithCoder and encodeWithCoder as follows :
- (void) encodeWithCoder: (NSCoder *)coder
{
//encode level data
[coder encodeInt:self->gameRuns forKey:#"gameRuns"];
[coder encodeInt:self->totalScore forKey:#"totalScore"];
}
- (id) initWithCoder: (NSCoder *) coder
{
if(self = [super init]){
self->gameRuns = [coder decodeIntForKey:#"gameRuns"];
self->totalScore = [coder decodeIntForKey:#"totalScore"];
}
return self;
}
Now when the app loads, I check to see if we already have a saved sate, if it exists, I just unarchive the class with that file, if not, I init that class using my custom method above, then set its defaults, encode it to file so we have a saved state, here's the code:
//Load Level state
sharedLevelStateInstance = [SingletonLevelState sharedLevelStateInstance];
//Check if file is saved
NSFileManager *fm = [[NSFileManager alloc] init];
NSString *gameStatePath = [NSString stringWithString:[self getSavePath]];
if([fm fileExistsAtPath:gameStatePath]){
[self loadState];
sharedLevelStateInstance.gameRuns = sharedLevelStateInstance.gameRuns+1;
NSLog(#"Loaded %d times", [sharedLevelStateInstance gameRuns]);
}
[fm release];
Now the last line in the if statement works perfectly, it increments every time I load the app as expected and I feel really happy lol.
However, the problem arises when I try to get a reference of the singleton in another class by doing the following:
sharedLevelStateInstance = [SingletonLevelState sharedLevelStateInstance];
NSLog(#"Played: %d times", sharedLevelStateInstance.gameRuns);
It always counts back to 1, I know what happens but I'm not sue what's the best way to solve it, when I initWithCoder the singleton, It's not returning a static object, it creates a new one, when I init my sharedLevelStateInstance, it calls my first custom method, initializing it to the defaults hardcoded.
So StackOverflow, can you please help me ?!
I just need to know what's the best way to get a reference to the same object without allocating a new one every time I initWithCoder !
Thanks :)
So, you code should probably look like this:
if(self = [[SingletonLevelState sharedLevelStateInstance] retain])
Which sets the variables of the singleton, and returns the singleton. Be sure to retain the singleton, so that when the NSCoder releases this instance, it doesn't fully deallocate your singleton.

Static UIImage in whole application

I want to have an static UIImage so I could access it from different classes. I've tried this way, but didn't worked:
Made Constans.h file with:
static UIImage *myImage;
And after that I import this header where it's needed. I thought that at this moment myImage was static and any changes made on this object would be visible everywhere. But it looks like every class is working on it's own myImage instance. Is there any way to have such static UIImage?
Edit:
Property in AppDelegate works fine. I have now static UIImage, but still I don't have effect I was expecting.
I have an UIImageView in ViewController. I load an image to my delegate.myImage and after I do:
delegate.myImage = [UIImage imageNamed:#"blah.png"];
myImageView.image = delegate.myImage;
Image is loaded, but after I want to change it in AppDelegate, but when I change myImage this way:
delegate.myImage = [UIImage imageNamed:#"blah2.png"];
nothing change in myImageView. It's like myImageView.image = delegate.myImage copied memory address of myImage so after if I change reference of myImage it's not affecting myImageView.image. I wanted to have an UIImage that after any changes it would also affect myImageView.
Is there other way than having an reference to myImageView in AppDelegate?
Rather than making an explicitly application-wide image, just use [UIImage imageNamed:]. This handles caching of the image for you! Whereever you need to use the image, just access it like so:
[UIImage imageNamed:#"imageName.png"]
Note: this will cause there to be a single copy of the image in memory. You can't unload it -- but newer versions of iOS may unload it behind the scenes upon low memory conditions.
See also the API docs for [UIImage imageNamed:].
Btw, imageNamed is often used for small images that get used multiple times -- e.g. table cell images -- but there's no reason to not use it on large images if you genuinely want a static app-wide image.
The keyword static makes a variable local to the compilation unit where it id defined. This means you can safely have the same symbol defined in multiple .c files; all those declarations will not collide and each file will have its own private symbol.
Put simply, if you really want to define a global variable that is accessed by any part of your program, you do not need the static keyword. In this case, though, the "trick" is declaring the variable in a header file (that you include everywhere the global should be visible) like this:
extern UIImage *myImage;
and then provide a definition for that variable in one single place (.c file) without the static keyword. The extern keyword tells the compiler that the definition for that symbol is not found inside of the current compilation unit (.c file), but in a different one.
Now, as many others have pointed out, you could better do that by means of a singleton, although it is usually recognized that using a singleton to mask a global variable is usually a way to mask a design problem.
That's a C problem (not specifically related to Objective-C or iOS)
The static keyword make the variable sticky inside its compilation unit.
When you #include (or #import in ObjC) a header, that's like if its content were copied & pasted into the file that includes it. As a reminder, ".h" files are not compiled (they are just included in ".m" files that themselves compile)
So that works exactly the same way as if you were typing the same lines of code you have in your .h in any file that #include it.
This explains why in each of your source files that #include "Constants.h" they each see a different instance of the myImage variable.
Instead you should:
Use the Singleton Pattern, that is specifically made for such cases
Or use the static keyword in an implementation file ("Constants.m") to make this variable sticky inside the compilation unit of this "Constants.m" file
I highly recommand to go with the Singleton Pattern for such cases anyway. More info on Singleton Pattern here in the Apple official DevPedia
You can create a #property (nonatomic, retain) UIImage *image; in your app delegate and in every class you want to use the image you can create AppDelegate *delegate=(AppDelegate *)[[UIApplication sharedApplication] delegate]; and then access to the UIImage from the delegate object like this :
[imageView setImage:[delegate image]];
Or you can use a class like this :
header file
#interface Data : NSObject
#property (nonatomic, strong) UIImage *image;
+ (Data *)sharedInstance;
+ (id)allocWithZone:(NSZone*)zone;
- (id)init;
- (id)copyWithZone:(NSZone *)zone;
#end
implementation file
#implementation Data
#synthesize image;
static Data *sharedInstance=nil;
+ (Data *)sharedInstance {
if (sharedInstance == nil) {
sharedInstance = [[super allocWithZone:NULL] init];
}
return sharedInstance;
}
+ (id)allocWithZone:(NSZone*)zone {
return [self sharedInstance];
}
- (id)init
{
self = [super init];
if (self) {
}
return self;
}
- (id)copyWithZone:(NSZone *)zone {
return self;
}
#end
Then, you have to import Data.h in every class you want and then use :
UIImageView *imageView=[[UIImageView alloc] init];
[imageView setImage:[[Data sharedInstance] image]];
This works great for me :)
Use the singleton pattern.
If your code is ARC follow this link http://lukeredpath.co.uk/blog/a-note-on-objective-c-singletons.html
In iPhone the AppDelegate class Acts a Static Class. so you can do the same thing which you have done in Constant.h in the YourAppDelegate Class. But dont use Static Keyword.
I am not very Sure but thinks it will work. :)
You can use UIImage category as example to get this picture.
In your .h file just add your static method.
#import <UIKit/UIKit.h>
#interface UIImage (StaticImage)
+(UIImage *)staticImage;
#end
And in your .m file do following steps:
#import "UIImage+StaticImage.h"
//This is your static image
static UIImage *myStaticImage;
#implementation UIImage (StaticImage)
+(void)initialize{
//Important to add this condition, because this method will be called for every
//child class of UIImage class
if (self == [UIImage class]){
myStaticImage = [[UIImage alloc] init];
}
}
+(UIImage *)staticImage{
//Just return your existing static image
return myStaticImage;
}
#end

CCSprite is not displaying on the iPhone

I am trying to make a sprite display on the screen in Cocos2d. But, I don't want to use a CCSprite directly. I have a class Unit which will have some additional properties that I will need later on in my game. The class declaration of Unit is as follows:
#interface Unit : CCSprite {
CCSprite *sprite;
}
-(void)init;
#property(nonatomic, retain) NSNumber *type;
#property(nonatomic, retain) CCSprite *sprite;
#end
And my init method for it looks like this:
-(void)init {
self.sprite = [CCSprite spriteWithFile:#"BasicUnit.png"];
self.sprite.position = ccp(50, 100);
}
Now what I need to do is apply it to the screen. So, I have another class called Playscene which is the scene where I want to display sprites and things. Here is what the init method (the method that should draw the sprites) looks like in Playscene:
-(id) init {
if( (self=[super init] )) {
self.isTouchEnabled = YES;
[army init];
[self addChild:army.sprite];
}
return self;
}
But, when I run this I get a ton of error data including: "terminate called after throwing an instance of 'NSException'" and probably of more importance: "Assertion failure in -[PlayScene addChild:]". I don't know how I can solve this. Any help would be appreciated.
Based on your snippets it is very difficult to know what goes wrong. That said I assume that army in your last snipped is of type Unit. But because that is inside the init() method it could be that it is nil because it is not created here like in army = [[Unit] alloc] initXXX];.
That said I am not sure what you want to accomplish with subclassing CCSprite in your Unit class because you are referencing CCSpirit and so there is not need to subclass it.
Finally your Assertion is probably because your army.spirit is either NIL or it is already added and the assertion inside Coco2d throws the exception (I am assuming that the last snippet is from a subclass of CCNode).
My suggestions:
Don't extend CCSpirit in Unit (not needed as far as I can see)
Don't have a method - (void) init but overwrite - (id) init
Make sure army is properly instantiated using [[Unit alloc] init] (see point above)
Using alloc you need to make sure that if it is assigned to a retaining property that you also release it to offset the alloc.
Hope that helps.

How to create Enemies class in cocos2d

I am using cocos2d for the iphone
I want to create a class for Enemies
see my code
#import <Foundation/Foundation.h>
#import "cocos2d.h"
#interface Enemies : CCSprite {
float imageHeight;
}
#property float imageHeight;
+(id) enemies;
#end
#implementation Enemies
#synthesize imageHeight;
+(id) enemies{
return [[[self alloc] initWithFile:#"enemy.png"] autorelease];
}
#end
I want the to set the imageHeight
float imageHeight = [enemy texture].contentSize.height;
so whenever I create an instance of the class Enemies I it should have imageHeight set properly?
Thanks
note: I am trying to improve this code
ahmed, keep the enemies method the same, and add this to your class:
-(id) init {
if (self = [super init]) {
float textureHeight = [enemy texture].contentSize.height;
[self setImageHeight:textureHeight];
}
return self;
}
This will set imageHeight for all new instances of the Enemies class.
Override initWithFile in Enemies class.
Then Inside it call, [super initWithFile passing the same Filename string]
After which you can set the imageHeight variable in the next line as the texture would have been loaded and height will be accessible.
Cocos2d automatically sets the height of some things based on the image itself. Look for the sprite's setHeight property, it should be easy to find in the docs.
However, your question looks like it could use rewording. Your "Enemy" should be data, not related to any display (sprites) whatsoever, unless you're going to make a really small app.
Check out Beginning XNA books for nice examples of how to abstract superclass enemy and players, if you can use C# and translate between iOS. They will work very much the same. (I wish I knew a good game programming book for iPhone, but all of the ones I open have flaws or bad design that only experienced programmers can get past.
Anywho, if you mix data and images, it usually means to redesign your code