Objective C: How does 7 - 1 = 3? - iphone

NSLog(#"Before: %d",currentArticle);
currentArticle--;
NSLog(#"SUBTRACT %d",currentArticle);
"currentArticle" is an integer. This is only being echoed once in my console. If I do not run this subtraction, the number "currentArticle" remains at 7.
This is being run in the main thread, and only run once per user interaction.
I have also tried
currentArticle = currentArticle - 1;
With the same result. Am I taking crazy pills?
Thanks!
Edit:
Declared as follows:
extern int *currentArticle;
And assigned later as:
currentArticle = 0;
I tried rewriting as this:
int *curArticle; // in my .h file
curArticle = 1;
And then I run the
curArticle--;
and it still decrements by two...
I have stepped through the code and ensured there are no other calls hitting this variable.. Thanks for the feedback so far, I will keep hacking away at it.

I concur with the comments above. I'd bet a dollar that your code looks like:
int *currentArticle = 7; // or something
currentArticle may not even be a pointer to an int, specifically, but it's very likely a pointer to some 4-byte type. The '--' and '++' operators, when applied to pointers, decrement or increment by the size of the type that's pointed to.

Things I think of: Threads (if it's a strange problem, there are threads)? Or is it called by an event (which is triggered more than once)?

Related

Different block behavior between debug and release configuration

My program works perfectly. I assure you with my life, 0 bugs. Proudly, I tried to package the application as an .ipa file for ad-hoc distribution to my beta tester using TestFlight.
The program didn't work. Animations which are supposed to happen never happened. Network code breaks. The button to fade out the music beautifully didn't do anything at all.
It turns out that the culprit is the new and shiny blocks. When I test my program in the Simulator or on my device, I used the default "Debug" build configuration. But when I archive it for distribution (and I believe later for submission to the App Store), XCode uses another configuration which is "Release". Investigating further, the difference is due to the optimization level (you can find it on XCode's Build Settings): Debug uses None (-O0) but Release uses Fastest, Smallest (-Os). Little did I know, that it's Fastest, Smallest, and Doesn't Work (tm). Yes, blocks behave differently between those 2 configurations.
So, I set out to solve the problem. I've simplified my soon-to-change-the-world app into its bare bones, shown in the image I've attached to this post. The view controller has an instance variable x with initial value 0. If we press b, it will spawn a thread that will continuously check the value of x, changing the bottom label when x becomes 1. We can change the value of x using button a.
Here is my naive code (I'm using ARC btw):
#implementation MBIViewController
{
int _x;
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
_x = 0;
}
- (void)updateLabel
{
self.topLabel.text = [NSString stringWithFormat:#"x: %d", _x];
}
- (IBAction)buttonAPressed:(id)sender {
_x = 1;
[self updateLabel];
}
- (IBAction)buttonBPressed:(id)sender {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
while (_x != 1) {
// keep observing for value change
}
dispatch_async(dispatch_get_main_queue(), ^{
self.bottomLabel.text = #"b changed me becase x changed!";
});
});
}
#end
_x is an instance variable, so it is reasonable to think that the block will access it using a pointer to "self", not on a local copy. And it works on the debug configuration!
But it doesn't work on Release build. So perhaps the block is using a local copy after all? OK, so let's explicitly use self:
while (self->_x != 1) {
// keep observing for value change
}
Doesn't work either in Release. OK, so let's access the damn variable directly using pointer:
int *pointerToX = &_x;
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
while (*pointerToX != 1) {
// keep observing for value change
}
// other codes
});
Still doesn't work. This is when it dawned to me that the smart optimizing compiler assumes that there is no possible way in this multithreaded world that the result of the comparison will change, so perhaps it substituted it to be always TRUE or some other voodoo.
Now, when I use this, things start working again:
while (_x != 1) {
// keep observing for value change
NSLog(#"%d", _x);
}
So, to bypass the compiler optimizing out the comparison, I resorted to making a getter:
- (int)x
{
return _x;
}
And then checking the value using that getter:
while (self.x != 1) {
// keep observing for value change
}
It now works, because self.x is actually a call to a function and the compiler is polite enough to let the function actually do its job. However, I think this is a rather convoluted way to do something so simple. Is there any other way you would have coded it, another pattern that you will use, if you are faced with the task of "observing for change of value inside a block"? Thanks a lot!
If you use a variable and do not modify it in a loop, the compiler optimization can cause the actual access to the variable to be optimized out, because your statement can be evaluated beforehand at compile time.
In order to prevent this, you can use the "volatile" keyword, which prevents the compiler from applying this type of optimization.
It does work with getters and setters, because then you need to send a message to your instance, which serves as a synchronization point.
Try declaring _x as follows:
__block int _x;
Normally variables that are also used in blocks are copied. This will indicate to the compiler that if _x is modified in the block the changes should be visible outside it. It might fix your problem.

Malloc() creates space for single struct, not array of structs

I've been banging my head against this problem all day, I would be very grateful to anyone who could help out.
Here's the deal - I'm trying to create a dynamic C array using malloc(). This array will hold CGPoint structs, which I start building and assigning right after the array is built. Here's the code:
CGPoint* tempVertices = malloc(sizeof(CGPoint) * 4); //defining a collision frame
tempVertices[0] = CGPointMake(37, 46);
tempVertices[1] = CGPointMake(69, 40);
tempVertices[2] = CGPointMake(48, 6);
tempVertices[3] = CGPointMake(17, 10);
//Then I pass the pointer to my array off to a setter...
[self setVertices: tempVertices];
However, when tempVertices gets created, it seems that I'm only getting space for one CGPoint:
int test1 = sizeof(CGPoint); // 8
int test2 = sizeof(tempVertices); // 4
int test3 = sizeof(*tempVertices); // 8
When stepping through with the XCode debugger, it shows that tempVertices is a pointer to a CGPoint. When I set tempVertices[0], the CGPoint that tempVertices points to recieves that value, which is reflected in the debugger. Where did my other 3 slots go? tempVertices seems to be pointing to a singe CGPoint instead of an array. I want the array.
Any ideas on what I'm doing wrong? I know that there are other ways to fix this using C++ or other objects, but I want to stick to C if possible.
Thanks in advance!
Update :
To answer zpasternack, setVertices: is a custom written setter. And I don't know how / if it knows how big the incoming array is. I'm trying to understand straight C stuff better, so insights/explanations regarding the proper way of passing a dynamic C-array as an argument are highly appreciated. Here's what the setter looks like :
- (void) setVertices:(CGPoint*) val {
_vertices = val; //_vertices is a member variable of the type CGPoint*
//...calculate a centroid, other stuff...
}
If needed, I could wrap my CGPoints in NSValue objects and use an NSArray instead, but I sure would like to know the right way of doing it in plain ol' C.
Thanks to everyone who has commented - you guys are great :)
On your 32 bit machine, you're getting exactly what you expect. sizeof(tempVertices) is the size of the pointer, while sizeof(*tempVerices) gives you the size of a CGPint (probably two ints). You can't get the size of an allocated array with sizeof(). The value is only known at run-rime, and sizeof() is a compile time operator.
OK, after your edit I think I see what's going on. That code, exactly as you've written, should work OK. Xcode won't show you the values of any of those CGPoints, because it doesn't know it's an array, just a pointer to a single CGPoint. But it's there. Set a breakpoint right after you call setVertices:. At the gdb prompt, print some of those values.
(gdb) print _vertices[1]
$2 = {
x = 69,
y = 40
}
(gdb) print _vertices[3]
$3 = {
x = 17,
y = 10
}
Correct, see?
That's not to say there aren't issues here. For one thing, setVertices: is leaking that memory. You're allocating memory for tempVertices, holding onto that pointer, but not freeing it anywhere. The next time you call setVertices:, you'll have a leak.
A bigger issue is that nobody knows how many CGPoints are in that array, except the code that allocated the memory for it. Will it always be 4 CGPoints? What happens if somebody accesses _vertices[5] or _vertices[27]? Bad things, if you didn't allocate that much space for them.
Is there a requirement that this be a plain C array? Like, these points are going to get passed to OpenGL or cocos2d or something? If not, you might consider using some kind of array class for it. Because these aren't NSObject-derived objects you're storing, you can't use an NSArray. You could use a std::vector, if you don't mind dragging in a buncha C++. I probably would not do that.
If you're set on sticking with a C array, you should probably do some work to try to make the interface less error prone. Like I mentioned before, you'll need to track the size of the array. Perhaps you could add a parameter to setVertices: representing the number of CGPoints that the array holds. Then other parts of the code that access _vertices could check that to make sure they're not walking off the end of the array. And, like I mentioned before, make sure you free that memory before you reassign the pointer.
Messing about with pointers is fraught with danger. Tread carefully, there be dragons there.
The malloc is allocating enough space for 4 GCPoint structs and returning a pointer to the allocated space.
The first is at tempVertices + 0. It's tempVertices[0].
The second is at tempVertices + 1. It's tempVertices[1].
The third is at tempVertices + 2. It's tempVertices[2].
The fourth is at tempVertices + 3. It's tempVertices[3].
I would not use sizeof() to determine the size of an array allocated at runtime.
Have you actually had trouble assigning new CGPoint objects into your array? Does CGPointMake() perform any allocation of its own?

Compare NSNumber with NSInteger

I spent some time today chasing down two bugs, and ended up fixing both of them using the same solution.
Now that I have the solution, I was hoping to get some clarity behind it.
I'm comparing an attribute from Core Data (Integer 16/NSNumber) with an Integer (ABPropertyID & ABMultiValueIdentifier).
The bug was in this comparison, and oddly enough, only showed itself after I had killed the app (from the background tray), reopened it, and run through the same process that included the comparison. Anyways...
This is what stopped working after a restart:
if (myNumber.aProperty == [NSNUmber numberWithInt:anInteger]) { /* do stuff here */ }
And these are the two solutions, which so far, are working perfectly:
if ([myNumber.aProperty integerValue] == anInteger) {/* do stuff here */ }
if ([myNumber.aProperty isEqualToNumber:[NSNumber numberWithInt:anInteger]]) { /* do stuff here */ }
To me, they all look identical. I'm always either converting the NSNumber to an integerValue, or converting the integer to an NSNumber.
Any ideas?
Do not use == to compare NSNumbers. Most of the time you'll be comparing two distinct objects, so the comparison won't evaluate to true. If you look at your if condition, notice that you're particularly comparing your property to a brand new NSNumber object.
Since NSInteger is a Cocoa wrapper for certain value types, comparing NSIntegers with == works fine.
The implementation of isEqualToNumber: probably takes the wrapped value types and compares them too.
As you said, both solutions are working...
I would prefer the first one, as it appears more readable, IMHO...
It may also be more performant, as you are comparing integers, after having converted a NSNumber to an int.
In the second one, you convert an int to an object, then you compare the two objects...
So that's a second method call, which you don't have in the first case...
Hope this helps... : )
netWorkingButtonsIndexes is the array which holds objects and
LinkedIn is a number with int data type.
[[netWorkingButtonsIndexes objectAtIndex:buttonIndex] isEqual:[NSNumber numberWithInteger:LinkedIn]]
By using the isEqual method we can compare objects with any data rtype.

What causes this error? "CALayer position contains NaN: [240 nan]"

I've seen this happen whenever i rotate a screen that has a UITableView on it. I've found out that it happens inbetween the willRotate and didRotate method calls in UIViewController My co-workers have seen it in other spots as well, usually around rotation. It hadnt started happening until very recently, and we're stumped as to how we should deal with it (google searches don't turn up the error message in its exact form). Has anyone else encountered this that knows what to do about it?
(Decided to take this out of comments and put it as an answer, since I think it's a darned good answer :)
Ha! I had an NaN calculation (div0), too. Key debugging aid: the message in question is output by NSLog(), so set a breakpoint on NSLog() and watch what the OS is doing at that time. For me, it was myUISlider.value = NaN.
To set breakpoint:
XCode 3.x
CMD-SHIFT-Y (debug window.)
Breakpoints button.
"Double-click for symbol"
Type in "NSLog" (no quotes.)
XCode 4.x
CMD-6 (breakpoints navigator.)
"+" to add breakpoint (lower left.)
Select ADD SYMBOLIC BREAKPOINT.
Symbol: NSLog
Confirm: Done.
XCode 5.x - 7.1 (at least)
(Same as 4.x, except breakpoints navigator is CMD-7, now.)
Run app, watch it break on NSLog, check the stack traces.
I've found the problem.
When you reset the frame of a tableview, it calls the delegate method tableView:heightForRowAtIndexPath: for each row in the table so it can recalculate its content size if it needs to. At that point, we do some special handling to return the height, and due to some bad assumptions in our code, we mistakenly returned NaN due to a divide by zero error (the variable we divide by was assumed to never be zero). Making sure that we do not divide by zero here fixed it.
I've spent a day trying to find the code that causes same problem and solved it within a minutes after enabling "break on exception" in Xcode. Check this tutorial to see how to enable it.
I had this problem when i was assumed that:
tableView:heightForHeaderInSection: returned an NSInteger, but it returns CGFloat...
changing:
-(NSInteger)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section
to
-(CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section
fixed my issue.
Edit:
At some point I figured out how computers work below the C level, so I thought I would share it... (I will use an register names from x86_64 as I am most familiar with them, ARM would be slightly different but analogous)
int f(){
float someFloat=5.0f;
return someFloat;
}
results in converting the value of someFloat to an integer type then copying that to a particular register: %rax then calling the return instruction.
float f(){
float someFloat=5.0f;
return someFloat;
}
results in copying the value of someFloat from its current location to a particular register: %xmm0 then calling the return instruction.
So if you have the wrong prototype the calling code will expect the value to be in the wrong place, you will end up really returning a garbage value.
This error also cost me a long time.
At the end I found my colleague wrote something like this:
UIEdgeInsets a;
a.left = (...some calculation);
button.imageEdgeInsets = a;
And I rewrote these code like this and fix the issue:
UIEdgeInsets a;
a.left = (...some calculation);
a.top = 0;
a.bottom = 0;
a.right = 0;
button.imageEdgeInsets = a;
some value of UIEdgeInsets isn't initialised properly, and it sometimes turn into a NaN value, and crash the application.
More generally, you should check whether all values of C-style structs are initialised properly.
There is an another way to reproduce the issue: using insetBy(dx:dy:) on a too small rect
You can try this yourTableview?.bounces = false. It works for me.

Parameter losing value when passed

I'm sure this is something simple but I've been staring at it for a bit now and I think all I need is a fresh pair of eyes to look at it, and since my cat doesn't have a whole lot of experience with iPhone programming I've turned to you.
I am passing a variable of type float from a class (UIView) to another class (UIViewController) right before the variable is passed it's value is correct but when it reaches the function it loses it's value, it's shown to be 0 or -2 and I'm not sure why. Like I said I'm sure it's something simple but I just need a fresh pair of eyes to look at it
Code is below
//inside UIView
-(void)UpdateFloat
{
myFloat = myFloat + 0.01;
}
-(void)RemoveView
{
//Function Call
[viewController myFunction:myFloat];
}
//Function
-(void)myFunction:(float)myFloat
{
[myView removeFromSuperview];
[self.view addSubview:myOtherView];
[myOtherView anotherFunction:myFloat];
}
the float gets updated by a timer and when the UIView makes the function call the value of the float is correct (usually about 15.67)
any help would be appreciated
Thank you in advance,
BWC
If your float really is a float, I bet there is something else is going on somewhere else that's manipulating that value, it's not the message send. Search for every occurrence of that variable name.
You'll see stuff like this happen when you accidentally do integer math on floats (which is really easy to do). Check and make sure your floats are floats and all the math is being done in floats and no int math is happening.
It's also possible that it is a scope related thing and you are instead getting a different myFloat, hard to tell without all the source available.
Well, I don't understand you, because you say you pass from UIView to UIViewController. But in your code, you first call an function in the UIViewController, which have to be [self myFunction:myFloat] by the way, and in that function you call your UIView.
Ok Guys,
I think I've figured out why the float isn't retaining it's value but the reason also baffles me.
when I'm calling the ViewControllers function in the UIView Xcode is showing the warning that there is no method and that methods without a matching signature will assume to return(id) and pass '...' as arguments
I understand what this warning means but what I don't understand is that I have the method declared in the header of my viewController
-(void)myFunction:(float)myFloat;
I also have another view that calls functions to the view controller and it's not displaying that warning...I'm pretty sure this is the reason the float isn't retaining it's value but I don't know why it can't see the method signature