I am creating a calculator for some cards game. In that game, I am creating a Singleton class to manager the game. It holds the scores, keeps track of where the game is etc...
Now after the app launches, I will ask the user to enter 4 players' names. After that, 4 player objects are instantiated according to their names. I already have an object called "Player", so 4 players will get instantiated with their name, and a score of 0 to start with.
Now I need to store those players in my singleton class. Therefore, I created 4 Player properties in the class. However my question is, under the init method in the Singleton class, in:
if ((self = [super init])) {
// set properties here
}
Where // set properties here is, what do I write? Do I have to do anything with the Players properties over there?
Thank you,
You don't need to do anything except return the shared instance. Usually the singleton's properties are set in whatever class your instantiating it from.
No, you aren't required to do anything with them, although I would probably set them to nil.
Maybe I'm wrong, but doesn't your AppDelegate already serve as a Singleton?
Related
I am currently new to objective c and have came across a problem while making a game I have a custom made object called battleEngine which is an instance variable in my helloWorld scene in cocos2d. That object has an object as an instance variable called plyController which is a PlayerController object. I want battleEngine to have a getter method that returns the plyController object and this code doesn't work:
-(PlayerController*)getPlayerController
{
return plyController;
}
Is there any reason you haven't just declared your player controller object as a property? You could just use the synthesised getter in that case to get the player controller.
Have a look at the documentation on properties.
Also, and I'm afraid I have to say this or they will take my Cocoa-programmer badge away from me, getPlayerController is not a good method name. Methods with get in them are conventionally used to return values in the parameters passed in by reference. The Cocoa Coding Guidelines tells us this, and much more.
I am trying to initialize the CMMotionManager so start updates and create a reference attitude matrix, and then when i click a button trough the storyboard, i display a different screen (which is in a viewcontroller) and i want to use the reference attitude matrix and other readings from the motion manager but if I do a simple check to see if its ready it says it isnt (even thought it was ready on the previous screen).
So I was researching a little bit and i came across some standford notes that say it is a global resource so that it is ok to either use delegates or classes, that got me thinking.
If i use a delegate then technically the owner of the resource is doing the action for me right? so it doesnt really mean it is global.
What about classes? i tried implementing a MotionManager Class but i still didnt get any readings on the second screen... and i just didnt initialize it again on the new screen because i dont want to have multiple instances runing at the same time.
To solve my problem i also suppose i could initialize it once in the main one, save the attitude, pass it to the next one in a segue transition and just re initialize the motion manager so i only have 1 instance (or close old one on screen will dissapear).
But i do not want this because the user might click right away on the screen and the motion manager does take a little bit of time to initialize (or thats what i noticed).
Thanks in advance for any help you can provide.
EDIT:
Ok i tried the delegate method and i still cant read from the device manager in the second window. What comes to mind is that MAYBE when I am going to the second window xcode is automaticaly releasing my instance of Motion manager.... (CMMotionManager).
Anyone knows how to check this?
I hope I understood you right. Then I suggest using a singleton design pattern encapsulating motion manager access in a specialised class. Some pseudo code:
MotionHandler.h
#interface MotionHandler {
CMMotionManager* motionManager;
+ (MotionHandler*) getInstance;
}
MotionHandler.c:
#interface MotionHandler {
static MotionHandler* instance;
+ (MotionHandler*) getInstance {
if (instance == nil) {
instance = [[self alloc] init];
}
return instance;
}
- (id)init {
if ((self = [super init])) {
motionManager = [[CMMotionManager alloc] init];
// initialise CMMotionManager
}
}
}
So there is one instance of MotionHandler only which manages access to CMMotionManager. You can accesss your CMMotionManager instance from everywhere with MotionHandler.getInstance.motionManager.
If you need access to CoreMotion from several classes, I recommend total encapsulation of CMMotionManager access. That means make it #private and provide methods like getDeviceMotion, setReferenceAttitude, ...
This helps to avoid complications like starting it twice or access to CMDeviceMotion before start and makes it more convenient to debug.
I have three classes, A, B and C. A is the main class.
When the user wants to see the list of all objects that were purchased, Class B is called from A and shows the list of objects in a core data entity.
Inside class B, the user can buy new objects (in-app purchase). When the user wants to buy another object, class C is called.
When class C is called, a new object is created on the core data entity using
anObject = [NSEntityDescription insertNewObjectForEntityForName:#"Objects" inManagedObjectContext:context];
this object is then assigned to a local reference on Class C, using something like
self.object = anObject;
this object variable was declared like this:
.h
MyObjects *object;
#property (nonatomic, retain) MyObjects *object;
and #synthesized on .m
MyObjects is a core data class representing the entity.
In theory, object will retain anything assigned to it, so the line self.object = anObject I typed previously will retain anObject reference on self.object, right?
The problem is that when I try to access self.object in the same class after buying the new object, I receive an error "CoreData could not fulfill a fault for XXX", where XXX is exactly self.object.
At no point in the code there's any object removal from the database. The only operation to the database I could identify was a saving operation done by another class moments before the crash. The save is done by something like
if (![self.managedObjectContext save:&error]) ...
Is there any relation? what may be causing that?
CoreData manages the lifetime of managed objects and you should not retain and release them. If you want to keep a reference to the object so that it can be retrieved later then you have to store the object's id (obtained using -[NSManagedObject objectID]). Then use that to retrieve the object later using -[NSManagedObjectContext objectWithID:].
Make sure you understand about CoreData faulting. Read the documentation.
I had a similar issue a few days ago (using NSFetchedResultsController) where I was placing my fetchedObjects into an array and gathering attributes to populate tables from the array objects. It seems that if the objects in the array are faulted, you cannot unfault it unless you are acting on the direct object. In my case, I solved the issue by taking the lines of code in question and calling [[_fetchedResultsController objectAtIndexPath:indexPath] someAttribute]. I would assume that doing something similar would fix your problem as well. It seems a bit tedious to need to fetch from the managedObjectContext to obtain a faulted value, but this was the only way I could personally get past the issue.
Core Data is responsible for managing the lifetime of managed objects in memory. It's really important to understand Managed Object Contexts - Read the documentation.
Apple also provides an entire troubleshooting section here, and it contains among other things the causes for your error. But it's really only useful if you understand how core data works.
Most likely error is that the object you are saving does not belong to the managed object context.
Say you use the same object on different threads and those different threads use different managed object context, then this will happen.
A few days ago, I started working with cocos2d. I really like the framework. I would like to create a game with cocos2d and have a probably simple question...
I am making a game with 4 characters, which all have similar characteristics, but have some different attributes like "type" and "points". I'd like to subclass the sprites into one class which handles all their logic, drawing, and animation.
My question though, is how do I call the sprite class with say, a "type" parameter of 1, 2, 3, or 4 and then have the class draw the correct sprite into my scene with all of it's individual logic?
Thanks!
You should have an Enemy class that contains properties of specific enemies and that are not type specific (like position, current health, a CCSprite instance?) and an EnemyType class that contains properties that are shared among all enemies of a specific type (max health, max speed, size, sprite filename). You should load your enemy types prior to loading the level, than instantiate each enemy using the appropriate type in the constructor.
For example if your enemy element in the level file looks like this
<enemy><type>spider</type>...more properties...</enemy>
The code (pseudo) would do something like
EnemyType *enemyType = nil;
if (typeElement.value == "spider")
{
enemyType = spiderType;
}
Enemy *newEnemy = [Enemy enemyWithType:enemyType];
Also the Enemy class should contain the CCSprite that represents it, not subclass it. An enemy is not a sprite, so unless I'm missing something, as i see it, an enemy should not inherit from a sprite. I'd read about when to contain and when to inherit.
EDIT:
Another nice post to read that seems very relevant and could communicate a few other things probably better than me.
Anyway, my intention was not to make you think you should just rethink your entire design. What i'm proposing is "better" MVC-wise, but it doesn't mean it's better for your game. If you spend all your time on "design correctness" you'll never get a game done, especially if you're just learning the cocos2d framework, i was actually making a learning project not too long ago and Steve McConnel himself would come over and slap me if he saw it.
If you're working on a game alone and it's a small project go ahead and subclass away if it's going to be more manageable to you, everything, including "design correctness" needs to be properly quantified (except maybe usage of "goto" statements :) ).
polymorphism in this way can be done a couple of different ways, some better than others.
1) you could try to just override the init or node method and set up your object there.
+(CCSprite *)node
{
MySprite * returnSprite = [super node];
returnSprite.hat = #"fedora";
returnSprite.hatImage = [CCSprite spriteWithImage:...];
}
2) use reflection (psuedocode)
-(void)drawingMethodHere
{
[self.hat drawAtPoint:somePoint];
}
then override -(CCNode *)hat to reflect the type.
you may have to do some combination of them, but plan a little before you start, you will end up saving a lot of time.
You should subclass CCNode instead of subclassing CCSprite.
I think your problem is quite easy. Just create a base class called Character, which has the common logic, properties etc etc. Then you create 4 other classes like, enemy, player and so on and subclass from Character base. Note the character base should be subclassing CCNode.
Now you override the logic to fit your needs in the specific class. Now you will be able to use polymorphism, which is good.
For your sprite I would say create an instance variable of the CCSprite type and then create methods to initialize with an image. Then you will just add that sprite as a child when initializing the object.
I have 2 entities I want to link with KVO, one a single statTracker class that keeps track of different stats and the other an achievement class that contains information about achievements. Ideally what I want to be able to do is set up KVO by having an instance of the achievement class observe a value on the statTracker class and also set up a threshold value at which the achievement instance should be "triggered"(triggering in this case would mean showing a UIAlertView and changing a property on the achievement class.)
I'd like to also set these relationships up on instantiation of the achievement class if possible
so kind of like this:
Achievement *achievement1 = (Achievement *)[NSEntityDescription insertNewObjectForEntityForName:#"Achievement" inManagedObjectContext:[[CoreDataSingleton sharedCoreDataSingleton] managedObjectContext]];
[achievement1 setAchievementName:#"2 time launcher"];
[achievement1 setAchievementDescription:#"So you've decided to come back for more eh? Here are some achievement points to get you going"];
[achievement1 setAchievementPoints:[NSNumber numberWithInt:300];
[achievement1 setObjectToObserve:#"statTrackerInstace"
propertyToObserve:#"timesLaunched"
valueOfPropertToSatisfyAchievement:2]
Anyone out there know how I would set this up? Is there some way I could do this by way of relationships that I'm not seeing?
Thanks,
Nick
NSManagedObjects are NSObjects, if you back them with classes you can add any methods that you'd like.
That said, you may want to create an achievement manager class that manages the relationships between the classes and executes any trigger responses.