I built a class and created a method which initialize all variables.
on .h
-(void) initWithX:(float *)x_ andY:(float *)y_ andWidth:(float *)width_;
and on .m
-(void) initWithX:(float *)x_ andY:(float *)y_ andWidth:(float *)width_{
[super init];
x = x_; ***
y = y_; ***
width = width_; ***
}
Lines with * give me error "Incompatible types in assignment" but I don't understand: I'm giving 3 floats as told in the .h!!!
Thank you all
Pass your floats by value by removing the *:
- (void)initWithX:(float)x_ andY:(float)y_ andWidth:(float)width_;
- (void)initWithX:(float)x_ andY:(float)y_ andWidth:(float)width_ {
[super init];
x = x_;
y = y_;
width = width_;
}
Otherwise the method is asking for pointers to floats (float *), and not their actual primitive values.
you are asking for float pointers and probably assigning them to float variables. take out the asterisks in the method declarations.
Related
This question already has answers here:
Mixing C Structs and Objective-C Properties
(2 answers)
Closed 8 years ago.
I have class A with a header that looks something like this:
typedef struct {
int x;
int y;
} Position;
#interface ClassA : NSObject
#property Position currentPosition;
#end
And I try to assign individual values of the position struct from the property in another class like this:
ClassA * classA = [ClassA new];
classA.currentPosition.x = 10;
Which gives an error "expression is not assignable" and won't compile.
I can set it like this:
ClassA * classA = [ClassA new];
Position position = {
.x = 1,
.y = 2
};
classA.currentPosition = position;
And I can even alter individual "properties" of position variable like this:
ClassA * classA = [ClassA new];
Position position = {
.x = 1,
.y = 2
};
// WORKS
position.x = 4;
// DOESN'T WORK
// classA.currentPosition.x = 4;
classA.currentPosition = position;
Why can't I set values individually when they are a property?
This expression:
classA.currentPosition
returns a temporary copy of your struct, not the struct itself. The compiler error is telling you that you can't assign a value to some member of that temporary copy (because it's an rvalue, technically). But you don't want to assign a value to that member anyway, because it would just disappear along with the struct itself.
So why are you only getting a copy of the struct in the first place?
Because
#property Position currentPosition
is actually just shorthand for:
-(Position)currentPosition;
-(void)setCurrentPosition(Position value);
and in C-family languages, the first line (the getter) indicates that it's returning a Position struct by-value, or as a copy.
You could make your own accessor that returns a reference, but you probably shouldn't. This isn't a common idiom in Objective-C -- at least not in this context -- and you should generally try to stick with common idioms for a language.
Instead, you should use position like the following;
Position pos = classA.position;
pos.x = 4;
classA.position = pos;
Lastly, if you really want to be able to set currentPosition using the syntax you originally desired, while maintaing Objective-C idioms, you could just make Position a class rather than a struct. Then, the property can return a Position * and the rest of the syntax would work. Make sure to initialize the pointer in your init function (or when appropriate).
Properties don't work for C structs.
You can do it like:
#property Position *currentPosition;
Basically, using a pointer.
Now you actually need to initialize that pointer so:
- (id) init {
self = [super init];
if(self){
self.currentPosition = malloc(sizeof(Position));
}
return self;
}
Then, don't forget to use arrow notation, since you're dealing with a pointer:
classA.currentPosition->x = 5;
And don't forget to free the memory you requested!
-(void)dealloc{
free(self.currentPosition);
}
My map object has a set of coordinates. It doesn't always have the same number of coordinates.
In java I'd just declare the object as Double[] xpoints and would set it's size when instantiating a map like this: xpoints = new double[npoints];
How can I do this with objective-c?
I tried doing this: #property(nonatomic) double * xpoints; but somehow all of it's values turn to 0 when I print it with NSLog.
Map's init:
-(id)initWithXpoints:(double[]) xpointss Ypoints:(double[]) ypointss Npoints:(int)npointss
{
self = [super init];
if (self)
{
self.xpoints = xpointss;
self.ypoints = ypointss;
self.npoints = npointss;
}
return self;
}
Something weird happens though. The values are changed to zero when I print xpoints[0] from the object that created the map. The first time I print it it works. The second time it just prints zero.
I think it happens because xpointss sent to init is removed from the memory. How can I "instantiate" the xpoints property if it's a pointer?
Is there a better way to do this?
added: I tried creating a temporary xpoints like this:
double tempxpoints[npointss];
double tempypoints[npointss];
for (int i = 0; i < npointss; i++)
{
tempxpoints[i] = xpointss[i];
tempypoints[i] = ypointss[i];
}
self.xpoints = tempxpoints;
self.ypoints = tempypoints;
But it still didn't work.
Edit: Thanks for all the answers. This ended up being my final Init code:
-(id)initWithXpoints:(double[]) xpointss Ypoints:(double[]) ypointss Npoints:(int)npointss
{
self = [super init];
if (self)
{
_xpoints = [[NSMutableArray alloc] init];
_ypoints = [[NSMutableArray alloc] init];
for (int i = 0; i < npointss; i++)
{
NSNumber *tempx = [NSNumber numberWithDouble:xpointss[i]];
NSNumber *tempy = [NSNumber numberWithDouble:ypointss[i]];
[_xpoints addObject:tempx];
[_ypoints addObject:tempy];
}
_npoints = npointss;
}
return self;
}
If you allocate the arrays as local variables, then they will be allocated on the stack. When execution leaves the function, those memory areas are freed up. You must use malloc() to allocate arrays that you can pass around and use free() to free them up.
// to allocate
double[] tempxpoints = (double[])malloc(sizeof(double) * npointss);
// to free when not used any more
free(tempxpoints);
But actually NSArray has been designed to handle these cases. And with ARC you don't even have to care about freeing the memory.
NSMutableArray *tempxpoints = [[NSMutableArray alloc] init];
[tempxpoints addObject:#2]; // wrap the double in an NSNumber object
If you were being fully Objective-C about it, you'd use an NSArray, fill it with NSNumbers and never specify a length. You can usually give them hints about how much space is likely to be required but Objective-C's collections all always size dynamically.
As of recent versions of the compiler, you can use array[x] notation on NSArray and write direct NSNumber constants as e.g. #4.5f if that sweetens the deal at all.
If you literally want C-style arrays then you'll need to descend to the C level of thought. So, something like:
#property(nonatomic, readonly) double * xpoints;
And:
-(id)initWithXpoints:(double[]) xpointss Ypoints:(double[]) ypointss Npoints:(int)npointss
{
self = [super init];
if (self){
size_t sizeOfArraysInBytes = sizeof(double)*npointss;
_xpoints = (double *)malloc(sizeOfArraysInBytes);
memcpy(_xpoints, xpointss, sizeOfArraysInBytes);
/* ... etc ... */
/* you never use self. notation in an init because it's a method call,
and method calls on objects that are not yet fully instantiated aren't
safe. Sample cause of failure: a subclass overrides the setter */
}
return self;
}
- (void)dealloc
{
free(_xpoints);
/* ... etc ... */
}
The array itself will be read/write elsewhere (it's the pointer that's read-only, not the things it points to) as class.xpoints[0], etc.
Being noob in objective-c,I just came across a problem in object ownership in a class that cannot explain the reason.
Suppose that I have a class called Point that describes a point with x,y.
A class called rectangle has an object of type Point that represents its left bottom edge. With following implementation
#implementation Rectangle {
Point *origin;
}
-(Point *) origin {
return origin;
}
-(void) setOrigin: (Point *) pt {
origin = pt;
}
#end
Now I simply instantiate the Rectangle, assign its origin a pointer to object of Point
Rectangle *rectangle2 = [[Rectangle alloc] init];
Point *pt = [[Point alloc] init];
[pt setX:1 andY:2];
rectangle2.origin = pt;
NSLog(#"Point's x= %i, y=%i",pt.x,pt.y); // result: Point's x=1,y=2
NSLog(#"Rectangle's origin x= %i, y=%i",rectangle2.origin.x,rectangle2.origin.y); //Rectangle's origin x=1,y=2
Now if I change the x,y of the object pt(following line of code), the rectangle2 object's origin will change as well, because it does not own its object, instead just points to where pt pointing to
[pt setX:10 andY:12];
NSLog(#"Point's x= %i, y=%i",pt.x,pt.y); // result: Point's x=10,y=12
NSLog(#"Rectangle's origin x= %i, y=%i",rectangle2.origin.x,rectangle2.origin.y); //Rectangle's origin x=10,y=12
This is completely logical, with no issue.
Issue seems to be happening in a similar scenario.
AddressCard class has an object of type NSString,
#implementation AddressCard{
NSString *phone;
}
-(void) setPhone:(NSString *) p {
phone = p;
}
-(NSString *) name {
return name;
}
#end
I instantiate AddressCard, assign an NSString pointer to its phone object.
AddressCard *addressCard1 = [[AddressCard alloc] init];
NSString *phoneObject = #"(111) 111 - 1111";
addressCard1.phone = phoneObject;
NSLog(#"addressCard1 phone: %#",addressCard1.phone); // result: (111) 111 - 1111
NSLog(#"phone object: %#",phoneObject); // result: (111) 111 - 1111
But now if I change phoneObject, addressCard1.phone won't change despite this way I'm setting the phone object in AddressCard class (setPhone method in class implementation)
phoneObject = [NSString stringWithString:#"PHONE IS CHANGED"];
NSLog(#"%#",phoneObject); //result : PHONE IS CHANGED
NSLog(#"Phone after change in the AddressCard is: %#",addressCard1.phone); // result: (111) 111 - 1111
Could some objective-c ninja tells me what's the difference between two snippets, and the reason of this?
In the first case, you modify an object: changing the x, y that are in the point.
In the second case, you create a new string, and point to that with phoneObject. You didn't modify the string itself (and you couldn't anyway - NSString is immutable). That means the original string you gave to the address card still exists and is still valid, so the address card still uses that string. If you want it to use the new one, you need to tell it to, putting:
addressCard1.phone = phoneObject;
again after reassigning phoneObject.
I'm using objective c and trying to output a value from a function. Apparently I am doing something wrong because I'm receiving an incorrect value.
This is my code:
-(float) getAngleBetween {
float num = 0.0;
return num;
}
and I'm calling it as follows:
float *theAngleBetween = [self getAngleBetween];
NSLog(#"Angle.. = %f", theAngleBetween);
Any help please?
float theAngleBetween = [self getAngleBetween];
// ^
There should be no *.
Since you are returning a float, the receiver should have type float as well. float* means a pointer to float, which is entirely different from float.
BTW, make sure you declare -(float)getAngleBetween; before you call [self getAngleBetween]. Put it in the #interface. If it is not declared before, the method will be assumed to have the type -(id)getAngleBetween;. On x86 returning a id and a float use different API (objc_msgSend vs objc_msgSend_fpret), which may be the cause of wrong result.
You should have:
float theAngleBetween = [self getAngleBetween];
Get rid of the *, that's for objects only, float is a primitive data type.
Is there a way to pass a float "byref" to a method in objective C? Here's an overview of what I've got:
method signature:
- (void) MyMethod: (float*) min max:(float*) max;
method:
- (void) MyMethod: (float*) min max:(float*) max
{
}
trying to invoke it:
float min1 = 0; float max1 = 0;
[self MyMethod: min:&min1 max:&max1];
I get the following warning, and the code abends when trying to invoke MyMethod:
warning: 'MyClass' may not respond to '+MyMethod:min:max:'
The signature for your method is declared as
- (void) MyMethod: (float*) min max:(float*) max
but you are calling it as
- MyMethod:min:max:
... which includes an extra 'min:' that's not in the declaration.
Try changing your calling code to
float min1 = 0; float max1 = 0;
[self MyMethod:&min1 max:&max1];
and see if that improves things.
However, I see that your error message complains about the signature '+ MyMethod:min:max:', which also suggests you're trying to send the message to the class rather than an instance of the class; you will have to rectify that.
Finally, method selectors in Objective-C code usually start with a lower-case letter; you might want to read up on common Objective-C naming conventions.