I have a android game ready to launch and I'm currently working on porting it to iOS.
I'm fairly new to Objective C and C in general and I'm not sure exactly how #properties and #synthesize and #imports work.
My game shares a method file called gMain. This file includes the shared methods between objects. I have an object called Fish and in that object contains a method which requires the x,y value of another object called Fish2.
I'm unsure of how to access the variables when both Fish and Fish2 share the same variable names, int x, int y.
will this work?
//Fish.h
#interface Fish
{
int x, y;
}
#property int x, y;
-(void)blah;
#end
//Fish2.h
#interface Fish2
{
int x, y;
}
#property int x, y;
#end
//Fish.m
#import Fish.h
#implementation Fish
#synthesize x, y;
-(void)blah
{
x = Fish2.x;
y = Fish2.y;
}
#end
//Fish2.m
#import Fish2.h
#implementation Fish2
#synthesize x, y;
#end
does this synthesize both xs and ys from the 2 objects?
No.
Your code won't compile. You've left out all the #interface, #implementation, and #end directives that tell the compiler what class you're talking about. A #synthesize directive will always be included between #implementation *classname* and #end, and it will only synthesize a property for the indicated class.
If you correct your code, the effect of the #synthesize should be obvious.
//Fish.h
#interface Fish
{
int x, y;
}
#property int x, y;
#end
//Fish.m
#import Fish.h
#import Fish2.h // it's not clear why you'd need this
#implementation Fish
#synthesize x, y; // creates accessors for properties x and y of class Fish
#end
I'm not sure if you are wanting to deal with a single class, with two instances, two separate classes. I'll try to give an example of each and try to explain what the code is doing.
Single Class, Two Instances
Fish.h
#interface Fish : NSObject
#property (nonatomic, assign) int x;
#property (nonatomic, assign) int y;
- (void) someMethod;
#end
So you are defining a new object called FishA and the object has 2 public properties, x and y. The 2 items in parenthisis nonatomic and assign tell the compiler extra information about the properties. Bassicaly nonatomic means not to worry about thread safty and assign means that the property is a base type, not an object.
Fish.m
#import "Fish.h"
#implementation Fish
#synthesize x = _x;
#synthesize y = _y;
- (id) init {
self = [super init];
if (self) {
// Initilize default values
// Only use the _x and _y in init
// no other place
_x = 0;
_y = 0;
}
return self;
}
- (void) someMethod {
// Set the values
self.x = 10;
self.y = 10;
// Access the values
NSLog(#"X: %d", self.x)
NSLog(#"Y: %d", self.y)
}
So the #synthesize statments will create two methods for you, one to set the value and one to get the value. In the statements above the x tells the compiler to create the methods for the x property, the _x is the name of the interal storage variable for the property. It is much better that the property and the internal storage are separatly named, it makes the code cleaner and easier to understand whats going on.
In th init method we directly set the internal variable with the initial values. The init method is generally the only place you want to access the internal variables.
Use
#import "Fish.h"
- (void) example {
Fish *fishA = [[Fish alloc] init];
Fish *fishB = [[Fish alloc] init];
fishA.x = 10;
fishB.x = 20;
[fishA someMethod];
[fishB someMethod];
}
Separate Classes
FishA.h
#interface FishA : NSObject
#property (nonatomic, assign) int x;
#property (nonatomic, assign) int y;
#property (nonatomic, assign) int size;
- (void) someMethod;
#end
FishA.m
#import "FishA.h"
#implementation FishA
#synthesize x = _x;
#synthesize y = _y;
#synthesize size = _size;
- (id) init {
self = [super init];
if (self) {
// Initilize default values
// Only use the _x and _y in init
// no other place
_x = 0;
_y = 0;
_size = 10;
}
return self;
}
- (void) someMethod {
// Set the values
self.x = 10;
self.y = 10;
// Access the values
NSLog(#"X: %d", self.x)
NSLog(#"Y: %d", self.y)
}
FishB.h
#interface FishB : NSObject
#property (nonatomic, assign) int x;
#property (nonatomic, assign) int y;
#property (nonatomic, strong) NSColor *color;
- (void) someMethod;
#end
The color propery looks a little different. Because color is an object and not a base type we need to tell the compiler how we want to handle it. The strong tells the compiler to hold on to this object untill we are done with it. The other option would be weak and that tells the compiler not to hold on to the object. Generally speaking, with objectes, use strong.
FishB.m
#import "FishB.h"
#implementation FishB
#synthesize x = _x;
#synthesize y = _y;
#synthesize color = _color;
- (id) init {
self = [super init];
if (self) {
// Initilize default values
// Only use the _x and _y in init
// no other place
_x = 0;
_y = 0;
_color = [NSColor blueColor];
}
return self;
}
- (void) someMethod {
// Set the values
self.x = 10;
self.y = 10;
// Access the values
NSLog(#"X: %d", self.x)
NSLog(#"Y: %d", self.y)
}
So I've created two separate classes, FishA has a size property and FishB has a color property. Both fish have the x and y properties. Not overly exciting but it makes the two classes different.
Use
#import "FishA.h"
#import "FishB.h"
- (void) example {
FishA *fishA = [[FishA alloc] init];
FishB *fishB = [[FishB alloc] init];
fishA.x = 10;
fishB.x = 20;
fishA.size = 50; // Works
fishB.size = 50; // Will not work
fishA.color = [NSColor redColor]; // Will not work
fishB.color = [NSColor redColor]; // Works
}
This will not work
-(void)blah
{
x = Fish2.x;
y = Fish2.y;
}
You need to create a pointer for Fish2. Something like this...
-(void)blah
{
Fish2 *selectedFish = //wherever the instance of the fish is.
x = selectedFish.x;
y = selectedFish.y;
}
If Fish creates an instance of fish2 maybe doing something like this would be more helpful.
-(void)blahWithFish:(Fish2)currentFish
{
x = currentFish.x;
y = currentFish.y;
}
If you do something like that you can pass the fish to this method.
Also is there a reason for fish2? Are you not just creating 2 fish objects? Do they perform the same task? Maybe fish2 should inherit from Fish?
Does that help?
Related
I have a class in a game that is often used, and I thought it would be nice to tidy it up by grouping together instance variables with a typedef struct. I'm not completely convinced yet this will help or not.
Originally in my class header interface I had something like this:
#interface ThingClass : CCLayer {
#public
bool _invulnerableToggled;
int _invulnerableCount;
int _invulnerableMax;
}
#property(nonatomic, assign) bool invulnerableToggled;
#property(nonatomic, assign) int invulnerableCount;
#property(nonatomic, assign) int invulnerableMax;
and in my .m
#synthesize
invulnerableToggled = _invulnerableToggled,
invulnerableCount = _invulnerableCount,
invulnerableMax = _invulnerableMax;
A subclass of this class would set these variables to their default values in init. Another class could access an instance of this subclass and set the values accordingly with regular dot notation, like tempThing.invulnerableToggled = YES;
Now that I'm using a typedef struct, it looks as though my values cannot be adjusted, and I've tried various things to overcome it. Although it may be because I'm not setting this up correctly to begin with, so just in case I'll show you what I'm doing now.
Currently my class header:
typedef struct {
bool toggled;
int count;
int max;
} Invulnerable;
#interface ThingClass : CCLayer {
#public
Invulnerable _invulnerable;
}
#property(nonatomic, assign) Invulnerable invulnerable;
and in my .m
#synthesize
invulnerable = _invulnerable;
I set these values in a subclass init like so:
_invulnerable.toggled = NO;
_invulnerable.count = 0;
_invulnerable.max = 50;
When I try to set this in another class, I expect it to add 1 to the current value. It always remains 1 instead. This if statement is sometimes checked 60 times a second, but has not change to the count:
Invulnerable invulnerable = tempBaddy.invulnerable;
// check baddy invulnerability and increment if needed
if(invulnerable.toggled == YES){
int increase = invulnerable.count +1;
invulnerable.count = increase;
NSLog(#"invulnerable.count = %i", invulnerable.count);
}
This is not a common way in ObjC but you can pass the struct by reference, i.e. return a pointer to the struct:
#interface ThingClass : CCLayer {
#protected
Invulnerable _invulnerable;
}
#property(nonatomic, readonly) Invulnerable* invulnerable;
#end
The *.m file:
#implementation ThingClass
- (Invulnerable*)invulnerable {
return &_invulnerable;
}
#end
Updating the data:
Invulnerable* invulnerable = tempBaddy.invulnerable;
// check baddy invulnerability and increment if needed
if(invulnerable->toggled == YES){
invulnerable->count++;
NSLog(#"invulnerable.count == %i", tempBaddy.invulnerable->count);
}
I guess you are trying to perform some action on an instance of ThingClass (or its subclass). And the action affects the value of _invulnerable. In this case a more common way would be having a method in the Thing class that performs all the required updates:
#implementation ThingClass
- (void)headshot {
if (_invulnerable.toggled) {
_invulnerable.count++;
} else {
[self die];
}
}
#end
I have two properties "M" and "m", not the best coding style I know but bear with me. Assignment to these properties in the init method does not function properly. Here's the code in it's entirety:
#import "AppDelegate.h"
#interface Foo : NSObject
#property (nonatomic, assign) int M;
#property (nonatomic, assign) int m;
- (id)initWithM:(int)M m:(int)m;
#end
#implementation Foo
- (id)initWithM:(int)M m:(int)m {
if((self = [super init])) {
self.M = M;
printf("M = %d %d\n", M, self.M);
self.m = m;
printf("M = %d %d\n", M, self.M);
printf("m = %d %d\n", m, self.m);
}
return self;
}
#end
#implementation AppDelegate
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
// Insert code here to initialize your application
Foo *f = [[Foo alloc] initWithM:2 m:1];
}
#end
And here is the output from the printf's:
M = 2 2
M = 2 1
m = 1 0
If I change "M" to "BAR" and "m" to "bar" it works as I would expect. Is there an explanation for this other than being a compiler bug?
Thanks.
#property int M;
#property int m;
both create
- (void)setM:(int)
If you really wanted to have both an m and an M property (which you definitely shouldn't) you can use
#property int M;
#property (setter = setLowerCaseM:, getter = lowerCaseM)int m;
I'm trying to take a C-style vector and convert it into an NSMutable array object.
Here's the function:
+(NSMutableArray*)arrayFromPoints:(vector<Point2f>&)points
{
NSMutableArray* pointArray = [[NSMutableArray alloc] init];
for (int i=0;i<points.size();i++)
{
Point2f point = points[i];
JBPoint* point2 = [[JBPoint alloc]initWithX:point.x andY:point.y];
[pointArray addObject:point2];
}
return pointArray;
}
Custom point class:
#implementation JBPoint
float _x;
float _y;
-(id) initWithX:(float)x andY:(float)y
{
if (self=[super init])
{
_x = x;
_y=y;
}
return self;
}
-(float)x{ return _x;}
-(float)y {return _y;}
#end
Test output:
for (JBPoint* pnt in array)
{
NSLog(#"%f, %f", pnt.x, pnt.y);
}
I except it to output the array, but every time it just gives me the last value! does anyone know why?
I thought that they were maybe pointing to the same object, but they have different memory addresses.
So I figured out the problem. float _x;
float _y; where being treated like class variables instead of instance variables. Changed the class to:
#interface JBPoint()
{
float _x;
float _y;
}
#end
#implementation JBPoint
-(id) initWithX:(float)x andY:(float)y
{
if (self=[super init])
{
_x = x;
_y=y;
}
return self;
}
-(float)x{ return _x;}
-(float)y {return _y;}
#end
if you wrote
#property (nonatomic, readonly) float x;
#property (nonatomic, readonly) float y;
in your header file you wouldn't need to declare the instance variables (and would have avoided the issue here) and you could delete the getter methods your wrote as that would all be generated by the compiler for you and your custom init method would continue to work (with the most recent compiler).
Its a good idea to do this because:
less code
your intent is clear - 2 variables that are readonly for clients
follows language conventions
If you are using an older compiler (an older version of Xcode) then you would also have to #synthesize the accessors like this:
#synthesize x = _x;
Some interesting asides:
With the most recent complier you didn't need the class extension.
#implementation{
float _x;
float _y;
}
would also have worked.
As referenced in WWDC 2012 session video 413, the current recommended pattern to write an init method is:
...
self = [super init];
if (self) {
...
}
return self;
I am following along with a series of web tutorials relating to Objective-C and am now getting a "Accessing unknown origin getter method" error when i try to build my program (origin being a member of a Rectangle class that I created).
Here is my class titled PointXY:
#import <Foundation/Foundation.h>
#interface PointXY : NSObject
{
int x;
int y;
}
//Setters and Getters
#property int x;
#property int y;
//Methods
- (void) setXY : (int) xCO : (int) yCO;
#end
I then define a rectangle class, that has a member that is of type PointXY:
#import <Foundation/Foundation.h>
#class PointXY;
#interface rectangle : NSObject
{
float width;
float height;
PointXY * origin;
}
//Setters and Getters
#property float width, height;
//Instance Methods
- (float) getArea;
- (float) getPerimeter;
//We already have setters and getters defined for width
//and height. The below method is for illustration purposes
- (void) setHW: (float) h : (float) w;
//Methods to set and get origin values
- (PointXY *) getOrigin; //Returns a PointXY object
- (void) setOrigin : (PointXY *) point;
#end
I get the error in main, if i try to access the x or y property of my origin member via my NSLog statement:
#import <Foundation/Foundation.h>
#import "rectangle.h"
#import "PointXY.h"
int main (int argc, const char * argv[]) {
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
//Create an object
rectangle * myRectangle = [[rectangle alloc]init];
PointXY * rOrigin = [[PointXY alloc]init];
[rOrigin setXY:100 :100];
myRectangle.origin = rOrigin;
NSLog(#"The origin for the rectangle is %i, %i", myRectangle.origin.x, myRectangle.origin.y);
[pool drain];
return 0;
}
I understand that one cannot access the members without either explicitly defining a synthesized accessor or by creating a method to do just that and was surprised to see the author of the tutorial do the above with no issue.
Is the above even possible? Can I access myRectangle.origin.x without origin being synthesized in myRectangle or do I have something set up incorrectly.
Thanks for your time.
Origin is an instance variable you need to create an #property for it and synthesize it as you already know.
//Setters and Getters
#property float width, height;
#property PointXY *origin;
But without the property you could access the origin by doing this rectangle->origin but that defeats the purpose of encapsulation.
Edit- origin will need to be defined as #public or #package
I'm trying to work my way through an Objective-C tutorial. In the book there is this example:
#interface
{
int width;
int height;
XYPoint *origin;
}
#property int width, height;
I thought, "hey there's no getter/setter for the XYPoint object. The code does work though." Now i'm going maybe to answer my own question :).
I thinks its because "origin" is a pointer already, and whats happening under the hood with "width" and "height", is that there is going te be created a pointer to them..
Am i right, or am i talking BS :) ??
I just dont get it. here's main:
#import "Rectangle.h"
#import "XYPoint.h"
int main (int argc, char *argv[])
{
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
Rectangle *myRect = [[Rectangle alloc] init];
XYPoint *myPoint = [[XYPoint alloc] init];
[myPoint setX: 100 andY: 200];
[myRect setWidth: 5 andHeight: 8];
myRect.origin = myPoint;
NSLog (#"Rectangle w = %i, h = %i",
myRect.width, myRect.height);
NSLog (#"Origin at (%i, %i)",
myRect.origin.x, myRect.origin.y);
NSLog (#"Area = %i, Perimeter = %i",
[myRect area], [myRect perimeter]);
[myRect release];
[myPoint release];
[pool drain];
return 0;
}
And here's the Rectangle object:
#import "Rectangle.h"
#import "XYPoint.h"
#implementation Rectangle
#synthesize width, height;
-(void) setWidth: (int) w andHeight: (int) h
{
width = w;
height = h;
}
- (void) setOrigin: (XYPoint *) pt
{
origin = pt;
}
-(int) area
{
return width * height;
}
-(int) perimeter
{
return (width + height) * 2;
}
-(XYPoint *) origin
{
return origin;
}
#end
What i dont understand is this line in main: myRect.origin = myPoint; I did not make a setter for it..
BTW thanks for your fast reply's
What i dont understand is this line in main: myRect.origin = myPoint; I did not make a setter for it..
There is both a getter and a setter (collectively referred to as accessors) created for origin in the Rectangle class. If you have a look in the implementation for Rectangle, this is the getter:
-(XYPoint *) origin
{
return origin;
}
and this is the setter:
- (void) setOrigin: (XYPoint *) pt
{
origin = pt;
}
And as of Objective-C 2.0 calling:
myRect.origin = myPoint;
is equivalent to:
[myRect setOrigin:myPoint];
Declaring getters and setters using #property (and then implementing them using #synthesize) is only one way of declaring and creating accessors, and is there for a convenience if you have lots of properties to declare in the class interface. As Schildmeijer said, #property int width is equivalent to declaring two methods:
- (int)width;
- (void)setWidth:(int)newWidth;
Due to the dynamically-bound nature of Objective-C method calls, you don't even have to declare the getter and setter methods in the interface, although it is generally best practice to do so if you are advertising them as publicly available to other classes.
You can think of a property declaration as being equivalent to declaring two accessor methods. Thus
#property int width;
is equivalent to:
- (int)width;
- (void)setWidth:(int)newWidth;
//Rectangle.h
#import <Foundation/Foundation.h>
#interface Rectangle : NSObject
#property int Width;
#property int Height;
-(int)Area;
#end
//Rectangle.m
#import "Rectangle.h"
#implementation Rectangle
#synthesize Width;/*Will create value Width , Setter called"setWidth" and Getter called "Width"*/
#synthesize Height;/*Will create value Height , Setter called"setHeight" and Getter called "Height"*/
-(int)Area
{
return Width*Height;
}
#end
// main.m
#import <Cocoa/Cocoa.h>
#import "Rectangle.h"
int main(int argc, const char * argv[])
{
Rectangle *myRectangle = [Rectangle new];
myRectangle.Width=3;
myRectangle.Height=5;
printf("Area = %d\n",[myRectangle Area]);
//Or
[myRectangle setWidth:5];
[myRectangle setHeight:6];
printf("Area = %d\n",[myRectangle Area]);
}
If you want to make Getter only or rename getter and setter
• readonly
• getter = newGetterName
• setter = new SetterName
example
//Rectangle.h
#import <Foundation/Foundation.h>
#interface Rectangle : NSObject
#property (getter = getWidth) int Width;
#property (readonly) int Height;
#end
You don't say what code is working, or what your expectations are for "working".
The above interface will create simple accessor methods for width and height that can be called from other objects as [object setWidth:1]; or object.width = 1; - these two are analogous.
Origin is some other object type and is a pointer, yes. But you would still want to declare a property for it to generate accessor methods.
Getters and setters are mostly useful if you need to access an instance variable from another class or you're using bindings to get/set them. So my guess would be that you need this functionality for the width and height but not for the origin. Note that the getters/setters do not make pointers out of the integers as you stated might be the reason. Ints are ints and getters/setters do not change that.