How to use a C array as instance variable? - objective-c

For example I want to store this in an ivar:
CGFloat color[4] = {red, green, blue, 1.0f};
so would I put this in my header?
CGFloat color[];
How would I assign values to that guy later? I mean I can't change it, right?

Instance variables are zeroed out on allocation so you can't use initialisers with them.
You need something like this:
// MyObject.h
#interface MyObject
{
CGFloat color[4];
}
#end
// MyObject.m
#implementation MyObject
-(id) init
{
self = [super init];
if (self != nil)
{
color[0] = red;
color[1] = green;
color[2] = blue;
color[3] = alpha;
}
return self;
}

You'd need to put the size in so that enough space is reserved.
CGFloat color[4];
Or use a pointer to the array, but that's more work and hardly superior for representing something as well-known as a color.

You are better off using a NSColor object if you can.
However, to your original question one of my first questions is where do you want to create this array. When you say put it in a header do you mean as a member of a class or as a global array, you certainly can do both however there are some serious gotchas with putting globals in headers. If you need that follow up and I can explain it better.
If it is in a class then you can just declare it like any other member field. If you say
CGFloat color[4];
then the space for the array is allocated in your object itself. You can also just use a
CGFloat *color;
or its moral equivalent to refer to an array that is stored outside of the object. You do need to manage that storage appropriately however.
This matters in the case you hinted at where you use a constant array object and cannot later change it. That can happen but is rare, since it cannot happen with the first approach, you don't see it in the wild very often.
There is a whole dissertation on the corner cases in here, I am sure it is not helping to go into it. Just use CGFloat color[4] in your object and it won't matter, by the time you see things they will be mutable and you can just use them the way you expect.

Related

Accessing a property of a node

I currently have a SpriteKit game with the objective of shooting down enemies. I've implemented collision detection for it, and it works just fine. But I need to implement health for enemies. Enemies are constantly generated and keep moving, so you never know what node that should bebeSo I tried to declare my custom class node in didBeginContact method, then assigning it to bodyA, then changing it's health value, but this seems useless since I just create a new node (same shows the NSLog). I tried typecasting the declaration, but still with no luck. Did some research on this topic, but didn't find anything that suits me. Currently I can't provide source code for what I did, but I hope what I have requested is possible to explain. Please push me in the right direction.
Every SKSpriteNode has a userData NSMutableDictionary which can be used to store data (objects).
You first have initialize the dictionary like this:
myNode.userData = [NSMutableDictionary dictionary];
Then you can assign data to it like this:
float myHealth = 100.0;
NSString *myX = [NSString stringWithFormat:#"%f",myHealth];
[myNode.userData setValue:myX forKey:#"health"];
To read data you do this:
float myHealth = [[myNode.userData objectForKey:#"health"] floatValue];
I used float in my example but you can use whatever you want. Just remember that you cannot store primitives like float, int, long, etc... directly. Those need to be converted to NSNumber, NSString and so on.
That being said, Stephen J is right with his suggestion. You should subclass SKSpriteNode for your enemies and have health as a class property. Subclassing is much easier to work with in the long run and gives you greater flexibility compared to using the userData.
To illustrate some Object oriented concepts Stephen J and sangony are referring to, I have added some code for you.
Subclassing SKNode will define a new object class which inherits all functionality from SKNode. The main advantage here is that you can implement custom properties (such as health) and custom logic (such as lowering that health).
#interface EnemyNode : SKSpriteNode
- (void)getHit;
- (BOOL)isDead;
#property (nonatomic) CGFloat health;
#end
#implementation EnemyNode
- (instancetype)initWithColor:(UIColor *)color size:(CGSize)size {
self = [super initWithColor:color size:size];
if (self) {
self.health = 100.f;
}
}
- (void)getHit {
self.health -= 25.f;
}
- (BOOL)isDead {
return self.health <= 0;
}
#end
In your scene, you would use it as such:
EnemyNode *newEnemy = [[EnemyNode alloc] initWithColor:[UIColor blueColor] size:CGSizeMake(50,50)];
[self addChild:newEnemy];
...
[newEnemy getHit];
if ([newEnemy isDead]) {
[newEnemy removeFromParent];
}
For further illustration, you could take a look at my answer to a similar question.

How to switch two objects in objective-c

I am trying to find if collision occurs between two rectangles in objective-c. I thought one way to accomplish this would be detect the rectangle that is closest to 0,0 point then do rest of the work.
I wrote a function that takes two rectangle objects as parameters and does the math to calculate area, distance to origin etc....
So lets say rect1 is at (100,200) and rect1's width is 100 height 200, rect2 is at 150,150 and rect2's width is 100 height 200 this is calculated by function well enough.
If I switch rec1 and rect2 properties, so rect1 will be at 150,150 while rect2 will be at 100,200. And call following function
-(Rectangle*)intersect:(Rectangle*)rectA:(Rectangle*)rectB{
//check closest rectangle to 0,0 and switch rectangles
if (rectA.origin.x>rectB.origin.x) {
Rectangle *temporary = [[Rectangle alloc] init];
temporary=rectA;
rectA=rectB;
rectB=temporary;
[temporary release];
}
float rectAX = rectA.origin.x;
float rectAY = rectA.origin.y;
float rectBX = rectB.origin.x;
float rectBY = rectB.origin.y;
When I enable guard malloc and zombies I get following error:
-[Rectangle origin]: message sent to deallocated instance 0x100acffd0
As soon as rectA.origin.x; is called I get the error.
So Howcome rectA or rectB is deallocated? What is the correct way to switch two objects that has bunch of properties ?
There is a built in function for comparing CGRects CGRectIntersectsRect(rectA, rectB) that you can use to check your rectangle's frames :)
As far as your code for switching you have created a third object by allocing temporary. Then you set the temporary pointer at rectA and then you release rectA at the end since its pointing to temporary. Leaving the newly created object as a leak and then sending messages to the released rectA.
You don't really want to swap object pointers like that if you can help it in my experience. But if you absolutely have to and understand what's going on you could do it like this:
// Create copies of your objects
Rectangle *rectACopy = [rectA copy];
Rectangle *rectBCopy = [rectB copy];
// release the originals.
[rectA release];
[rectB release];
// Set your copies to the original pointers.
rectA = rectBCopy;
rectB = rectACopy;
NSCopying Protocol
First you need to implement the protocol.
#interface Rectangle : NSObject <NSCopying>
Then you need to create the new method. This will create a new object but with all the same values.
- (id)copyWithZone:(NSZone *)zone
{
id copy = [[[self class] alloc] init];
if (copy) {
// Copy NSObject based properties like UIViews, NSArrays, Subclassed objects.
[copy setObjectProperty:[self.objectProperty copy]];
// Set primitives like ints, CGRects, Bools.
[copy setPrimitiveProperty:self.primitiveProperty];
}
return copy;
}
You don't need to allocate a new object instance for temporary (and therefore you don't need to release it either). You are just taking your 2 existing pointers and switching them around. You're correct to use a 3rd variable (temporary) but you don't need to allocate any new space because you're not moving anything in memory, just swapping which variables point to the existing objects.
-(Rectangle*)intersect:(Rectangle*)rectA:(Rectangle*)rectB{
//check closest rectangle to 0,0 and switch rectangles
if (rectA.origin.x>rectB.origin.x) {
//Rectangle *temporary = [[Rectangle alloc] init]; // here you don't need to allocate as you are not using this object
// So use
Rectangle *temporary=rectA;
rectA=rectB;
rectB=temporary;
//[temporary release]; //you don't need this. Here you were releasing rectA not the temp rect that you allocated just below if, as you assign rectA to temporary
}
float rectAX = rectA.origin.x;
float rectAY = rectA.origin.y;
float rectBX = rectB.origin.x;
float rectBY = rectB.origin.y;

converting dot syntax to bracket syntax on a struct

I have a property of CGSize:
#property (nonatomic) CGSize descriptionSize;
'
#synthesize descriptionSize = _descriptionSize;
I can access the height through the dot syntax:
self.descriptionSize.height = 35;
but how does this work with the bracket syntax?
[self setDescriptionSize:???];
Looked stupid simple to me, but I can't get the clue. Thanks in advance!
This is one of the pitfalls of dot notation for properties: Those two dots in self.descriptionSize.height look the same but mean very different things. The first is a property accessor which maps to a "get descriptionSize" method, but the second is an old-school struct reference. The first dot returns a CGSize scalar, NOT a pointer to the size value in the object. When the second dot sets the height in that returned CGSize, it's setting a value on the stack instead of changing the value in the object. This is how you have to do it:
CGSize size = self.descriptionSize;
size.height = 35;
self.descriptionSize = size;
…or the equivalent without properties dot notation:
CGSize size = [self descriptionSize];
size.height = 35; // we still use the dot here: size is a struct not an object
[self setDescriptionSize:size];
The implementation of descriptionSize will return a copy of the CGSize struct, so you can't work directly with that and hope it will work. What you need to do is get the whole of the CGSize struct, modify it, and then pass it back in:
CGSize size = [self descriptionSize];
size.height = 35;
[self setDescriptionSize:size];
However given you are working on a property of self and the property isn't an object, which requires memory management, the most efficient way of modifying the size is:
_descriptionSize.height = 35;
However you'd use the former getter/setter approach if:
The object was not self.
You had manually written the setter method to do something as a side-effect of changing the size (for example invalidating bits of the view in order to automatically update the view).
Dot syntax can mean two different things: Either a struct reference (CGSize is a C struct), or an objective-C message send.
Theoretically, if you have a method like - (void)doSomething;, you could call it like this: myObject.doSomething; //bad style. Don't do this. Dot syntax is not meant for calling methods that actually do stuff, other than getting or setting values (although nothing in the language or the IDE is going to stop you).
Synthesizing properties creates accessor methods: - (myType)myProperty and - (void)setMyProperty:(myType)newValue. Here, dot syntax lets you access the getter in the ordinary way (because the getter is an ordinary Objective-C method), and has a special case for the setter: myObject.myProperty = newValue gets translated to [myObject setMyProperty:newValue].
This means you can switch between dot syntax and Objective-C style message sending syntax for properties (and technically for all other parameter-less Objective-C method sends), but you must use dot syntax to access struct members. Structs are not objects, and they know now methods.

Constant NSDictionary/NSArray for class methods

I am trying to code a global lookup table of sorts.
I have game data that is stored in character/string format in a plist, but which needs to be in integer/id format when it is loaded.
For instance, in the level data file, a "p" means player. In the game code a player is represented as the integer 1. This let's me do some bitwise operations, etc. I am simplifying greatly here, but trying to get the point across. Also, there is a conversion to coordinates for the sprite on a sprite sheet.
Right now this string->integer, integer->string, integer->coordinate, etc. conversion is taking place in several places in code using a case statement. This stinks, of course, and I would rather do it with a dictionary lookup.
I created a class called levelInfo, and want to define the dictionary for this conversion, and then class methods to call when I need to do a conversion, or otherwise deal with level data.
NSString *levelObjects = #"empty,player,object,thing,doohickey";
int levelIDs[] = [0,1,2,4,8];
// etc etc
#implementation LevelInfo
+(int) crateIDfromChar: (char) crateChar {
int idx = [[crateTypes componentsSeparatedByString:#","] indexOfObject: crateChar];
return levelIDs[idx];
}
+(NSString *) crateStringFromID: (int) crateID {
return [[crateTypes componentsSeparatedByString:#","] objectAtIndex: crateID];
}
#end
Is there a better way to do this? It feels wrong to basically build these temporary arrays, or dictionaries, or whatever for each call to do this translation. And I don't know of a way to declare a constant NSArray or NSDictionary.
Please, tell me a better way....
If you want an array to be available to all the code in your class, just declare it outside the #implementation context, and then initialize it in your class's +initialize method.
NSArray *levelObjects;
#implementation LevelInfo
+ (void) initialize
{
if (!levelObjects)
levelObjects = [[NSArray alloc]
initWithObjects:#"empty",#"player",#"object",#"thing",#"doohickey",nil];
}
// now any other code in this file can use "levelObjects"
#end
Declare it static so it only needs to be created once.

self in Objective-C

is self not completely interchangeable with this in C++?
It seems to work with message passing ([ self sayHi ] would work within any method there).
I don't quite understand why I can't use self to access private members of an object (in the example below, I show I can't use self.width)
#import <Foundation/Foundation.h>
// Write an Objective-C class
#interface Rectangle : NSObject
{
int width ;
}
-(int)getWidth;
-(void)setWidth:(int)w;
-(void)sayHi;
-(void)sayHi:(NSString*)msg ;
#end
#implementation Rectangle
-(int)getWidth
{
// <b>return self.width ; // ILLEGAL, but why?</b>
// why can't I return self.width here?
// why does it think that's a "method"?
return width ;
}
-(void)setWidth:(int)w
{
// <b>self.width = w ; // ILLEGAL</b>
// again here, I CAN'T do self.width = w ;
width = w ;
}
-(void)sayHi
{
puts("hi");
}
-(void)sayHi:(NSString*)msg
{
printf( "Hi, and %s\n", [ msg UTF8String ] ) ;
}
#end
int main (int argc, const char * argv[])
{
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
Rectangle* r = [ Rectangle alloc ] ;
[ r sayHi ] ;
[ r setWidth:5 ] ;
printf( "width is %d\n", [ r getWidth ] ) ;
[pool drain];
return 0;
}
The other answers are almost correct, but not quite.
In Objective-C, no object [save for Blocks, but that is a very very special case] are ever on the stack. Thus, self.width doesn't make sense.
However, self->width does work. Since self is a reference to what is effectively a structure allocated on the heap, using the -> operator to get at the member variables makes sense.
But, in the context of Objective-C, it generally doesn't make sense, either. That is, Objective-C generally assumes a philosophy of preserving encapsulation. That is, you don't generally reach into an object and muck with the instance variables -- the internal state -- directly. Instead, you use the accessors to get/set the state. By doing so, the object (and subclasses) can customize getter/setter behavior, as needed. (This includes such mechanisms as Key-Value Observing and Key-Value Coding).
That self.width happens to equate to [self width] or [self setWidth: ...something...] is fallout from the above. That is, the . operator for accessing members of Objective-C class instances was not otherwise used and could be overloaded as a short hand for property access.
However, there is little difference between property access and invoke the getter/setter method. Thus, dot notation is synonymous with method invocation.
Within the context of your code, instance variables are transparently accessible within your classes implementation and without prefix.
Thus, you would use width = 5.0; instead of self.width = 5.0;, typically. Of course, the latter does equate to a method call with Objective-C 2.0 for reasons stated above.
You can't use self.width because it's not a property. self.width = w is shorthand for [self setWidth:w]; which was introduced in Objective-C 2.0. Try adding #property int width; above your method prototypes in the interface file, and at the top of your implementation file under the #implementation line, add #synthesize width;. That should allow you to use self.width, but it would no longer be a private variable.
You could also use #property (readonly) int width; to only generate a 'getter' method for width, but I doubt that's what you want. For more options you can pass to #property, check this documentation page.
Also, like Cliff said, getVar isn't convention in Objective-C. Instead, you just use the name of the variable you want to expose. The get prefix is usually used for when you're returning some form of raw data, as far as I know.
self.width is shorthand for [self width] and since you have not defined a width method it will be illegal. The getters in ObjC do not start with "get" by convention as they would in other languages like Java. Also I've heard from other experts (though I don't understand why) that it's not a good idea to use the property syntax from within the object that owns the proerty. From what I heard it causes some kind of a gotcha with Key Value Coding. In your example if you want to define a custom getter/setter then just reference the value directly without the self qualifier. It probably makes sense to use the getter/setter or dot notation everywhere else for good encapsulation.
self in Objective-C, like this in C++, is a pointer to the current object. So to access a field through self, you would do self->width (just as you would do this->width in C++)