Invalid floating point comparison in Objective C - objective-c

I have a weird dilema that I can't seem to place a finger on the issue and would like some outside assistance when trying to figure out the issue. I have a NSString value that I read in from a textbox and I convert it into a NSNumber. This works well and I get my value. Then I take my new number and I want to compare it with an array of 4 floating point numbers. However, when I try to compare I never get the proper results and this is where I am pulling my hair out. Below is a small snippet of code explaining my situation:
// THE FIRST IF STATEMENT IS WHAT GETS SELECTED
// newValue = 0.93
// colorRange = {0.10, 0.20, 0.80, 0.90 }
NSNumberFormatter *format = [[NSNumberFormatter alloc] init];
[format setNumberStyle:NSNumberFormatterDecimalStyle];
NSNumber *newValue = [format numberFromString:value];
[format release];
if (newValue < [colorRange objectAtIndex:0]) {
// Red background
selectedButton.backgroundColor = [UIColor redColor];
}
else if (newValue > [colorRange objectAtIndex:0] && newValue < [colorRange objectAtIndex:1]) {
// White background
selectedButton.backgroundColor = [UIColor whiteColor];
}
else if (newValue > [colorRange objectAtIndex:1] && newValue < [colorRange objectAtIndex:2]) {
// Black background
selectedButton.backgroundColor = [UIColor blackColor];
}
else if (newValue > [colorRange objectAtIndex:2] && newValue < [colorRange objectAtIndex:3]) {
// Blue background
selectedButton.backgroundColor = [UIColor blueColor];
}
else {
// Green background
selectedButton.backgroundColor = [UIColor greenColor];
}
What I am trying to do is see where my input value lies within my percentage range and select a color based on that information. If there is a more optimal way of doing this please let me know.

You can not compare NSNumbers directly like that, as you are comparing the values of their pointers. Instead, use the compare method of NSNumber to compare them like this:
if ([newValue compare:[colorRange objectAtIndex:0]] == NSOrderedAscending) {
// Red background
selectedButton.backgroundColor = [UIColor redColor];
}
...

I would do it in simple way:
if ([newValue floatVaue] < [colorRange objectAtIndex:0] floatValue])
And it is.

This (and the others like it):
newValue < [colorRange objectAtIndex:1]
Compares the pointer newValue to the pointer [colorRange objectAtIndex:1]. So it'll evaluate to non-zero if newValue happens to be lower down in memory.
Having been beaten to saying that by at least two posters, I'll take the time to propose the more compact method:
NSArray *backgroundColours = #[ [UIColor redColor], [UIColor whiteColor], ...];
NSUInteger index = 0;
for(NSNumber *colour in colorRange)
{
if([newValue compare:colour] == NSOrderedAscending)
{
selectedButton.backgroundColor = [backgroundColours objectAtIndex:index];
break;
}
index++;
}

You cannot compare NSNumber* objects using the < or > operators: it compares pointers, giving you arbitrary results. Use the compare: method instead:
if ([newValue compare:[colorRange objectAtIndex:0]] == NSOrderedAscending) ...
NSOrderedAscending means that the receiver is less than the argument
NSOrderedDescending means that the receiver is greater than the argument
NSOrderedSame means that the receiver is equal to the argument

As everybody else said you cannot compare pointers like that, just variables.
You could use
if ([newValue floatValue]<[[color objectAtIndex:0] floatValue]

Related

Obj C - Word Line Truncation

I want to show my long text in a UILabel. But, My design having small size of frame for that UILabel. So, i want to truncate my long text like this[see below]:
Ex:
UILabel Text: "I want to show my long text in a UILabel"
Recent Result: [Using lineBreakMode:]
I want to s........a UILabel
I want to s.....
I want to s
Expected Result: "I want to...."
[Note:  I want truncation after the word which can fit within their label frame.]
I hope that you can sense about my expected result. Sorry for my English!.
I am not sure whether there is API for this. If you are not getting answers. You can use the below logic to achieve This is not optimum logic.
-(NSString *) textThatFits:(NSString *) originalText font:(UIFont *) font
{
NSArray *array = [originalText componentsSeparatedByString:#" "];
NSString *stringThatFits;
for (int i = 0 ; i < [array count]; i++)
{
NSString *tempString = [stringThatFits stringByAppendingFormat:#" %#", array[i]];
CGRect boundingRect = [tempString boundingRectWithSize:CGSizeMake(999, 999)
options:NSStringDrawingUsesLineFragmentOrigin
attributes:#{NSFontAttributeName:font}
context:nil];
if (boundingRect.size.width < self.yourLabel.width) {
return stringThatFits;
}
else
{
stringThatFits = tempString;
}
}
return stringThatFits;
}
According to the OP excepted result and the #Naveen logic, I develop the code which works but with some restriction.
Restriction:
Sometimes, extending that label width by adding 10.0 value.
don't give any spaces at begin and end of label text.
Design:
Controls: A UIButton, UITextField, UILabel
Type your text in the UITextField.
Do Action to display your excepted result in the UILabel.
Code:
-(IBAction)actionDisplayTextWithTruncate:(id)sender{
lblFinalResult.frame=CGRectMake(60, 345, 55, 21);
NSString *strGivenText, *strFuncResult, *stringThatFits;
int spaceCount;
//Custom Truncate Function
strGivenText=txtFldGivenText.text;
arrForGivenText_Words = [strGivenText componentsSeparatedByString:#" "];
stringThatFits=#"";
strFuncResult=#"";
for (int i = 0 ; i < [arrForGivenText_Words count]; i++)
{
/* must follow #" %#" - a space before %# */
NSString *tempString = [stringThatFits stringByAppendingFormat:#" %#", arrForGivenText_Words[i]];
CGRect boundingRect = [tempString boundingRectWithSize:CGSizeMake(999, 999) options:NSStringDrawingTruncatesLastVisibleLine attributes:#{NSFontAttributeName:lblFinalResult.font} context:nil];
if (boundingRect.size.width > lblFinalResult.frame.size.width) //Breakpoint1
{
if(i==0){
[lblFinalResult setText:#"..."];
return;
}
else{
for (int j = 0 ; j < i; j++)
{
strFuncResult = [strFuncResult stringByAppendingFormat:#"%# ",arrForGivenText_Words[j]];
NSLog(#"Present_a1: %#", strFuncResult);
}
strFuncResult = [strFuncResult substringToIndex:strFuncResult.length-(strFuncResult.length>0)];
lblFinalResult.frame= CGRectMake(lblFinalResult.frame.origin.x, lblFinalResult.frame.origin.y, lblFinalResult.frame.size.width+10, lblFinalResult.frame.size.height);
strFuncResult=[strFuncResult stringByAppendingString:#"..."];
[lblFinalResult setText:strFuncResult];
return;
}
}
else{
stringThatFits = tempString;
NSLog(#"Present_a2: %#", stringThatFits);
}
}
[lblFinalResult setText:stringThatFits];
}

NSMutableArray inside setTitle

I've stored 4 unique numbers inside an NSMutableArray from 1-4. i've done that by using this code:
storeArray = [[NSMutableArray alloc] init];
BOOL record = NO;
int x;
for (int i=1; [storeArray count] < 4; i++) //Loop for generate different random values
{
x = arc4random() % 4;//generating random number
if(i==1)//for first time
{
[storeArray addObject:[NSNumber numberWithInt:x]];
}
else
{
for (int j=0; j<= [storeArray count]-1; j++)
{
if (x ==[[storeArray objectAtIndex:j] intValue])
record = YES;
}
if (record == YES)
{
record = NO;
}
else
{
[storeArray addObject:[NSNumber numberWithInt:x]];
}
}
}
I can then print the numbers out using storeArray[1] and so on.
the problem is i want to print the numbers inside this.
[option1 setTitle:questions[r][storeArray[0]] forState: UIControlStateNormal];
[option2 setTitle:questions[r][storeArray[1]] forState: UIControlStateNormal];
[option3 setTitle:questions[r][storeArray[2]] forState: UIControlStateNormal];
[option4 setTitle:questions[r][storeArray[3]] forState: UIControlStateNormal];
How can i do this?, cause i when i do this i get thread sigbrt error?
The problem is that your algorithm is faulty and when there are collisions because you are trying to keep the numbers unique, you don't record anything so your array might not always be the expected length. Actually there is a 91% chance of this happening in your case so it looks like it happens all the time.
Instead of trying to write your own algorithm, just use the existing classes. Simply use an NSSet to guarantee the uniqueness of the numbers in your array.
NSMutableSet *set = [[NSMutableSet alloc] init];
while(set.count < 4) {
int x = arc4random() % 4;
[set addObject:[NSNumber numberWithInteger:x]];
}
NSArray * storeArray = [set allObjects];

Custom NSFormatter in Objective C

I am trying to write my own custom formatter in Objective C by subclassing NSNumberFormatter. Specifically what I'd like to do is make a number turn red if it is above or below certain values. The apple documentation says
For example, if you want negative financial amounts to appear in red, you have this method return a string with an attribute of red text. In attributedStringForObjectValue:withDefaultAttributes: get the non-attributed string by invoking stringForObjectValue: and then apply the proper attributes to that string.
Based on this advice I implemented the following code
- (NSAttributedString*) attributedStringForObjectValue: (id)anObject withDefaultAttributes: (NSDictionary*)attr;
{
NSMutableAttributedString *attrString = [[NSMutableAttributedString alloc] initWithString:[self stringForObjectValue:anObject]];
if ([[attrString string] floatValue] < -20.0f) {
[attrString addAttribute:#"NSForegroundColorAttributeName" value:[NSColor redColor] range:NSMakeRange(0, 10)];
return attrString;
} else return attrString;
}
But when I test this all it does is freeze my application. Any advice would be appreciated. Thanks.
I believe this has something to do with your NSRange that you create. I believe your length (10 in your example) is out of bounds. Try getting the length of the string that you use to initialize your NSMutableAttributedString.
For example:
- (NSAttributedString*) attributedStringForObjectValue: (id)anObject withDefaultAttributes: (NSDictionary*)attr;
{
NSString *string = [self stringForObjectValue:anObject];
NSMutableAttributedString *attrString = [[NSMutableAttributedString alloc] initWithString:string];
NSInteger stringLength = [string length];
if ([[attrString string] floatValue] < -20.0f)
{
[attrString addAttribute:#"NSForegroundColorAttributeName" value:[NSColor redColor] range:NSMakeRange(0, stringLength)];
}
return attrString;
}
Here is how I was finally able to implement this. To make it more visible when a number is negative, I decided to make the background of the text red with white text. The following code does work in a NSTextField cell. I'm not sure why the code in my question (and the answer) does not work, addAttribute should work.
- (NSAttributedString *)attributedStringForObjectValue:(id)anObject withDefaultAttributes: (NSDictionary *)attributes{
NSString *string = [self stringForObjectValue:anObject];
NSMutableAttributedString *attrString = [[NSMutableAttributedString alloc] initWithString:string];
NSInteger stringLength = [string length];
if ([[attrString string] floatValue] < 0)
{
NSDictionary *firstAttributes = #{NSForegroundColorAttributeName: [NSColor whiteColor],
NSBackgroundColorAttributeName: [NSColor blueColor]};
[attrString setAttributes:firstAttributes range:NSMakeRange(0, stringLength)];
}
return attrString;
}

UITextChecker without proper nouns

I'm exercising the UITextChecker class to do a quick check on a string for a word-spelling game. Works a little TOO well. Unfortunately, as far as I can tell, the only methods that operate on this class return "correct" words that also include proper nouns. I would like to check my strings against a list of common words that do NOT include proper nouns. Here's my code so far:
//Test the answer for a word
UITextChecker *checker = [[UITextChecker alloc] init];
NSString *testString = wordString;
NSRange range = NSMakeRange(0,0);
range = [checker rangeOfMisspelledWordInString:[testString lowercaseString]
range:NSMakeRange(0, [testString length])
startingAt:0
wrap:NO
language:#"en_US"];
if (range.location == NSNotFound) {
spelledWord = YES;
} else {
spelledWord = NO;
}
Any help would be appreciated!
Not sure if this is the easiest way but you could put a second condition. First store an array with proper nouns (or other words you don't want) elsewhere in your code do a search on Google if you can't think of them. (I've adapted this slightly from a method i use)
if (range.location == NSNotFound) {
int i = 1;
NSString *p;
foundrand = FALSE;
if ([[MyArray sharedKelArray].Myarray count] >2){
////NSLog(#"GOTTEN - %d", choosennumber);
while(i<[[MyArray sharedKelArray].Myarray count])//would check that if equal
{
p = [[[MyArray sharedKelArray].Myarray objectAtIndex:i] NSString];
NSLog(#"Checking word - %d",p);
if (testString == p){
NSLog(#"Matched");
spelledWord = NO;
i = 5 + [[MyArray sharedKelArray].Myarray count];
}
i+=1;
}
spelledWord = YES;
}
}
}

Sort Colors (Objective-C)

I'm doing this sort of thing:
- (NSArray*)colors {
float divisor = .3333;
NSMutableArray *retVal = [NSMutableArray array];
for (float one=0; one <= 1.0f; one += divisor) {
for (float two = 0; two <= 1.0f; two += divisor) {
for (float three = 0; three <= 1.0f; three += divisor) {
UIColor *color = [UIColor colorWithRed:one green:two blue:three alpha:.5];
// also bad
// UIColor *color = [UIColor colorWithHue:one saturation:two brightness:three alpha:.5];
[retVal addObject:color];
}
}
}
return retVal;
}
and, as I suspected, the colors come out horribly out of order (to the eye). The reds are not with the reds, purples not with the purples, etc.
Is there no easy way to create a list of diverse colors, nicely grouped according to human criteria like, "that looks blue?"
This worked quite well. It will NOT help the fact that you have a lot of repeated colors. See below:
NSArray *sorted = [[dict allValues] sortedArrayUsingComparator:^NSComparisonResult(UIColor* obj1, UIColor* obj2) {
float hue, saturation, brightness, alpha;
[obj1 getHue:&hue saturation:&saturation brightness:&brightness alpha:&alpha];
float hue2, saturation2, brightness2, alpha2;
[obj2 getHue:&hue2 saturation:&saturation2 brightness:&brightness2 alpha:&alpha2];
if (hue < hue2)
return NSOrderedAscending;
else if (hue > hue2)
return NSOrderedDescending;
if (saturation < saturation2)
return NSOrderedAscending;
else if (saturation > saturation2)
return NSOrderedDescending;
if (brightness < brightness2)
return NSOrderedAscending;
else if (brightness > brightness2)
return NSOrderedDescending;
return NSOrderedSame;
}];
You can access the components (HSBA) like this in iOS 4.x:
CGFloat *components = (CGFloat *)CGColorGetComponents([color CGColor]);
float hue = components[0];
float saturation = components[1]; // etc. etc.
To avoid repeating colors: you can put the elements in an NSMutableDictionary, keyed on something like their hue-saturation-brightness (each rounded to the nearest .10)... then you get the array from THAT, and then sort.
I think using [UIColor colorWithHue:saturation: brightness: alpha:] is your best bet. If you fix saturation, brightness and alpha and just use Hue you'll get all the colours in order.
Check out the wiki for HSB for more information.
for (float hsb = 0; hsb <= 1.0f; hsb += divisor) {
UIColor *color = [UIColor colorWithHue:hsb saturation:1.0f brightness:1.0f alpha:.5f];
[retVal addObject:color];
}