float in an object's message - objective-c

I have an object with a method that should take a float as a parameter, but the value in the object is not correct. Passing an int or double fixes the problem, but why doesn't float work?

Because you haven't provided a prototype for the method in the scope of the caller.

Related

When to use instance variables instead of properties in objective-C?

With the Objective-C's #property directive I can declare properties for which getter and setter methods will be created automatically. I can't think of any particular reason to use instance variables where I would have to write my own setter and getters, but I'm sure there must be an example where using instance variables is more preferable. Could there be any reason to use instance variables instead of properties? Are there any practical examples for it?
The problem is on this line
slope = (line_cordinates[3] - line_cordinates[1]) / (line_cordinates[2] - line_cordinates[0]);
slope is declared a float, but line_cordinates is an array of int.
So you are doing all of the math on the right hand side as int math, then assigning it to a float. So the final result of all the int operations is implicitly converted to float, but by then you have already lost the precision from truncation, etc.
The quickest fix would be to simply declare
float line_cordinates[4] = {0.0, 0.0, 0.0, 0.0};
Use,
slope = static_cast<float>((line_cordinates[3] - line_cordinates[1])) / (line_cordinates[2] - line_cordinates[0]);
You need to typecast any of the operand on right hand side to float. So expression will result in float.
int op int = int
float op int = float

Pointer to BOOL in Objective C

Code:
NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature];
BOOL initial = YES;
[invocation setArgument:&initial atIndex:2];
Question:
Would it be possible to pass YES to setArgument:atIndex: without creating the temporary variable?
I was thinking that maybe there's a language construct I'm not aware of and/or constant in the runtime that is always YES that I can point to.
Thanks!
No, not in any clean, reliable way.
NSInvocation will dereference whatever pointer you send it and copy data of length specified by the method signature out of it. You need to have that information somewhere so you can get an address to it, and having the local variable as you have is the best way to do so.
The answer is no. A pointer must point to an address in memory. So first you must allocate that memory and then send the address of that allocated memory into the method. In the case of a primitive the memory allocated will be on the stack and with an object the memory allocated for the object will be on the heap and the address of that object will be stored on the stack. As for the error you are getting the void* parameter of setArgument:atIndex: seems to want an object and not a primivtive. Have you tried using a NSNumber to represent a bool. NSNumber comes with a numberWithBool: method.
A pointer must point to something(including garbage) or nothing(means the pointer being initialized to NULL). A pointer is an indirect reference to an object. If you don't have such an object for your pointer to point to, you may not need a pointer. You can simply call setArgument:NULL atIndex:2.
The case to use a pointer like that in your code is to pass an output parameter, whose value will be set in the function you call, and in this case, you probably don't need to initialize the parameter before passing it to the function, the function is supposed to take care of assigning correct value to it.
So in your case, if you didn't mean to use a output parameter, you only need to pass the primitive BOOL to the function, no pointer needed.
EDIT
I just took a look at the doc for NSInvocation. The answer is the same as others', NO.
You have to pass a pointer, which must point to an existing object for NSInvocation to work correctly.

Incompatible Type for Argument 1 Objective-C

I have a function that sets an entity within a Core Data store. I used to have all values it would be storing as type double, however now I must make it accommodate NSStrings as well. Consequently, I changed the type of the parameter the function takes in, to an id type. However, now I get the error:
error: incompatible type for argument 1 of 'numberWithDouble:'
...at the following lines:
//...
[dfm setTimeStamp:[NSNumber numberWithDouble:value]];
//...
[[fetchedObjects objectAtIndex:0] setValue:[NSNumber numberWithDouble:value] forKey:#"timeStamp"];
//...
Apparently it doesn't like the [NSNumber numberWithDouble:value] segment of each line. I was contemplating making a container class that holds an NSNumber type (doesn't Apple already have a class like this?) to get around this problem, but I thought that there has to be an easier way I am not thinking of (besides duplicating the function and changing the type of the value parameter). Any ideas? Thanks in advance!
EDIT:
Here is the function declaration:
-(void)setItemInDFMWhilePreservingEntityUniquenessForItem:(attribute)attr withValue:(id)value
attribute is merely an enum which specifies which entity to store within. The problem is that the compiler is giving me problems with value being of type id, theoretically I can pass in anything I want, and I believe the way I have it I am implying that I will be passing it as an NSNumber, but the compiler doesn't like that as that is not actually a class instance I suppose?
The problem is that the compiler is
giving me problems with value being of
type id, theoretically I can pass in
anything I want, and I believe the way
I have it I am implying that I will be
passing it as an NSNumber, but the
compiler doesn't like that as that is
not actually a class instance I
suppose?
By declaring value as id, you can pass any object you want. But why do you "suppose" that NSNumber isn't an object, when it's clearly documented as being an object? The warning isn't about passing an NSNumber instance when you've declared value as an id - that's perfectly valid, because id means "any object," and an NSNumber instance is an object. The warning comes from calling +numberWithDouble:, a method that takes a double for its first argument, and passing it value, which is declared as id - i.e. an object. You can't pass an object to a method that expects a double.
Your proposed solution, typecasting value with (NSInteger)value will silence the warning, but it won't fix the problem. The typecast simply converts the memory address the object pointer targets to an integer value. If (as your edit suggests) value is already an NSNumber object, what do you hope to gain by creating another one, or by typecasting its memory address to an integer? Just do:
[dfm setTimeStamp:value];
The problem lies with the value variable. It should be declared as a double (primitive) for this call to succeed.
edit: after rereading your question, do a check in the function on the type of value, if it is an NSString (use [value isKindOfClass:[NSString class]]) store it as such, if its not then its a double (if thats the only two types you are passing) and store it as such.
Can't you just pass the NSNumber instead of double?
Just realized that the call I was making (numberWithDouble:) was having the compiler check for a primitive, i.e. double. Changing it to the following worked like a charm:
[dfm setTimeStamp:[NSNumber numberWithInteger:(NSInteger)value]];
Thanks to those that responded!

ObjC internals. Why my duck typing attempt failed?

I've tried to use id to create duck typing in objective-c. The concept looks fine in theory but failed in practice. I was unable to use any parameters in my methods. The methods were called but parameters were wrong. I was getting BAD_ACESS for objects and random values for primitives. I've attached a simple example below.
The question:
Does any one knows why the methods parameters are wrong?
What is happening under the hood of the objective-c?
Note: I'm interest in the details. I know how to make the example below work.
An example:
I've created a simple class Test that is passed to an other class using property id test.
#implementation Test
- (void) aSampleMethodWithFloat:(float) f andInt: (int) i {
NSLog(#"Parameters: %f, %i\n", f, i);
}
#end
Then in the class the following loop is executed:
for (int i=0; i < 10; ++i) {
float f=i*0.1f;
[tst aSampleMethodWithFloat:f andInt:i]; // warning no method found.
}
Here is the output that I'm getting. As you can see the method was called but the parameters were wrong.
Parameters: 0.000000, 0
Parameters: -0.000000, 1069128089
Parameters: -0.000000, 1070176665
Parameters: 2.000000, 1070805811
Parameters: -0.000000, 1071225241
Parameters: 0.000000, 1071644672
Parameters: 2.000000, 1071854387
Parameters: 36893488147419103232.000000, 1072064102
Parameters: -0.000000, 1072273817
Parameters: -36893488147419103232.000000, 1072483532
Update:
I've found out by accident that when I add a declaration of aSampleMethodWith... to the class with for loop the warning disappears and the method on the Test class is called correctly.
Update 2:
As pointed out by JeremyP the direct cause of the problem is that the floats are treated as doubles. But anyone knows why? (following the 5why principle :) ).
According to #eman the call is translated to simple C function call and compiler directive to get the SEL. So the #selector gets confused. But why? The compiler have all necessary type informations in the first method call. Does any one knows a good source of information about the Objective-C internals I've search The Objective-C Programming Language but i didn't find the answer.
By default floating point values are passed as doubles, not floats. The compiler does not know, at the point where [tst aSampleMethodWithFloat:f andInt:i]; occurs that it is only supposed to pass a float, so it promotes f to a double. This means that, in the method, when the compiler does know it is dealing with a float, f is the float formed by the first four bytes of the double passed to the method and i is an int formed from the second four bytes of the double passed.
You can fix this by either
changing the first parameter of aSampleMethodWithFloat:andInt: to a double
importing the interface declaration of Test into the file where you use it.
NB there is no gain except a small amount of space when using floats in C. You might as well use doubles everywhere.
I think JeremyP is correct about the problem being about doubles vs floats. As for implementation details, message dispatch in Objective-C uses the objc_msgSend(id theReceiver, SEL theSelector, ..) C function (for some deep nitty-gritty, see here). You can simulate the same results of method dispatch like so:
SEL theSelector = #selector(aSampleMethodWithFloat:andInt:);
objc_msgSend(self.test, theSelector, 1.5f, 5);
SEL is just a number that corresponds to a function (that is dynamically determined based on the method signature). objc_msgSend then looks up the actual function pointer (of type IMP) of the method and invokes it. Since objc_msgSend has a variable number of arguments, it will just use as many as you pass in. If you were to do:
objc_msgSend(self.test, theSelector, 1.5f);
It would use 1.5f correctly and have junk for the other variable. Since the method signature typically denotes the number of arguments, this is hard to do under normal usage.
You can make the warning go away by making a category like this:
#interface NSObject (MyTestCategory)
- (void) aSampleMethodWithFloat:(float) f andInt: (int) i;
#end
Without a signature available at the calling point, it isn't known what type the parameters are supposed to have. Undefined methods will be assumed to take ... as parameters, which isn't what yours does. If there is any interface seen by the compiler at this point, where the method in question exists, that definition will be used.
The trouble here is with the dividing line between C and Objective-C. The id type specifies any object, but ints and floats are not objects. The compiler needs to know the C type of all the arguments and the return type of any method you call. Without a declaration, it assumes that a method returns id and takes an arbitrary number of id arguments. But id is incompatible with int and float, so the value doesn't get passed correctly. That's why it works correctly when you provide a declaration — then it knows your int is an int and your float is a float.

How to get double value from dictionary?

I'm trying to get a double value from a dictionary. How can I accomplish this in objective-c?
Dave's response to your previous question holds true for this, as well. To store a double value in an NSDictionary, you will need to box it in an NSNumber.
To set a double value in the dictionary, you'd use code like the following:
[someDict setObject:[NSNumber numberWithDouble:yourDouble] forKey:#"yourDouble"];
and read it back using the following:
double isTrue = [[someDict objectForKey:#"yourDouble"] doubleValue];
Brad Larson's response is exactly right. To elaborate on this a little more, you have to explicitly "wrap up" non-object number types (e.g., int, unsigned int, double, float, BOOL, etc.) into NSNumber when working with anything that expects an object.
On the other hand, however, some mechanisms in Objective-C, like Key-Value Coding (KVC), will automatically do this wrapping for you.
For example, if you have a #property of type int called intProperty, and you call NSObject (NSKeyValueCoding)'s valueForKey: method like [ someObject valueForKey:#"intProperty" ], the return result will be an NSNumber *, NOT an int.
Frankly, I don't care for having to switch between dealing with object and non-object types (especially structs and enums!) in Objective-C. I'd rather everything be treated as an object, but maybe that's just me. :)