Can't do mathematical operations with int from NSUserDefaults - iphone

i have integer data, stored in NSUserDefaults, there is my code:
- (IBAction)addButton:(id)sender {
NSInteger oldValue = [[NSUserDefaults standardUserDefaults] integerForKey:#"myValue"];
NSString *string1=[addTextField text];
int add = [string1 floatValue];
int new = globalCalories;
int old=oldValue;
if(recomended.text==[NSString stringWithFormat:#"%i", oldValue]){
**self.day = (int)roundf(old-add);
dayLeft.text=[NSString stringWithFormat:#"%d", oldValue-add];
}**
else
{
self.day=(int)roundf(new-add);
dayLeft.text=[NSString stringWithFormat:#"%d", day];
}
}
I copied all of button action code, just in case, but i did mark with bold strings of code, that appear to not work. So, it suppose to do mathematical operations with stored data (oldValue), but when i launch programs, it dosnt, in fact, it does, but instead of valid value program "think" that oldValue is 0 (instead of valid value).
So, when it contain, for example, number 2000, and I launch program and enter in text field 500, it suppose to be 1500 (2000-500), but it shows -500.

You can convert recommended.text to integer by using this:
int recommendedValue = [recommended.text intValue];
then compare the numbers.

The problem is that == compared the address es of the NSString and not their values (see many SO questions). To compare strings use the isEqualToString: method.
However in this case it would be even better to compare the numbers ie convert recomended.text to the number and use a intValue method on dayLeft.

Related

How to store UUID as int

I m having some issues here.. I am using the following code to generate the uuid in mine application.
- (NSString *)GetUUID
{
CFUUIDRef theUUID = CFUUIDCreate(NULL);
CFStringRef string = CFUUIDCreateString(NULL, theUUID);
CFRelease(theUUID);
return [(NSString *)string autorelease];
}
This code returns a NSString object back. Now I want to store the generated UUID as unsigned int. Any suggestions please how can i do it here. Thanks.
According to the Wikipedia page, UUIDs are 128 bits long. The largest int value you'll be able to work with is 64 bits. Therefore, I'd says you can't store it in an int because there simply isn't room.
Convert UUID to String using .UUIDString
Take string's .hash property.
Cast to int.
int numericFormUUID = (int)UUIDString.hash;
Note: collision is possible, as always, with hashing. Two users could end up with the same value here, whereas UUID is guaranteed unique.

What's most performant way in iOS to check if a string is one of a list of strings?

I want to see if stringA is equal to any of a list of strings -- string1, string2, string3. What's the most performant way to do the comparison?
Since my comparison list is rather small, I'm currently trying this:
- (BOOL) isStringInList:(NSString *)testString{
if ([testString caseInsensitiveCompare:#"string1"] == NSOrderedSame)
return YES;
else if ([testString caseInsensitiveCompare:#"string2"] == NSOrderedSame)
return YES;
else if ([testString caseInsensitiveCompare:#"string3"] == NSOrderedSame)
return YES;
return NO;
}
This obviously does not scale well if I have many strings to compare against. I'd prefer more of a method signature like this -(BOOL) isString:(NSString *)testString inList:(NSString *)listString where listString is a space-separated string of keywords.
Any thoughts on how to improve performance would be appreciated.
The most performant way is to construct an NSSet of the strings you want to compare against and use -member: to test. Once the set is constructed, this will be a constant-time test. If you have a space-separated list to start with, you can use
NSSet *set = [NSSet setWithArray:[listOfWords componentsSeparatedByString:#" "]]
Constructing the set will be linear on the size of the input string. If your set is the same every time, you can construct it once and hold on to the result. To do the actual test you can use
[set member:myWord]
If the result is nil, your word isn't in the set. If it's non-nil, it is. Note, this is a case-sensitive search. If you need case-insensitivity, then you should either lowercase or uppercase both the list of words and the input word before performing your test.
- (BOOL)isString:(NSString*)testString inList:(NSString*)listString
{
BOOL result = NO;
if (testString != nil)
{
NSRange range = [listString rangeOfString:testString];
result = (range.location != NSNotFound);
}
return result;
}
- (BOOL)isString:(NSString *)testString inList:(NSString *)spaceSeparatedStrings
{
NSArray *list = [spaceSeparatedStrings componentsSeparatedByString:#" "];
return [list containsObject:testString];
}
Note: the above will be case-sensative, unlike your example. For case-insensative, you will probably have to iterate over some portion of the NSArray.
According to this, containsObject is more efficient than I would have guessed. Good news.
A binary search tree might be better, but obviously, that would take some work.

NSString internals - how does length works?

I've a question about NSString internals.
I want to check a string length and basically I wanted to know if a NSString knows its length / count each time / count & cache the result.
Should I store it's length and compute or call the length method each time ?
To test a string I can test against nil OR ask for it's length.
if (str != nil) {
// compute
}
if ([str length]) {
// compute
}
Which one is the fastest ?
Which one is the more memory efficient ?
Thanks
Checking for nil ("no object") is most definitely not the same as sending the length message to the (NSString) object. Only one of the conditional checks is valid to test for an "empty" string. (An "empty" string is an object and, therefore, not nil.)
The bigger question is: does NSString store a length or is it sentinel-terminated (like a "normal c string")? NSString stores the length as an internal property so it, length, is as O(1) operation.
Happy coding.
Here is how CFStringGetLength works:
(from http://opensource.apple.com/source/CF/CF-550.43/CFString.c)
/* Returns length; use __CFStrLength2 if contents buffer pointer has already been computed.
*/
CF_INLINE CFIndex __CFStrLength(CFStringRef str) {
if (__CFStrHasExplicitLength(str)) {
if (__CFStrIsInline(str)) {
return str->variants.inline1.length;
} else {
return str->variants.notInlineImmutable1.length;
}
} else {
return (CFIndex)(*((uint8_t *)__CFStrContents(str)));
}
}
So it should be O(1) for all cases.
The two -- testing a NSString pointer for nil and testing the length of an NSString -- are not in any way equivalent. An NSString object with a zero length can exist, and a pointer to it will not compare equal to nil.
To my knowledge (and I'd be quite surprised to discover I was wrong), the length of an NSString is stored within the object as an efficiently-referenced property. Caching the length would generally be unnecessary complexity.
NSString is immutable class, so the length stays the same all of the time.
Addendum: Testing against [string length] evaluates to 0/nil/NO in both cases (string being nil and string having zero length).

ObjectiveC Parse Integer from String

I'm trying to extract a string (which contains an integer) from an array and then use it as an int in a function. I'm trying to convert it to a int using intValue.
Here's the code I've been trying.
NSArray *_returnedArguments = [serverOutput componentsSeparatedByString:#":"];
[_appDelegate loggedIn:usernameField.text:passwordField.text:(int)[[_returnedArguments objectAtIndex:2] intValue]];
I get this error:
passing argument 3 of 'loggedIn:::' makes pointer from integer
without a cast
What's wrong?
I really don't know what was so hard about this question, but I managed to do it this way:
[myStringContainingInt intValue];
It should be noted that you can also do:
myStringContainingInt.intValue;
You can just convert the string like that [str intValue] or [str integerValue]
integerValue
Returns the NSInteger value of the receiver’s text.
(NSInteger)integerValue
Return Value
The NSInteger value of the receiver’s text, assuming a decimal representation and skipping whitespace at the beginning of the string. Returns 0 if the receiver doesn’t begin with a valid decimal text representation of a number.
for more information refer here
NSArray *_returnedArguments = [serverOutput componentsSeparatedByString:#":"];
_returnedArguments is an array of NSStrings which the UITextField text property is expecting. No need to convert.
Syntax error:
[_appDelegate loggedIn:usernameField.text:passwordField.text:(int)[[_returnedArguments objectAtIndex:2] intValue]];
If your _appDelegate has a passwordField property, then you can set the text using the following
[[_appDelegate passwordField] setText:[_returnedArguments objectAtIndex:2]];
Basically, the third parameter in loggedIn should not be an integer, it should be an object of some kind, but we can't know for sure because you did not name the parameters in the method call. Provide the method signature so we can see for sure. Perhaps it takes an NSNumber or something.
Keep in mind that international users may be using a decimal separator other than . in which case values can get mixed up or just become nil when using intValue on a string.
For example, in the UK 1.23 is written 1,23, so the number 1.777 would be input by user as 1,777, which, as .intValue, will be 1777 not 1 (truncated).
I've made a macro that will convert input text to an NSNumber based on a locale argument which can be nil (if nil it uses device current locale).
#define stringToNumber(__string, __nullable_locale) (\
(^NSNumber *(void){\
NSLocale *__locale = __nullable_locale;\
if (!__locale) {\
__locale = [NSLocale currentLocale];\
}\
NSString *__string_copy = [__string stringByReplacingOccurrencesOfString:__locale.groupingSeparator withString:#""];\
__string_copy = [__string_copy stringByReplacingOccurrencesOfString:__locale.decimalSeparator withString:#"."];\
return #([__string_copy doubleValue]);\
})()\
)
If I understood you correctly, you need to convert your NSString to int? Try this peace of code:
NSString *stringWithNumberInside = [_returnedArguments objectAtIndex:2];
int number;
sscanf([stringWithNumberInside UTF8String], "%x", &flags);

NSNumber, Setting and Retrieving

I'm messing around with NSNumber for an iPhone app, and seeing what I can do with it. For most of my variables, I simple store them as "int" or "float" or whatnot. However, when I have to pass an object (Such as in a Dictionary) then I need them as an Object. I use NSNUmber. This is how I initialize the object.
NSNumber *testNum = [NSNumber numberWithInt:varMoney];
Where "varMoney" is an int I have declared earlier in the program. However, I have absolutely no idea how to get that number back...
for example:
varMoney2 = [NSNumber retrieve the variable...];
How do I get the value back from the object and set it to a regular "int" again?
Thanks!
(Out of curiosity, is there a way to store "int" directly in an Objective-C dictionary without putting it in an NSNumber first?)
You want -intValue, or one of its friends (-floatValue, -doubleValue, etc.). From the docs:
intValue Returns the receiver’s value
as an int.
- (int)intValue
Return Value The receiver’s value as
an int, converting it as necessary.
The code would be:
int varMoney2 = [testNum intValue];
NSNumber *testNum = [NSNumber numberWithInt:varMoney];
/* Then later... */
int newVarMoney = [testNum intValue];