Objective-C Condtions operators weirdness - objective-c

Okay here's the damned thing:
- (void)setMinimumNumberOfSides:(NSNumber *)newMinimumNumberOfSides {
if (newMinimumNumberOfSides != minimumNumberOfSides) {
NSNumber *minimum = [[NSNumber alloc] initWithInt:(int)2];
if (newMinimumNumberOfSides > minimum) {
[newMinimumNumberOfSides retain];
[minimumNumberOfSides release];
minimumNumberOfSides = newMinimumNumberOfSides;
} else {
NSLog(#"setMinimumNumberOfSides: Invalid number of sides: %# is smaller than the minimum of %# allowed.",
newMinimumNumberOfSides, minimum);
}
[minimum release];
[newMinimumNumberOfSides release];
}
}
There's something weird going on in there! The problem is my if (newMinimumNumberOfSides > minimum) {} condition. Even if newMinimumNumberOfSides is greated than minimum it goes into the else statement.
I did:
NSNumber *minimum = [[NSNumber alloc] initWithInt:(int)6];
[polygon setMinimumNumberOfSides:minimum];
which is way greater than 2. And I receive my error message...
I tried to NSLog those two, and it gives me the right numbers... So what's going on with this?
Thanks a lot!

I think you need to change your if statement to:
if ([newMinimumNumberOfSides intValue] > [minimum intValue])
NSNumber is an object, so you have to get its integer value before you can start using it in comparisons.

You need to use the following method to compare NSNumber objects:
- (NSComparisonResult)compare:(NSNumber *)aNumber
but better yet just convert them to c ints: [myNSNumberValue inValue]

Related

how to test object equality using xcttest?

My method returns a NSNumber* and I want to unit test this method. Since my actual return value is NSNumber*, I create a new expected value of NSNumber*, but it fails. Here is the code:
NSNumber *cRating = [movie getRating:ratingDictionary ratingType:criticRating];
XCTAssertEqualObjects(cRating, [[NSNumber alloc]initWithInt:70], #"");
The error is:
[SFModelTest testGetCriticRatingMethod] failed: ((cRating) equal to ([[NSNumber alloc]initWithInt:70])) failed: ("70") is not equal to ("70")
Since it is saying "70" is not equal to "70", I am guessing it has to do with alloc init. Some pointer stuff that is not equal. Can somebody please help? Thank you.
Edit for comment: adding getRating method
- (NSNumber *)getRating:(NSDictionary *)movieDic ratingType:(enum RatingsEnum) rating{
NSNumber *result = 0;
NSNumber *ratingNum = 0;
switch (rating) {
case userRating:
{
ratingNum = [movieDic objectForKey:#"audience_score"];
break;
}
case criticRating:
{
ratingNum = [movieDic objectForKey:#"critics_score"];
break;
}
default:
break;
}
if(ratingNum && ratingNum > 0)
{
result = ratingNum;
}
return result;
}
The method returns NSNumber. And my test is:
NSNumber *cRating = [movie getRating:ratingDictionary ratingType:criticRating];
XCTAssertEqualObjects(cRating, [[NSNumber alloc]initWithInt:70], #"");
When I do a class NSLOG, it returns __NSCFConstantString. I am confused now.
I think that you're doing something wrong because XCTAssertEqualObjects(#(1), #(1), #"Not equal."); or XCTAssertEqualObjects([NSNumber numberWithInt:1], [NSNumber numberWithInt:1], #"Not equal."); if you are not familiar with literals, will pass.
You should checkout the getRating:ratingType: method to see which type of object it returns.
Try adding a breakpoint just before that XCTAssertEqualObjects and inspect the cRating instance.

How to find out whether input is number or text in objective-c?

I've tried to search, but I think my google is skill is not good enough, so I'm asking a help from people. I'm scanning through a string and taking each element. I need to find out whether it's number or text. I did my checking in that way:
// Try to convert to double
#try{
double whatever=[myString doubleValue];
// If text is stored in myString, then it should throw an exception
} #catch (NSException *e){
// Do whatever I need, but here I know that it's text, not a number
}
However I found out that Objective-C doesn't throw an exception, it just returns 0. I can't rely on the fact that user won't use zero as an input, what should I do?
Thanks in advance and I'm pretty sure there are treads like this, I just didn't find them...
Try this:
NSNumberFormatter *formatter = [[NSNumberFormatter alloc] init];
[formatter setNumberStyle:NSNumberFormatterDecimalStyle];
NSNumber *number = [formatter numberFromString:myString];
if (number) {
// it's a number
} else {
// it's not a number
}
Convert to double and back to string. If it matches the source, then it was a double.
Careful with leading and trailing spaces.
You can use the class NSScanner to find out if you got a valid double with this method :
- (BOOL)scanDouble:(double *)doubleValue
once you have initialized your scanner with your string.
Why (double *) ?
Because you want the method to return to you 2 informations, the doubleValue and is it a valid double. The latter is given by the BOOL and for the former only a Pointer can get you a value out of a method call (apart from the return value)
Parameters
doubleValue
Upon return, contains the scanned value. Contains HUGE_VAL or –HUGE_VAL on overflow, or 0.0 on underflow.
Return Value
YES if the receiver finds a valid floating-point representation, otherwise NO.
NSMutableString *stringElement = [NSMutableString stringWithCapacity:[yourString length]];
for (int i=0; i<[yourString length]; i++) {
if (isdigit([stringElement characterAtIndex:i])) {
//is digit
}
}
Example:
NSError* error;
NSString* string=#"10";
NSNumberFormatter* formatter=[NSNumberFormatter new];
formatter.numberStyle= NSNumberFormatterDecimalStyle; // set whatever style you need
NSNumber* number;
if([formatter getObjectValue: &number forString: string errorDescription: &error])
{
// You got the number
NSLog(#"%#",number);
}
else
{
// haven't got the number, the string is invalid
NSLog(#"%#",error);
}

Method returning 0

I'm doing the foundation calculator homework from the cs193p course, and my
+evaluateExpression:usingVariables: method doesn't work. It always returns 0.
Here's my method:
+ (double)evaluateExpression: (id)anExpression usingVariablevalues: (NSDictionary *)variables {
CalculatorBrain *worker = [[[CalculatorBrain alloc] init] autorelease];
double returnValue = 10.0;
if ([anExpression isKindOfClass:[NSMutableArray class]]) {
for (id term in anExpression) {
NSLog(#"%f", returnValue); // breakpoint
if ([term isKindOfClass:[NSString class]]) { // string
if ([term hasPrefix:#"%"] && [term length] == 2) { // variable
double value = [(NSNumber *)[variables objectForKey:[term substringFromIndex:1]] doubleValue];
NSLog(#"Variable: %#, value: %d", [term substringFromIndex:1], value);
[worker setOperand:value];
}
else if ([term length] == 1) { // operation
returnValue = [worker performOperation:term];
}
else {
NSLog(#"Invalid expression.\n\tMultiple character operation found: %#", term);
}
}
else if ([term isKindOfClass:[NSNumber class]]) { // operand
double value = [term doubleValue];
[worker setOperand:value];
}
else {
NSLog(#"Invalid expression.\n\tWrong type in expression: %#, The value is: %#.",[term class], term); // Wrong type in expression
}
}
}
else {
NSLog(#"Invalid expression.\n\tThe expression is of the wrong type: %#.", [anExpression class]); // expression is of wrong type
}
//returnValue = worker.operand;
return returnValue;
}
Any hints? it always returns 0.
/* Ouput from Console */
2012-06-27 20:01:05.487 Calculator[2823:207] 0
2012-06-27 20:01:05.488 Calculator[2823:207] 0
2012-06-27 20:01:05.489 Calculator[2823:207] 0
2012-06-27 20:01:05.490 Calculator[2823:207] Variable: x, value: 0
2012-06-27 20:01:05.490 Calculator[2823:207] 0
2012-06-27 20:01:05.491 Calculator[2823:207] 0
2012-06-27 20:01:05.491 Calculator[2823:207] 0
Note: I set returnValue to 10.0 at the beginning to check if it is getting changed at all.
Update:
I found out that it gets 0 from the dictionary. I think the calling code is the cause:
- (IBAction) performSampleExpression {
NSMutableArray *expr = [[NSMutableArray alloc] init];
[expr addObject:[NSNumber numberWithDouble:3.0]];
[expr addObject:#"+"];
[expr addObject:#"%x"];
[expr addObject:#"*"];
[expr addObject:[NSNumber numberWithDouble:4.0]];
NSDictionary *varsdict = [NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithDouble:10.0], #"x", nil];
double result = [CalculatorBrain evaluateExpression:expr usingVariablevalues:varsdict];
if (!result) NSLog(#"result = nil");
NSLog(#"%f", result);
display.text = [NSString stringWithFormat:#"%f", result];
[expr release];
}
Result isn't nil though.
Update 2:
Using the debugger (nice hint. This might solve it.) I found something strange:
On this line: (first time)
returnValue = worker.operand;
It says returnValue is still 10, and not three (worker.operand IS).
Is the assignment failing, or is this how it should be? (Just wondering).
UPDATE 3:
Okay there is something very strange going on here: I set a breakpoint on the return statement, the last line of +evaluateExpression:usingVariables:, and it says
returnValue = 4.
This means, the actual problem lies in -performSampleExpression. What am I doing wrong?
UPDATE 4:
Changing #"%d", double into #"%f", double helped a lot. That explains the strange Console output. But, it solved it, because I updated the display like display [setText:#"%d", result]; what caused my double to be displayed as 0 due to a wrong cast.
I discovered this by using the debugger, so the one who suggested that practically solved it. (And I asked for hints, not for solutions. After all, homework is to learn from).
The possible issues can shown in:
returnValue = [worker performOperation:term];
and
returnValue = worker.operand;
You should stop debugger in this line (or line below) and watch how to your value of returnValue change.
You stop app clicking on position where it is on the screen, app stops, and then jump to next line with F6 (or Fn+F6). Below (in console) you can see the value.
EDIT
You could try this solution - Change allocation to:
CalculatorBrain *worker = [[[CalculatorBrain alloc] init] autorelease];
And delete line:
[worker release];
This release right before return may couse the problem without NSCopying #protocol.
Autorelease and NSCopying
For better understanding compile this code:
NSMutableArray *arrOne = [[NSMutableArray alloc] initWithObjects:#"1",#"2", nil];
NSMutableArray *arrTwo = [[NSMutableArray alloc] init];
arrTwo = arrOne;
[arrOne addObject:#"3"]; //After that arrTwo "shold" be 1,2 and arrOne 1,2,3. No! There both 1,2,3!
for(int i=0;i<[arrTwo count];i++)
NSLog(#"%#",[arrTwo objectAtIndex:i]);
So you may consider how you assign a variable. In above example releasing memory shouldn't effect return values, but by using autorelease with return object you don't have to assign anything.
Have you tried stepping through the code a line at a time and examining the variable values?
I'm seeing a little memory leak in your code:
so, instead of this:
[worker release];
try this line: [worker autorelease];
I'm not sure it caused the problem but your version definitely does not look good.

Add a (double) variable to NSMutableArray

I have a user input variable and i want to add that to an array. The firstStore is a BOOL type t determine if the array has been initialize. So the first time the STORE was called, it would initialize the array. I tried to make num equal to the operand (which is a double) by masking it NSNumber but that doesn't seem to work because i have this error "NSNumber may not respond to +operand", also the program crashes when it hits the line [memArray addObject:num]. I'm new at this stuff so any help would be greatly appreciated.
else if ([operation isEqual:#"Store"]) {
if(!firstStore){
memArray = [[NSMutableArray alloc] init];
NSNumber *num = [NSNumber operand];
[memArray addObject:num];
firstStore = YES;
} else {
//NSNumber *num = [NSNumber operand];
//[memArray addObject:num];
}
}
Try changing [NSNumber operand] to [NSNumber numberWithDouble:operand].
"NSNumber may not respond to +operand" means what is says: There is no such class-method operand. What was it supposed to do?
You dont need a bool to track if memArray is initialized. use:
if(!memArray)
or
if (memArray == nil)

Weird cocoa bug?

Hey folks, beneath is a piece of code i used for a school assignment.
Whenever I enter a word, with an O in it (which is a capital o), it fails!
Whenever there is one or more capital O's in this program, it returns false and logs : sentence not a palindrome.
A palindrome, for the people that dont know what a palindrome is, is a word that is the same read left from right, and backwards. (e.g. lol, kayak, reviver etc)
I found this bug when trying to check the 'oldest' palindrome ever found: SATOR AREPO TENET OPERA ROTAS.
When I change all the capital o's to lowercase o's, it works, and returns true.
Let me state clearly, with this piece of code ALL sentences/words with capital O's return false. A single capital o is enough to fail this program.
-(BOOL)testForPalindrome:(NSString *)s position:(NSInteger)pos {
NSString *string = s;
NSInteger position = pos;
NSInteger stringLength = [string length];
NSString *charOne = [string substringFromIndex:position];
charOne = [charOne substringToIndex:1];
NSString *charTwo = [string substringFromIndex:(stringLength - 1 - position)];
charTwo = [charTwo substringToIndex:1];
if(position > (stringLength / 2)) {
NSString *printableString = [NSString stringWithFormat:#"De following word or sentence is a palindrome: \n\n%#", string];
NSLog(#"%# is a palindrome.", string);
[textField setStringValue:printableString];
return YES;
}
if(charOne != charTwo) {
NSLog(#"%#, %#", charOne, charTwo);
NSLog(#"%i", position);
NSLog(#"%# is not a palindrome.", string);
return NO;
}
return [self testForPalindrome:string position:position+1];
}
So, is this some weird bug in Cocoa?
Or am I missing something?
B
This of course is not a bug in Cocoa, as you probably knew deep down inside.
Your compare method is causing this 'bug in Cocoa', you're comparing the addresses of charOne and charTwo. Instead you should compare the contents of the string with the isEqualToString message.
Use:
if(![charOne isEqualToString:charTwo]) {
Instead of:
if(charOne != charTwo) {
Edit: tested it in a test project and can confirm this is the problem.
Don't use charOne != charTwo
Instead use one of the NSString Compare Methods.
if ([charOne caseInsensitiveCompare:charTwo] != NSOrderedSame)
It may also have to do with localization (but I doubt it).