NSArray in if statement strange behaviour - objective-c

i have the following two pieces of code which i think should be identical
int temp = [[[myArray objectAtIndex:iIndex] objectAtIndex:jIndex] state];
if (temp > 0)
{
NSLog(#"TEST: %d",temp);
}
if ([[[myArray objectAtIndex:iIndex] objectAtIndex:jIndex] state] > 0)
{
NSLog(#"TEST: %d",temp);
}
state is just an int in the objects in the array with accessor like:
#property (assign)int state;
but when state is negative, the first version works (no output), but the second version outputs (for example) "TEST: -4" (?!)
is there any obvious reason why they might be different?

Since -objectAtIndex: returns an id, the compiler will not be able to know what -state should return. If you did not import the header that declares state first, or if the property state has ambiguous declaration (e.g. another class has declared #property(retain) id state before your class is imported), then the compiler may infer a wrong type for -state.
If it infers id, for instance, as all pointers are nonnegative, -4 will be implicitly viewed as 0xFFFFFFFC, thus the > 0 condition passes.
But for code 1, you have specified that temp is an int, so even if the return value of the call is 0xFFFFFFFC, it will be cast back to a signed value (-4), hence the condition fails.
The safest approach is to specify the type of -objectAtIndex:, i.e.
Foo* obj = [[myArray objectAtIndex:iIndex] objectAtIndex:jIndex];
if (obj.state > 0) {
...

I I understand it right, and the two if's are NOT in the same method, then the second one prints an unassigned variable. the fix should go like this:
if ((temp = [[[myArray objectAtIndex:iIndex] objectAtIndex:jIndex] state]) > 0)
{
NSLog(#"TEST: %d",temp);
}

Related

Objective-C compile error: Invalid operands to binary expression

-(void)updateCharacterStatsForArmor:(RKArmor *)armor withWeapons:(RKWeapon *)weapon withHealthEffect:(int)healtheffect
{
if (armor != nil){
self.character.health = self.character.health - self.character.armor.health + armor.health;
self.character.armor = armor;
}
else if (weapon != nil){
// The problematic line:
self.character.damage = self.character.damage - self.character.weapon.damage + weapon.damage;
self.character.weapon = weapon;
}
else if (healtheffect != 0){
self.character.health = self.character.health + healtheffect;
}
else {
self.character.health = self.character.health + self.character.armor.health;
self.character.damage = *(self.character.damage + self.character.weapon.damage);
}
}
#end
The line with the error is marked in the code snippet. The error says invalid operand to binary expression int int*.
Would It be best to restart the whole thing?
You probably defined one of the damage properties you're using as an int* instead of int. Check your character and weapon classes for that. I'd suspect self.character.damage.
If the line you indicated really is the problem, it looks like you've probably declared the damage property of the character class to return int * instead of int. It's easy to make that mistake because properties that point to objects are always pointers. int, however, is not an object type, so there's usually not need to store a pointer to one in a property.
The line you say is a problem is:
self.character.damage = self.character.damage - self.character.weapon.damage + weapon.damage;
But later on you have:
self.character.damage = *(self.character.damage + self.character.weapon.damage);
It looks like this second line is some kind of attempt to avoid a compiler error, but it doesn't seem to make a lot of sense. You'd only dereference the result of the addition if you were doing pointer arithmetic, but that doesn't make much sense for a property called damage.
To fix all this, take a look at your character class declaration. You'll probably see something like:
#property(...) int *damage;
Remove that * and make sure the attribute is assign, like this:
#property(assign) int damage;
Also, it's not clear how pirates are involved. Perhaps ye have been a mite hasty in makin' yer query? Arrr!

Obj-c EXC_BAD_ECCESS error

I'm having a strange crash, at the 4th line below.
{
...
int exp = [[resourceCompletionReward objectAtIndex:experienceD] integerValue];
int xx = mySprite.x;
int yy = mySprite.y;
[self setupRisingText:exp withX:xx withY:yy];
...
}
-(void)setupRisingText:(int)risingValue withX:xx withY:yy {
...
}
When it tries to run the setupRising Text method it just crashes. Can't see anything wrong though?
What ever you do with xx and yy in setupRisingText::: they are treated as id (something like NSObject *, not exactly like that but similar)
So instead of int variables pointers to objects (any object, not just subclasses of NSObject) are accessed and dealt with. That is the default for any parameter without a type.
Use
-(void)setupRisingText:(int)risingValue withX:(int)xx withY:(int)yy {
...
}
instead.
BTW, if you used NSNumber you would have less of a problem here.
I am wondering, shouldn't your method look like this?
-(void)setupRisingText:(int)risingValue withX:(int)xx withY:(int)yy {
//NSLog(#"%d",risingValue+xx+yy);
}

Why use double parentheses in init methods, or is 1 == (1)?

What do parentheses do when evaluating some meaning?
I have faced this in code, when something is checked and they use
if ( (some condition that returns 1) )
{
code
}
So my question is, does this evaluate to true? I would think that it is always false since (1) does not return anything?
Edit: clarification, question is why double parenthesis in if? I know that 1 is true.
The additional parentheses are used when an assignment is used for its truth value. They allow the compiler to distinguish between
if ((var = expr))
which signals intentional combination of assignment and truth value test, and
if (var = expr)
as an unintentional misspelling of if (var == expr).
The convention, carried over from C and C++, is for the compilers to warn on if (var = expr) as a possible misspelling of if (var == expr). They don't warn on if ((var = expr)), because the extra set of parentheses signals to the compiler that the assignment was intended. As rob mayoff explains, clang has a special case not to warn for certain assignments to self, but for many coders the habit remained.
As others said, the generated code is exactly the same with and without the extra parens.
If you write,
if (self = [super init]) { // Warning
// ...
}
The compiler will give you a warning, because it thinks you might have mistyped = as ==. If you add a second set of parentheses, the warning goes away.
if ((self = [super init])) { // No warning
// ...
}
So the extra parentheses are there to make typos less likely. The parentheses do not change the value of the expression.
In general 0 equates to false, NOT 0 to true.
This link explains bool in objective-c: http://www.mindsizzlers.com/2010/04/objective-c-and-the-properties-of-bool/
true and false value of bool and int
boolean value of false is equivalent to the int value of 0.
boolean value of true is equivalent to the int value of non-zero (e.g. 1, 10, 3000, etc)
For example, consider an example of C code below:
bool bValue;
int nValue;
bValue = true;
nValue = 1;
if (bValue == nValue) {
printf("bValue and nValue are the same!\n");
}
// output: bValue and nValue are the same!
Wrapped with multiple parenthesis:
The following two snippets returns exactly the same results.
if ((((((((((((((((((((1)))))))))))))))))))) {
printf("Hello World!\n");
}
returns the same result as:
if (1) {
printf("Hello World!\n");
}
Expression in if statement
Within your given if statement, you must have an expression that resolves to either true or false value. Please refer to this page for example of expression.

if statement comparing integers not working in objective c

I am trying to perform logic based on the values of two integers. Here I am defining my integers, and I also have NSLog so I can see if the values are correct when I run the code:
int theHikeFlag = (int)[theNewHikeFlag objectAtIndex:(theID-1)];
NSLog(#"theHikeFlag: %#",theHikeFlag);
int fromTheDB = [self.detailItem hikeFlag];
NSLog(#"fromTheDB: %d",fromTheDB);
And here is the logic:
if (theHikeFlag==1) {
hikeString=#"You have";
}
else if (theHikeFlag==0) {
hikeString=#"You have not";
}
else {
if (fromTheDB==1) {
hikeString=#"You have";
}
else {
hikeString=#"You have not";
}
}
As an example of how this code is working. When theHikeFlag=1 and fromTheDB=0, the code bypasses the if and the else if and goes straight to the else and sets hikeString="You have not". This means that my result is irrelevant of theHikeFlag and is based on the fromTheDB integer.
Since you cannot store ints in an array, the line
(int)[theNewHikeFlag objectAtIndex:(theID-1)];
is not doing what you think it should. You need to pull the data from NSNumber, not cast to int.
int theHikeFlag = [[theNewHikeFlag objectAtIndex:(theID-1)] intValue];
The reason why the log output is correct is a bit funny: you made two mistakes in a row! First, you re-interpreted a pointer as an int, and then you let NSLog re-interpret it as an object again by adding a format specifier %# that is incompatible with int, but works fine with pointers! Since the int value contains a pointer to NSNumber, NSLog produces the "correct" output.

Can an If Statement tell if an assignment was valid?

I have an object that returns a value if successful and false (or nil) if it failed.
i want to assign that value to a variable
if(var1 = [object foo])
{
//if the [object foo] returned a variable, goes here
}
else
{
//[object foo] returned FALSE (or nil), go here
}
can an If statement detected if an assignment was valid?
This is all right but will generate a warning, since this is a common typo (= instead of ==). To silence that warning add another set of parentheses like this:
if ((var = [object foo])) ...
Since this easily can lead to misunderstandings a lot of people will advise against doing this. For a simple if statement this is much clearer to do the assignment first:
var = [object for];
if (var) ...
In while loops this is more useful, but also considered harmful by many people.
Not sure I understand your question, but let me try and explain a few situations you can check
1) Property contains value
if ([object foo])
{
// If foo has a value associated to it that is not nil/false/zero
}
else
{
// If foo equals nil, false or zero
}
2) Assignment to a variable was successful
if ((bar = [object myMethod]))
{
// If myMethod returns any non-nil value
}
else
{
// If myMethod returns nil
}
3) Previous assignment of a variable was successful
bar = [object myMethod];
if (bar)
{
// If bar has a value associated to it that is not nil/false/zero
}
else
{
// If bar equals nil, false or zero
}
use == instead of = in the if statement.
before the if statement, you may have var1 = [object foo]
see comparison operators
If you mean by valid that the variable contains an expected result, you can just perform another if on the variable against the expected result, or null to check it.