Ok so this is gonna be a bit of a shot in the dark without you being able to see my application!
I have a bug. I have a SwimmingPool class, my app passes the pool from a tableview into a detail view where you can see all the swimmingPool class fields. You can then click on the individual detail, edit it, and then save it. The 'original' pool facility is copied and passed to the view controller responsible for actually making changes. If the user presses save, the fields are copied from the copy into 'original'
switch (self.sectionFromParentTable) {
case KNameIndex:
self.thePoolFacility.name = self.thePoolFacilityCopy.name;
self.thePoolFacility.type = self.thePoolFacilityCopy.type;
break;
case KAddressIndex:
self.thePoolFacility.address = self.thePoolFacilityCopy.address;
break;
case KPhoneNumberIndex:
self.thePoolFacility.phoneNumber = self.thePoolFacilityCopy.phoneNumber;
break;
case KWebAddressIndex:
self.thePoolFacility.webAddress = self.thePoolFacilityCopy.webAddress;
break;
case KPricesIndex:
self.thePoolFacility.prices = self.thePoolFacilityCopy.prices;
break;
case KPoolIndex:
self.thePoolFacility.pools = self.thePoolFacilityCopy.pools;
default:
break;
}
[self.navigationController popViewControllerAnimated:YES];
Can I have some guesses at a bug that does the following:
The bug results in the changes done
to a class' fields not being saved. In particular a class called TimeEntry, in a mutable array called Monday in a Dictionary called TermTimes in a class called pool and then in a mutable array called Pools.
It's appears random. Sometimes it
works perfectly. Sometimes it
doesn't! I can't recreate the error,
only if I'm lucky can i get it not
to save. My hunch is it could be
time sensitive. For example, If I am
entering a timetable for Pool
opening times, if i quickly add a
few entries and save it usually
works fine. If I fill in a whole
timetable then it more than not
doesn't save.
The app doesn't crash.
It's infuriating the try and debug an error that seems to happen at random. Any hints on such an epic bug hunt?
One of the best ways to tackle this type of problem (where it seemingly can't be reproduced reliably) is to insert logging code in various areas where you expect certain things to be happening. Log places that errors could occur, log what values you are expecting and what you have, etc. Next, try, try, try until you can reproduce the bug.
Unlike before, you now have a log to look at and see where things went wrong. If things still look correct everywhere, insert some more logging code elsewhere. If you see something go wrong, but don't understand it, put more logging code in that area and keep narrowing the problem down.
Hopefully this will lead to new hypotheses about how the bug happens, and you will be able to reproduce it under the debugger reliably and fix it!
As duffymo mentioned, multithreading could be the culprit, and would be a good place to investigate first if you're knowingly using multiple threads.
"random" and "hard to reproduce" makes me think that this is an issue having to do with multi-threading. Race conditions are very hard to reproduce and debug. You'll need to make sure that you have exclusive rights to the resources you need to perform this operation.
My suggestion is to look for nils. Any method call on a nil object simply does nothing and returns nil, so any time you're expecting a method to be called and it isn't, you should look for that. (.foo = is the same as setFoo:, so nil.foo = 1; will do nothing.)
Thanks for all your answers. It's now fixed.
For those interested I'd forgotten to add a cellidentifer in the XIB of my cell subclass.
cellForRow: method was therefore creating a new cell every time. The memory got filled up very quick. It then seemed as though my app was automatically trying to cut the fat by forcing another tableView out of editing mode and not managing my instances properly.
Again it's a memory problem. Isn't this always the case!?!
The clue was a one off 101 error in the console indicating my app was using too much memory. Oh and a slow scrolling tableView.
Related
When you are stepping through Swift code in Xcode (9/10?), there is a green bar on the right with something like:
You are supposed to be able to drag the partial-hamburger-menu upwards to rewind the statement pointer to re-run code. However, every time I try it it moves back as expected, but then 100% of the time I step from that point I get:
Is there a trick to this?
You can move the pointer to the next statement to be executed to either a previously executed statement or a not-yet-executed statement, but in order for that to work the stack needs to be in the correct state, and so do the variables in memory.
In my experience, the outcome is usually a crash.
You'd need to drop down to the assembler code and examine it in order to figure out what's really going on, and might need to patch variables and/or the contents of the stack in order for your code to survive the change of program counter. I've never invested the time to try to do that, however. As a result I find the feature pretty much useless, and have given up on it. (I've worked in assembler a LOT in years past, but never learned enough about ARM assembler to be able to read it well, much less hack registers, memory, and the stack to make moving the program counter work.)
Is this:
[self showInWindow:window];
what get called after delay by this code:
[self performSelector:#selector(showInWindow:)
withObject:window
afterDelay:delay];
or am I misunderstanding the method?
Edit: the problem I'm having is that the method showInWindow get called after the delay but behaves like [self showInWindow:nil]. Any suggestion?
Yes, that's what gets called. (After the delay, of course.)
The documentation doesn't really explain what it means to "perform the selector", but what it means is exactly what you suspect.
There is one small difference between using performSelector:withObject: type methods and sending the message directly: they only work if the object is actually an object (that is, an id, a pointer to an Objective C object). But window obviously is an object.
(Strictly speaking, this isn't quite true. If you pass something that's the same size as an id or smaller, it will often work. In some cases it won't. In some cases it will work, but is illegal. In some cases, it will work and is legal but Apple strongly recommends against it. There are no cases where it's a good idea—so instead of learning the specific rules, just assume it never works. The only reason to bring this up is that this used to be common practice in Objective C back in the NeXT days, so you may occasionally still see it in other people's today.)
For more information about the performSelector: family, see the NSObject Protocol Reference, and the SO question Using -performSelector: vs. just calling the method. (For information specifically about the afterDelay: variants, see the documentation linked above.)
From the later edit to the question:
the problem I'm having is that the method showInWindow get called after the delay but behaves like [self showInWindow:nil]. Any suggestion?
First, in what way does it "behave like" the parameter is nil? Is the parameter actually nil? (Just log it in the showInWindow: implementation; if you haven't overridden the base implementation, just add an override that logs and calls the base.)
Second, if it actually is nil, was it nil at the time you sent performSelector:withObject:afterDelay:? If so, obviously it'll still be nil when the selector is sent. Also, make sure window really is an id rather than some other type. (Note that if you've got members, properties, globals, and/or locals sharing the name window, it can be confusing which one you're referring to. This is a common source of problems.)
If it's actually not nil when you schedule it, but is nil when it arrives, there are a few ways that could happen, but they're all less likely, and trickier to debug, than these two cases, so let's rule them out first.
Yes, that's what it does... Although keep in mind that it may take longer than the delay to execute. This method basically sets up an NSTimer in the current thread's run loop, so if your thread gets busy doing heavy duty work and the run loop takes longer than your delay to come back, your method will get executed later.
With reference to the question here.
The solutions provided in that thread, include:
Being smart about where and how many variables you declare, that would go on the stack.
Disable Guard Malloc if needed.
Also, in general:
3. Make sure you are releasing a variable you have actually allocated memory for!!
I have none of the above issues. There are very few stack-allocated variables that I use within functions, say 2-3 within each. But because the functions are called in a loop several times, it seems to trigger an exception.
And here's the kicker, this is not just happening for statically allocated variables, but stuff on the heap too! I'm getting the page errors on Auto-released declarations of NSNumber variables that I use a couple of inside the loop, as well as a dictionary that I juDIciously alloc and release within the scope of the function, every single time it's called.
So why is this happening, and why the heck are heap variables getting affected? I don't get it at all, please throw some light on this. :)
I'm on IOS5 with XCode 4.2, iPhone/iPad simulator.
Thanks!
Regards,
Dev
Edit: Sample code
- (void)doSomething {
NSInteger fun = 3;
NSInteger time = 4;
NSInteger overload = fun*time;
NSString *string = [NSString stringWithFormat:#"%d",overload];
NSObject *myCustomObject = [[NSObject alloc] init];
[myCustomDictionary setObject:myCustomObject forKey:string];
[myCustomObject release];
//myCustomDictionary is an iVar, alloced in the class's init method, and released in dealloc and not touched anywhere in between
}
//doSomething gets called several times through the course of execution as the state of the view changes, the user interacts with it etc, often 2-3 times during one state change.
The code is purposely vague, but at the same time, it is EXACTLY as simple as in the sample. As is the rest of the code in the entire project. Several functions, each doing a small amount of work, as nicely self contained memory-wise as this one.
I faced EXC_BAD_ACCESS issues before, and at that point had referred to this question. However in my case, I was not creating multiple variables on the stack within a loop, they were getting created repeatedly by a function which gets called several times through the course of the execution. Ideally, the variables should have just got destroyed at the end of function-scope. Not sure why that didn't happen.
Anyway, to resolve that and to prevent multiple allocations from happening, I ended up declaring my stack-allocated variables as all static. That is bad practice, but that's exactly what I had to do to get it working. And it was working until I ended up facing the issue AGAIN with the "doSomething" function.
So the difficulty in "doSomething", was that I did not have only stack-allocated variables getting created, but heap stuff too. So I first started getting EXC_BAD_ACCESS on the NSInteger variables, at which point I tried fixing it again, by declaring them as static. It worked, but now EXC_BAD_ACCESS started occurring on the auto-released variable and finally the custom-allocated variable - which is when I got stumped. I have been following all the rules of memory management, and I'm having stack AND heap variables fubaring all over me. If it was only heap stuff, or stack stuff inside a loop, I could understand there's a mistake SOMEwhere. But here, it's neither, these are perfectly innocent variables getting allocated on the stack inside ONE function that is NOT called in a loop, and regular auto-released variables that never ever get retains or releases thrown at them from another place in the code. What makes it all even worse, is that the failure points are random - not just in this function but practically every one that gets called several times through the course of execution of the project.
Edit2: Turns out, in this case, it's my fault. See my answer for details. Sorry for wasting people's time. :\
We can't really help you without seeing the whole stack trace.
EXC_BAD_ACCESS doesn't mean anything in order to troubleshoot we need to know what the exception is.
Based on my experience when you don't get a stack tarce it means you are double releasing. Zombies is the way to find your double release.
Go to: Product -> Profile and then select "Zombies" from the list.
Run the app and perform any task that causes the crash, if the problem is a double release a pop-up would appear. Select the arrow in the popup and it tells you exactly what object is being double released, and it shows you the retain cycle.
Without any code posted in your question, and seeing that you are using iOS 5 and Xcode 4.2 my best advice for you is, in Xcode, go to Edit>Refactor>Convert to Objective-C ARC and wave all your memory management headaches goodbye.
ARC does all the memory management for you. You do not need to retain, release or write dealloc methods. You don't have to worry about memory management in most cases. You will leave mysterious EXC_BAD_ACCESS crashes behind. The way it works is super efficient. The compiler puts in the retains and releases for you and then optimises. You never even have to see the code.
Ah geez I don't believe this.
The issues faced earlier with the stack-allocated NSInteger variables holds, but in this case, it was entirely my fault.
"doSomething" was part of a long chain of events, that, due to some silly negligence on my part, ends up looping a bunch of times, which is what, rightfully and as it should be, leads to the application running out of memory. Whether it's with the stack variables or with the malloced ones sitting on the heap, with an infinite loop, it's gonna crash one way or another. :)
So the crash is perfectly fair, just got confused in this case with a previous issue that turned out to be unrelated. :(
Sorry for wasting everybody's time.
I am creating function (for example) to validate content, then if it is valid, close the view, if it is not, present further instructions to the user. (Or other such actions.) When I go to name it, I find myself wondering, should I call it -doneButtonPressed or -validateViewRepairAndClose? Would it be better to name the method after what UI action calls it, or name it after what it does? Sometimes it seems simple, things like -save are pretty clear cut, other times, and I can't thing of a specific example right off, but I know some have seemed like naming them after what they do is just so long and confusing it seems better to just call them xButtonPressed where x is the word on the button.
It's a huge problem!!! I have lost sleep over this.
Purely FWIW ... my vote is for "theSaveButton" "theButtonAtTheTopRight" "userClickedTheLaunchButton" "doubleClickedOnTheRedBox" and so on.
Generally we name all those routines that way. However .. often I just have them go straight to another routine "launchTheRocket" "saveAFile" and so on.
Has this proved useful? It has because often you want to launch the rocket yourself ... in that case call the launchTheRocket routine, versus the user pressing the button that then launches the rocket. If you want to launch the rocket yourself, and you call userClickedTheLaunchButton, it does not feel right and looks more confusing in the code. (Are you trying to specifically simulate a press on the screen, or?) Debugging and so on is much easier when they are separate, so you know who called what.
It has proved slightly useful for example in gathering statistics. The user has requested a rocket launch 198 times, and overall we've launched the rocket 273 times.
Furthermore -- this may be the clincher -- say from another part of your code you are launching the rocket, using the launch-the-rocket message. It makes it much clearer that you are actually doing that rather than something to do with the button. Conversely the userClickedTheLaunchButton concept could change over time, it might normally launch the rocket but sometimes it might just bring up a message, or who knows what.
Indeed, clicking the button may also trigger ancillary stuff (perhaps an animation or the like) and that's the perfect place to do that, inside 'clickedTheButton', as well as then calling the gutsy function 'launchTheRocket'.
So I actually advocate the third even more ridiculously complicated solution of having separate "userDidThis" functions, and then having separate "startANewGame" functions. Even if that means normally the former does almost nothing, just calling the latter!
BTW another naming option would be combining the two... "topButtonLaunchesRockets" "glowingCubeConnectsSocialWeb" etc.
Finally! Don't forget you might typically set them up as an action, which changes everything stylistically.
[theYellowButton addTarget:.. action:#selector(launchRockets) ..];
[theGreenButton addTarget:.. action:#selector(cleanUpSequence) ..];
[thatAnimatingButtonSallyBuiltForUs addTarget:.. action:#selector(resetAll) ..];
[redGlowingArea addTarget:.. action:#selector(tryGetRatingOnAppStore) ..];
perhaps that's the best way, documentarily wise! This is one of the best questions ever asked on SO, thanks!
I would also go with something along the lines of xButtonPressed: or handleXTap: and then call another method from within the handler.
- (IBAction)handleDoneTap:(id)sender {
[self closeView];
}
- (void)closeView {
if ([self validate]) {
// save and close
}
else {
// display error information
}
}
I have a pretty weird problem in my iPhone app which is, I think, related to memory getting corrupted:
At one point, I need to sort an array, which I do with -[sortArrayUsingFunction].
The result is not correct unless I either allocate some memory with something like void *test = malloc(2 * sizeof( int )) before the method call or have, e.g., a call to NSLog() (which is never invoked) in the sorting function.
In other words: the sorting only works if I slightly increase the memory that was used before calling the sorting function. I think this is because at some point, memory gets corrupted.
How do you debug something like this?
It sounds like some of your code is using already released objects. A lot of help with debugging this kind of errors is provided in Apple’s great Mac OS X Debugging Magic tech note, especially the foundation part.
For your case I'd disable autorelease pools (setting the environment variable NSEnableAutoreleasePool=NO) or use the zombie feature (NSZombieEnabled=YES) to find places where you send messages to released objects.
Try running your program in the simulator under Valgrind:
http://valgrind.org/
And how to use it under the simulator:
http://landonf.bikemonkey.org/code/iphone/iPhone_Simulator_Valgrind.20081224.html
You may have to change the VALGRIND path in the code example depending on where it gets installed.
Such things can be a challenge to debug. There are some tools for detecting out-of-bounds accesses and such on other platforms, so I presume there would be something for the iPhone, however I don't know of any.
Perhaps you should store two copies of the array, and compare them for differences. Print out the differences. The nature of the "junk" that was introduced to one of the arrays might give a hint as to where it came from.
Also just go through the code that runs before this point, and re-read it (or better yet, get someone else to read it). You might spot a bug.