Cast an Objective C UITextField value to float - objective-c

I have a UITextField called txtDiscount
It has a value in it: txtDiscount.text == 2.3 //for example
I've tried:
float test = (NSNumber *)txtDiscount.text;
And it compiles, but at runtime breaks down.
Unacceptable type of value for attribute: property = ..."; desired type = NSNumber; given type = NSCFString; value = .
How can I cast the value?
Any help greatly appreciated,
Thanks // :)

You probably want something like:
float test = [txtDiscount.text floatValue];
The NSString documentation provides a list of all the built-in casts.

A cast like this
(NSNumber *)myInstance
is telling the compiler to treat 'myInstance' as if it were an instance of class NSNumber. This may influence compile time warnings and errors. Note: - the compiler. It makes no difference to the code that is generated or run - at all. The code that you are running is still
float test = [txtDiscount text];
where the method -text is returning a pointer to an NSString and you are trying to assign it to a float variable.
see clee's answer for how to get float value from an NSString - but make sure you understand why what you were trying to do is wrong. It will help loads in the long run.

Related

error with NSSring

I'm very new to objective-c and I'm getting a basic error and unsure on how to fix it.
for(ZBarSymbol *sym in syms) {
resultText.text = sym.data; //sym.data = 0012044012482
[self phpPost:(int)sym.data];
break;
}
}
- (void)phpPost: (int)barcode {
NSString *theValue = [NSString stringWithFormat:#"%#", barcode]; //problem line
labelScan.text = theValue;
//labelScan.text = #"Barcode scanned";
}
when i use #"%#" the text of the label is correct (0012044012482), but when i use #"%d" it isn't (random number every time i restart the app). I would like to use #"%#" (or something that works) but for some reason xCode is giving me an error. and I'm unsure on how to fix the error.
The error is:
Format specifies type 'id' but the argument has type 'int'
In the end I plan on having that code (sym.data) written to a MySQL database using the POST method.
You can't just convert it to an int by casting if it's an object (which it must be if the %# format specifier isn't causing a crash).
Assuming from the fact that you're assinging it directly to a label's text that it's an NSString, you should either change the parameter type of phpPost:
- (void)phpPost: (NSString *)barcode {
labelScan.text = barcode;
}
or extract the intValue before passing sym.data:
[self phpPost:[sym.data intValue]];
and then use the proper %d format specifier in phpPost:.
Your barcode isn't an int, it is an NSString. Instead of doing (int)sym.data, pass in [sym.data intValue]. That should correctly convert it to an integer.
The reason you get a random number is because you can't just cast a string object to a primitive data type :)
I don't know what type sym.data is, but it is likely a pointer to an object, and not the value itself. You cast that pointer to int, so when you are using %d you are effectively printing the memory location of the object. That is why it changes each time you run the program (Objective-C let's you do this without any warnings - something to watch out for).
To fix this, either extract the integer value you need from the sym.data object using it's properties; or pass the object as a pointer. For instance, you could try calling your method like this:
[self phpPost:sym.data];
And then change your method to be:
- (void)phpPost: (id)barcode {
NSString *theValue = [NSString stringWithFormat:#"%#", barcode];
labelScan.text = theValue;
}
Ok, I did some thinking while I was at work today, and I figured out that an INT isn't going to work for me. if I make that object to an int, I would loss some data that is vital to what I'm doing. eg. object=001234 int=1234. I need the zeros. So, in the end, I'm keeping it an object (string) and just passing it into the function.
Here is my code after I got it working correctly.
for(ZBarSymbol *sym in syms) {
resultText.text = sym.data;
[self phpPost:sym.data];
break;
}
}
- (void)phpPost: (NSString *)barcode {
labelScan.text = barcode;
//labelScan.text = #"Barcode scanned"; //My custon label
}
Thanks, everyone for your responses. Your answer will not go unused. I'm sure I'll be needing this information here soon.
O, if you see that I did this wrong, or not the correct way, please make a comment and tell me .

trial and error do while statement in iOS

I am new to iOS programming/objective c, I am trying to do an iterative trial and error calculation and I am stuck. Ordinarily this code would have worked in excel VBA so I'm not sure how to overcome this issue in obj C:
- (IBAction)calculate:(id)sender {
static float friction=2;
static float difference;
float Re = [pipe_id.text floatValue] * [fluid_velocity.text floatValue] / [kin_viscosity.text floatValue];
ReynoldsNo.text = [[NSString alloc]initWithFormat:#"%6.2f", Re];
do{
float Colebrook1 = 1/powf(friction,0.5);
float Colebrook2 = -2*log10f([RelativeRoughness.text floatValue]/(3.7*[pipe_id.text floatValue]) + 2.51/(Re*powf(friction,0.5)));
float difference = fabsf((Colebrook1-Colebrook2)*1000);
friction = friction - 0.000001;
FrictionFactor.text = [[NSString alloc]initWithFormat:#"%6.2f", friction];
Cole1.text = [[NSString alloc]initWithFormat:#"%6.2f", Colebrook1];
Cole2.text = [[NSString alloc]initWithFormat:#"%6.2f", Colebrook2];
}while (difference > 0.000001);
}
So when I compile this, the value for friction stays at 2. My loop isn't working, so the whole trial and error thing has fallen apart. I need some help to see how this should be written in objective C. Thanks for you help, ALM.
This line is your problem:
float difference = fabsf((Colebrook1-Colebrook2)*1000);
You already declare the variable difference outside the loop; there is no need to declare it again inside the loop.
You probably want to say:
difference = fabsf((Colebrook1-Colebrook2)*1000);
Also, are you sure that your outer declaration needs to be static? That means its value persists between calls to the method. It's valid code, but unusual to see.
Be aware of block scope. Your inner difference shadows the outer, so you may want to avoid re-declaring it by simply removing the float.
Also, as a convention tip, leave the capitalized identifiers for classes.

Parameters in output in selector, objective c

i'm executing a method in background, by #selector(method) but i dont' understand how can i return data, for example if method name is:
-(int)methodWithAge:(int)age
i make:
int a = [self performBackgroundThread #selector(methodWithAge:) WithObjects:myAge];
but it doesn't work.
Thanks for any help.
I guess you shuold use NSNumber instead of int
-(int)methodWithAge:(NSNumber*) age
And convert int to NSNumber
NSNumber* num = [NSNumber numberWithInt:age];
int a = [self performBackgroundThread #selector(methodWithAge:) WithObjects:num];
Not using it right. Whats your exact error? I don't know any backin method called performBackgroundThread. You have to pass your values pack to the main thread. Read this tutorial on this topic.

Objective c - float returning wrong value

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.

object_getInstanceVariable works for float, int, bool, but not for double?

I've got object_getInstanceVariable to work as here however it seems to only work for floats, bools and ints not doubles. I do suspect I'm doing something wrong but I've been going in circles with this.
float myFloatValue;
float someFloat = 2.123f;
object_getInstanceVariable(self, "someFloat", (void*)&myFloatValue);
works, and myFloatValue = 2.123
but when I try
double myDoubleValue;
double someDouble = 2.123f;
object_getInstanceVariable(self, "someDouble", (void*)&myDoubleValue);
I get myDoubleValue = 0. If I try to set myDoubleValue before the function eg. double myDoubleValue = 1.2f, the value is unchanged when I read it after the object_getInstanceVariable call. Setting myIntValue to some other value before the getinstancevar function above returns 2 as it should, ie. it has been changed.
then I tried
Ivar tmpIvar = object_getInstanceVariable(self, "someDouble", (void*)&myDoubleValue);
If I do ivar_getName(tmpIvar) I get "someDouble", but myDoubuleValue = 0 still! Then I try ivar_getTypeEncoding(tmpIvar) and I get "d" as it should be.
So to summarize, if typeEncoding = float, it works, if it is a double, the result is not set but it correctly reads the variable and the return value (Ivar) is also correct.
I must be doing something basic wrong that I cant see so I'd appreciate if someone could point it out.
object_getInstanceVariable is a confused little function. It is documented that the last parameter is a void ** parameter—that is, you pass the address of a void * variable and get a pointer to the instance variable—but it is implemented as if it was a void * parameter—that is, you pass the address of the variable that you want to hold a copy of the instance variable. The problem is that the implementation ignores the size of the instance variable and just does a pointer copy. So anything that's the same size as a pointer will work perfectly. If you're running on a 32-bit architecture, only the high 32 bits will be copied. (You should witness the same behavior with a long long instance variable as well.)
The solution is to use the primary API, key-value coding, using -valueForKey:.
The other solution: If you wanted to write a fixed version, say as a category for NSObject, it would look something like this:
#implementation NSObject (InstanceVariableForKey)
- (void *)instanceVariableForKey:(NSString *)aKey {
if (aKey) {
Ivar ivar = object_getInstanceVariable(self, [aKey UTF8String], NULL);
if (ivar) {
return (void *)((char *)self + ivar_getOffset(ivar));
}
}
return NULL;
}
#end
Then your code would look like this:
double myDoubleValue = *(double *)[self instanceVariableForKey:#"someDouble"];
What about using valueForKey:?
NSNumber * value = [self valueForKey:[NSString stringWithUTF8String:ivar_getName(tmpIvar)]];
NSLog(#"Double value: %f", [value doubleValue];
Note: this requires you to have a "someFloat" method. If you want to use setValue:forKey:, you'll also need the "setSomeFloat:" method. This is easily implemented by declaring the ivar as an #property and synthesizing it.