Objective-C: int value changing without cause - objective-c

Objective-C: I need help retaining the value of an int. It's changing on me without my command.
The original question was: "How do you declare and retain an int?", that was satisfied in another post here: Objective-C: How do you declare and retain an int?
Now I have a problem where an int that was 18 is changing to 2, somehow on its own.
Here's my code:
#interface Game : Layer // this is from cocos2d
{
int maxSprites;
}
#implementation Game
-(void)initVariables
{
maxSprites = 18;
}
Later on, when I print it out, like
NSLog(#" maxSprites = %d ", maxSprites);
I get:
maxSprites = 2
And operations that require it to be 18, crash or don't work, as if it's really just 2 now.
How would that be possible? =)
Apple + Shift + F reveals no other usage of the maxSprites variable.
I've looked at other code examples and often they're exposing the variable with a getter and setter, and they are also using #property. Am I missing something? I'm new to Objective-C, so I might as well just be!
I did a Apple + Shift + F for maxSprites" In Project, Textual, Contains, Ignore Case and only resulted in:
Game.h: int maxSprites;
Game.m: maxSprites = 18;
Game.m: NSLog(#" maxSprites = %d", maxSprites);
Game.m: NSLog(#" maxSprites = %d", maxSprites);
Game.m: NSLog(#"maxSprites is at %p", &maxSprites);
Game.m: NSLog(#"maxSprites is at %p", &maxSprites);
Game.m: NSLog(#" maxSprites = %d", maxSprites);
Game.m: NSLog(#" maxSprites = %d", maxSprites);
Game.m: NSLog(#"maxSprites is at %p", &maxSprites);
Game.m: NSLog(#"maxSprites is at %p", &maxSprites);
I found the location where it changes using a watchpoint. It changes
Expression: “*(int *) 67379960”
New Value: 2
Old Value: 18
on this line:
[self checkMatchBarAward:spriteTypeToAdd];
Odd? That function doesn't do anything with maxSprites, nor does that line.
EDIT:
here is the function, I commented everything inside it out and it still occurs:
.h
-(void)checkMatchBarAward:(int)spriteTypeToAdd;
.m
-(void)checkMatchBarAward:(int)spriteTypeToAdd
{
}
EDIT:
Thanks for the recommendations. I have cleaned all targets and it still changed values. Because of the answers you guys/gals gave, you lead me to the problem. Thanks for all of your help.
I posted my results below in an answer. Here's a copy:
Guys/gals you wouldn't believe what was the cause. Thank you for all your help because telling me to clean and look and check my types, that helped.
I looked over my arrays. I found one that was declared like this:
int matchBarArray[8];
2 lines up from the breakpoint halt where it says that the value changed from 18 to 2, I have this line:
matchBarArray[spritesCaptured-1] = spriteTypeToAdd;
And guess what, I overstepped the bounds of the array by 1. If I increase the size of the array to 9, I no longer get the int change from 18 to 2.
Also, if I overstep the bounds by more than 1, that is, I reduce the array size to smaller, there are other things that start changing such as my score, booleans, the whole game ! =)
I can't believe hitting memory outside the array in Objective-C can cause such a riot =) AND IT'S SO HARD TO DEBUG!

Guys/gals, you wouldn't believe what was the cause. Thank you for all your help because telling me to clean and look and check my types, that helped.
I looked over my arrays. I found one that was declared like this:
int matchBarArray[8];
2 lines up from the breakpoint halt where it says that the value changed from 18 to 2, I have this line:
matchBarArray[spritesCaptured-1] = spriteTypeToAdd;
And guess what, I overstepped the bounds of the array by 1. If I increase the size of the array to 9, I no longer get the int change from 18 to 2.
Also, if I overstep the bounds by more than 1, that is, I reduce the array size to smaller, there are other things that start changing such as my score, booleans, the whole game ! =)
I can't believe hitting memory outside the array in Objective-C can cause such a riot =) AND IT'S SO HARD TO DEBUG!

If your checkMatchBarAward: method truly is empty, then you need to clean your project (Shift + cmd + k) and rebuild it.

I didn't see the line you specify in your code.
Chances are, though, that you are referring to something as a long* when it's an int* or something like that (although how, after all these years, C STILL can't see that is beyond me).
Anyway, check your types where the sizes of what they point to may differ. If you reference an int * memory location with a long * (say, by passing in an int* to a method that expects a long*), you will fubar the stack and start modifying adjacent variables.
I've done this more than once, but in C, not Objective C--so I'm not sure it's the correct answer.

Related

Weird compiler optimization/behavior regarding a "for" loop without a body in Objective-C

I have the following C array of NSString *:
static NSString *const OrderByValueNames[] = {#"None",#"Added",#"Views",#"Rating",#"ABC",#"Meta"};
Now, I want to check the length of this array at runtime so I wrote the following method:
NSInteger LengthOfArray(NSString *const array[])
{
NSInteger length = 0;
// For Loop Without a body!
for (length = 0; array[length] != nil; length++);
return length;
}
Now, when I run this code at debug configuration, everything is fine and the function returns the right result.
BUT as soon as I switch to release configuration and run it again, the program freezes at the for loop. After 10 seconds of the loop being executed, iOS kills the app for not responding. Weird.
Now, if I add body to the loop, like that:
for (length = 0; array[length] != nil; length++)
{
NSLog(#"%d",length);
}
Then it's working fine even in release mode.
Giving the loop an empty body, like that:
for (length = 0; array[length] != nil; length++){}
Still freezes in release mode.
My guess is that there is a compiler optimization when running in release mode, but what exactly?!
Any ideas?
C-style arrays are not nil-terminated by default. If you want to check the length this way, you need to add the terminator yourself.
static NSString *const OrderByValueNames[] =
{#"None",#"Added",#"Views",#"Rating",#"ABC",#"Meta",nil};
A much better way to find the length is simply this:
length = sizeof(OrderByValueNames) / sizeof(OrderByValueNames[0]);
(Note that this trick doesn't work if you pass the array into a function, since it then degenerates into a pointer.)
Your OrderByValueNames array doesn't contain a nil element. No wonder you can't find one! Walking off the end of the array like that will result in undefined behaviour. If you want to mark the end of the array with nil, you'll have to add it manually.
By the way, if you'd like to know the length of a fixed size C array, you can do this:
length = sizeof(OrderByValueNames)/sizeof(OrderByValueNames[0]);
This doesn't work for function parameters, though, as those are just pointers!

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.

Passing and calling dynamic blocks in Objective C

As part of a unit test framework, I'm writing a function genArray that will generate NSArrays populated by a passed in generator block. So [ObjCheck genArray: genInt] would generate an NSArray of random integers, [ObjCheck genArray: genChar] would generate an NSArray of random characters, etc. In particular, I'm getting compiler errors in my implementation of genArray and genString, a wrapper around [ObjCheck genArray: genChar].
I believe Objective C can manipulate blocks this dynamically, but I don't have the syntax right.
ObjCheck.m
+ (id) genArray: (id) gen {
NSArray* arr = [NSMutableArray array];
int len = [self genInt] % 100;
int i;
for (i = 0; i < len; i++) {
id value = gen();
arr = [arr arrayByAddingObject: value];
}
return arr;
}
+ (id) genString {
NSString* s = #"";
char (^g)() = ^() {
return [ObjCheck genChar];
};
NSArray* arr = [self genArray: g];
s = [arr componentsJoinedByString: #""];
return s;
}
When I try to compile, gcc complains that it can't do gen(), because gen is not a function. This makes sense, since gen is indeed not a function but an id which must be cast to a function.
But when I rewrite the signatures to use id^() instead of id, I also get compiler errors. Can Objective C handle arbitrarily typed blocks (genArray needs this), or is that too dynamic?
Given that blocks are objects, you can cast between block types and id whenever you want, though if you cast the block to the wrong block type and call it, you're going to get unexpected results (since there's no way to dynamically check at runtime what the "real" type of the block is*).
BTW, id^() isn't a type. You're thinking of id(^)(). This may be a source of compiler error for you. You should be able to update +genArray: to use
id value = ((id(^)())(gen))();
Naturally, that's pretty ugly.
*There actually is a way, llvm inserts an obj-c type-encoded string representing the type of the block into the block's internal structure, but this is an implementation detail and would rely on you casting the block to its internal implementation structure in order to extract.
Blocks are a C-level feature, not an ObjC one - you work with them analogously to function pointers. There's an article with a very concise overview of the syntax. (And most everything else.)
In your example, I'd make the gen parameter an id (^gen)(). (Or possibly make it return a void*, using id would imply to me that gen generates ObjC objects and not completely arbitrary types.)
No matter how you declare your variables and parameters, your code won't work. There's a problem that runs through all your compiler errors and it would be a problem even if you weren't doing convoluted things with blocks.
You are trying to add chars to an NSArray. You can't do that. You will have to wrap them them as some kind of Objective C object. Since your only requirement for this example to work is that the objects can be inputs to componentsJoinedByString, you can return single-character NSStrings from g. Then some variety of signature like id^() will work for genArray. I'm not sure how you parenthesize it. Something like this:
+ (id) genArray: (id^()) gen;
+ (id) genString {
...
NSString * (^g)() = ^() {
return [NSString stringWithFormat:#"%c", [ObjCheck genChar]];
};
...
}
NSString * is an id. char is not. You can pass NSString * ^() to id ^(), but you get a compiler error when you try to pass a char ^() to an id ^(). If you gave up some generality of genArray and declared it to accept char ^(), it would compile your call to genArray, but would have an error within genArray when you tried to call arrayByAddingObject and the argument isn't typed as an id.
Somebody who understands the intricacies of block syntax feel free to edit my post if I got some subtle syntax errors.
Btw, use an NSMutableArray as your local variable in genArray. Calling arrayByAddingObject over and over again will have O(n^2) time performance I imagine. You can still declare the return type as NSArray, which is a superclass of NSMutableArray, and the callers of genArray won't know the difference.

Is it safe to use pointers to change values in blocks?

I've started using blocks, and one of the first things I encountered is an inability to set values which are captured by the closure. This is fine, I've been using C/C++ a long time. I'll just use pointers!
MyObject* bestObj = nil;
float bestDist= 10000.f;
MyObject **pBestObj = &bestObj;
float* pBestDist = &bestDist;
[self testObjects:class block:^(MyObject* obj){
CGRect r = [obj boundingBox];
// position is captured from outside this code sample
if( CGRectContainsPoint( r, position ) )
{
float dist = GetDistance( obj, position );
if(dist < bestDist)
{
*pBestDist = dist;
*pBestObj = obj;
}
}
}];
return bestObj;
My question is, is this safe? I assume that as long as my pointer points to something that hasn't gone out of scope and that still exists, that it should work. But I'm also assuming that things that take blocks don't ever, say, run them in parallel. I know my code doesn't, but I don't know about, say, using a block with an NSArray enumerateObjectsUsingBlock call.
The 'right' way to do this would be to mark those original variables as block mutable, __block

interacting with UIViews stored inside a NSMutableArray

a big noob needs help understanding things.
I have three UIViews stored inside a NSMutableArray
lanes = [[NSMutableArray arrayWithCapacity:3] retain];
- (void)registerLane:(Lane*)lane {
NSLog (#"registering lane:%i",lane);
[lanes addObject:lane];
}
in the NSLog I see: registering lane:89183264
The value displayed in the NSLog (89183264) is what I am after.
I'd like to be able to save that number in a variable to be able to reuse it elsewhere in the code.
The closest I could come up with was this:
NSString *lane0 = [lanes objectAtIndex:0];
NSString *description0 = [lane0 description];
NSLog (#"description0:%#",description0);
The problem is that description0 gets the whole UIView object, not just the single number (dec 89183264 is hex 0x550d420)
description0's content:
description0:<Lane: 0x550d420; frame = (127 0; 66 460); alpha = 0.5; opaque = NO; autoresize = RM+BM; tag = 2; layer = <CALayer: 0x550d350>>
what I don't get is why I get the correct decimal value with with NSLog so easily, but seem to be unable to get it out of the NSMutableArray any other way. I am sure I am missing some "basic knowledge" here, and I would appreciate if someone could take the time and explain what's going on here so I can finally move on. it's been a long day studying.
why can't I save the 89183264 number easily with something like:
NSInteger * mylane = lane.id;
or
NSInteger * mylane = lane;
thank you all
I'm really confused as to why you want to save the memory location of the view? Because that's what your '89183264' number is. It's the location of the pointer. When you are calling:
NSLog (#"registering lane:%i",lane);
...do you get what's actually being printed out there? What the number that's being printed means?
It seems like a really bad idea, especially when if you're subclassing UIView you've already got a lovely .tag property which you can assign an int of your choosing.
You're making life infinitely more complex than it needs to be. Just use a pointer. Say I have an array containing lots of UIViews:
UIView *viewToCompare = [myArray objectAtIndex:3];
for (id object in myArray) {
if (object == viewToCompare) {
NSLog(#"Found it!");
}
}
That does what you're trying to do - it compares two pointers - and doesn't need any faffing around with ints, etc.