I have been following the documentation for using NSURLConnection and am using delegates for managing the connection (overriding among other methods connection: didFailWithError: and connectionDidFinishLoading:). The memory allocated for the NSURLConnection object is released in those delegate methods.
My problem is that running "Build/Build and Analyze" from the XCode menu triggers an annoying "Potential leak of an object (...)" warning in the method calling alloc on the NSURLConnection class (logically enough as I do not release it in the same block).
Is there a way to silence this warning?
The way round this to store the connection object in a retained instance variable. Then you can safely release it at the end of your first method.
When you click on the Analyzer message it gives you more information, showing the path of execution etc. Does this indicate that it's just being dumb or does it give you a hint as to what might be wrong?
Assuming the analyzer is just being dumb, I'd just keep the reference in an ivar if the message bothers you, then release it from within -dealloc.
Releasing an allocated resource from within a delegate method feels a bit voodoo to me in any case. I'd even be tempted to move all of the code that's processing the NSURLConnection into its own class.
I'm with Florent on this one. "Listing 1" in Apple's documentation on NSURLConnection will flag a "potential leak" in "build and analyze". Yet putting a [theConnection release] at the end of the method crashes.
Would love to have someone comment on this for me!
Related
I converted my app to ARC and noticed that an object alloc'ed in one of my view controllers was not being dealloc'ed when that view controller was dealloc'ed. It took a while to figure out why. I have Enable Zombie Objects on for my project while debugging and this turned out to be the cause. Consider the following app logic:
1) Users invokes action in RootViewController that causes a SecondaryViewController to be created and presented via presentModalViewController:animated.
2) SecondaryViewController contains an ActionsController that is an NSObject subclass.
3) ActionsController observes a notification via NSNotificationCenter when it is initialized and stops observing when it is dealloc'ed.
4) User dismisses SecondaryViewController to return to RootViewController.
With Enable Zombie Objects turned off, the above works fine, all objects are deallocated. With Enable Zombie Objects on ActionsController is not deallocated even though SecondaryViewController is deallocated.
This caused problems in my app b/c NSNotificationCenter continues to send notifications to ActionsController and the resulting handlers cause the app to crash.
I created a simple app illustrating this at https://github.com/xjones/XJARCTestApp. Look at the console log with Enable Zombie Objects on/off to verify this.
QUESTION(S)
Is this correct behavior of Enable Zombie Objects?
How should I implement this type of logic to eliminate the issue. I would like to continue using Enable Zombie Objects.
EDIT #1: per Kevin's suggestion I've submitted this to Apple and openradar at http://openradar.appspot.com/10537635.
EDIT #2: clarification on a good answer
First, I'm an experienced iOS developer and I fully understand ARC, zombie objects, etc. If I'm missing something, of course, I appreciate any illumination.
Second, it is true that a workaround for this specific crash is to remove actionsController as an observer when secondaryViewController is deallocated. I have also found that if I explicitly set actionsController = nil when secondaryViewController is dealloc'ed it will be dealloc'ed. Both of these are not great workaround b/c they effectively require you to use ARC but code as if you are not using ARC (e.g. nil iVars explicitly in dealloc). A specific solution also doesn't help identify when this would be an issue in other controllers so developers know deterministically when/how to workaround this issue.
A good answer would explain how to deterministically know that you need to do something special wrt an object when using ARC + NSZombieEnabled so it would solve this specific example and also apply generally to a project as a whole w/o leaving the potential for other similar problems.
It is entirely possible that a good answer doesn't exist as this may be a bug in XCode.
thanks all!
Turns out, I've written some serious nonsense
If zombies worked like I originally wrote, turning on zombies would directly lead to innumerable false positives...
There is some isa-swizzling going on, probably in _objc_rootRelease, so any override of dealloc should still be called with zombies enabled. The only thing that won't happen with zombies is the actual call to object_dispose — at least not by default.
What's funny is that, if you do a little logging, you will actually see that even with ARC enabled, your implementation of dealloc will call through to it's superclass's implementation.
I was actually assuming to not see this at all: since ARC generates these funky .cxx_destruct methods to dispose of any __strong ivars of a class, I was expecting to see this method call dealloc — if it's implemented.
Apparently, setting NSZombieEnabled to YES causes .cxx_destruct to not be called at all — at least that's what happened when I've edited your sample project:
zombies off leads to backtrace and both deallocs, while zombies on yields no backtrace and only one dealloc.
If you're interested, the additional logging is contained in a fork of the sample project — works by just running: there are two shared schemes for zombies on/off.
Original (nonsensical) answer:
This is not a bug, but a feature.
And it has nothing to do with ARC.
NSZombieEnabled basically swizzles dealloc for an implementation which, in turn, isa-swizzles that object's type to _NSZombie — a dummy class that blows up, as soon as you send any message to it. This is expected behavior and — if I'm not entirely mistaken — documented.
This is a bug that has been acknowledged by Apple in Technical Q&A QA1758.
You can workaround on iOS 5 and OS X 10.7 by compiling this code into your app:
#import <objc/runtime.h>
#implementation NSObject (ARCZombie)
+ (void) load
{
const char *NSZombieEnabled = getenv("NSZombieEnabled");
if (NSZombieEnabled && tolower(NSZombieEnabled[0]) == 'y')
{
Method dealloc = class_getInstanceMethod(self, #selector(dealloc));
Method arczombie_dealloc = class_getInstanceMethod(self, #selector(arczombie_dealloc));
method_exchangeImplementations(dealloc, arczombie_dealloc);
}
}
- (void) arczombie_dealloc
{
Class aliveClass = object_getClass(self);
[self arczombie_dealloc];
Class zombieClass = object_getClass(self);
object_setClass(self, aliveClass);
objc_destructInstance(self);
object_setClass(self, zombieClass);
}
#end
You will find more information about this workaround in my blog post Debugging with ARC and Zombies enabled.
Turns out it is an iOS bug. Apple has contacted me and indicated they've fixed this in iOS 6.
to answer the second question you would need to remove the observer from NSNotification - that will keep it from calling the view.
Normally, you would do this in the dealloc but with that zombie issue maybe it's not getting called. Maybe you could put that logic in viewDidUnload?
Because you have open NSZombieEnabled, this let the object not call dealloc, and put the object to a special place. you can close NSZombieEnabled and have try again. And double check if your code have circle retain condition.
I'm coding a library (Obj-C for iPhone) that I want to package and sell, so I obviously need to work out any design kinks before listing it for sale. I am also utilizing this library to help me develop another app.
My library is heavily built on task delegation. The primary function I have is to launch a (potentially) long-running process, and when it's done, I call a Delegate Protocol method in the class's delegate.
An additional complicating factor here is that I will often schedule this task to fire off every 30 seconds or so. Usually, I do this with [self performSelector:#selector(someMethod:) withObject:nil afterDelay:30] rather than using an NSTimer. Then, when the delegate method successfully returns, I process the returned data and trigger the method to fire in another 30 seconds. This gives me 30 seconds BETWEEN method calls, rather than 30 seconds FROM THE START OF ONE CALL TO THE NEXT. (This is mainly just in case the call ever takes more than 30 seconds, which shouldn't happen.)
The error that I'm catching is that sometimes, the Delegate callback method is failing with an EXC_BAD_ACCESS error. Based upon my investigation, it appears that the delegate of my class library has disappeared (been released/dealloced) since the long-running process was initiated. Thus, when it calls [[self Delegate] doSomeDelegateMethod], it's accessing a released object.
I tried first checking [[self Delegate] respondsToSelector:#selector(doSomeDelegateMethod)], but even that access apparently also throws the EXC_BAD_ACCESS.
It doesn't yet seem that checking for [self Delegate] == nil is the right way to go, either.
One way I think I have solved the problem, in this specific instance, is when the view controller that instantiates my object is disappearing (and therefore on its way to the garbage dump), I call [NSObject cancelPreviousPerformRequestsWithTarget:self]. This apparently fixes the problem. (Does this "fix" also indicate that my object "knows" about the call to come and keeps itself in memory until it can successfully, desperately, fire off its final shot?)
This appears to put a band-aid on a bullet wound. Yes, it appears to stop my app from breaking this time, but my gut tells me that this is a poor solution.
I've also considered setting the custom object to nil in my viewWillDisappear:animated: method, which is probably the correct coding pattern, but it doesn't seem right that the customer has to be so precise in handling my objects.
What's really bugging me, though, is that I haven't yet found a way, as a library developer, to "box in" my code so that it won't throw an exception for the user if they don't do just the right things. Basically, I'd like a way to have my object:
Get a request.
Go look for the answer.
Find the answer.
Try to return the answer.
Realize that there's nothing on the other end.
Give up and die on its own. (OK, so "die on its own" probably won't happen, but you get the point.)
One interesting side point:
A main reason I have for preventing this type of error from occurring is this:
I did the following steps:
Built my library's .h/.m files.
Generated my library's .a output file.
Imported my library's .a/.h files into another project.
Had the error described above.
Got to peruse the code from one of the .m files that SHOULD have been hidden inside the .a file.
Am I missing something here? Am I really risking exposing my entire source code if it ever throws an error for a client? (This is just a side issue, but I'm fairly concerned here!)
Thanks for any help you can provide to help me be a better programmer!
---EDIT---
I have found another reason why this is important. In another view controller, where I am using this library, I implemented the NSTimer strategy. If the view is popped from the navigation stack (i.e., in the viewWillDisappear:animated: method), I invalidate said timer. So, no more calls will go to my library after the view disappears.
Here's the rub: what if the view disappears IN THE MIDDLE of the long-running call? Yes, it's tricky and unlikely to do, but I just had it happen on the simulator. In particular, THIS is why I'm looking for a workaround to let my code realize "hey, there's nothing on the other end of this pipe" and then fail gracefully. Anyone?
Thanks!
There are several approaches to this problem:
The traditional delegate approach (UITableViewDelegate) makes it a requirement to clear yourself as delegate before going away. This is traditionally done in dealloc of the delegate with otherObject.delegate = nil. Failure to do so is a programming error. That's basically what you're seeing. This is the common pattern when the delegate and the delegator have basically the same lifespan.
Another approach is how NSURLConnection handles it: retain your delegate until you're done. The key to this working well is that NSURLConnection has a lifespan of its own, so the retain loop will work itself out automatically. UITableView could not retain its delegate because this would almost always create a permanent retain loop. If your object lives for a while and then goes away, then this makes sense. Typically here the delegate has a much shorter lifespan than the delegator, so the retain loop doesn't hurt anything.
Any object that calls performSelector:withObject:afterDelay: should always call cancelPreviousPerformRequestsWithTarget:self in its own dealloc. This has nothing to do with your delegate, though. It should be self-contained to the object itself. (I don't know why I keep thinking this is true, and then proving to myself again that it isn't. When you call performSelector:...afterDelay:, you are retained, so you can't deallocate before it fires. My SIDE NOTE, while true, isn't relevant here.)
SIDE NOTE cancelPrevious... is really expensive in my experience. If you have to call cancelPrvious... very often, I recommend keeping your own one-shot NSTimer and just resetting it when it fires to get the same effect. performSelector:withObject:afterDelay: is just a wrapper around a one-shot timer.
I'm answering myself because the page warned me to not have extended discussions in the comments... :)
OK, so it appears that part of my answer is that [self performSelector:withObject:afterDelay:] automatically retains my object until it gets to "fire that shot", at which point I'm guessing the view controller dies.
So, now it makes sense why my custom class is trying to access a released object when it tries to return its answer to its delegate, which is an __unsafe_unretained object, meaning that it can die at will (I think).
What I'd like now is a way to prevent this from causing an error. In .NET, I've got all sorts of error handling options to do this, but I'm unable to think of a fail-safe "bail out" here.
I've tried [[self Delegate] isKindOfClass:..., but can't be sure what kind of class the delegate will be, so it won't work.
I've also tried [[self Delegate] respondsToSelector:#selector(...)]. I'm not sure why this fails, but I get the EXC_BAD_ACCESS here, too.
What I don't want is my customers to be able to crash my product with such a simple, innocent mistake.
As an aside, does anyone know why this sort of failure gives me such easy access to the contents of the .m file that should be hidden inside my .a file? Did I build my library incorrectly?
Thanks!
Try setting Delegates to nil in dealloc.
example:
self.fetchedResultsController.delegate = nil;
I've seen this problem a lot lately and usually fix the problem. Even though delegates are supposed to be weak references, sometimes some private implementation is using them as well.
If I release, I get bad access, if I retain, I leak
That's where I had a similar problem.
Edit: When using ARC, you can still override dealloc for cleanup, you just can't call [super dealloc] or release anything.
How to solve memory allocation in ios ?give me the right way to solve memory issues and memory leaks.
The best way to avoid these Memory issues is through proper coding. Just go through the Apple reference on Memory Management.
You only release or autorelease
objects you own.
You take ownership of an object if you
create it using a method whose name
begins with “alloc”, “new”, “copy”, or
“mutableCopy” (for example, alloc,
newObject, or mutableCopy), or if you
send it a retain message.
You use release or autorelease to
relinquish ownership of an object.
autorelease just means “send a release
message in the future” (specifically:
when the used autorelease pool
receives a drain message—to understand
when this will be, see “Autorelease
Pools”).
Without more info all I can say is...
Release anything you init and/or alloc that is not autoreleased.
Delete anything that you call "new" on
free any data you malloc
Use Instruments to diagnose where your leaks are occuring.
Release anything you retain
release anything you init that is not autoreleased.
#Nipin, For solving memory issues, you'll have to release each object that you're allocating... ie, use [yourObject release]; for each object you call alloc method... Also, unload any textures that you're using [texturename unload];
[texturename release];
Do all these when you no longer requires those objects or textures and in most cases it can be where you exit from the scene...
follow the below link memory management
another link is small guide for quick point small article
After upgrading to iPhone OS 4.0 the application started to crash after switching between applications. The application crashes in the same place when the application receives a memory warning.
It seems like some objects are automatically deallocated when a memory warning is received and then when we try to use the deallocated objects the application crashes.
Is it possible to test if an object has been deallocated, so that we can reallocate them?
You can't test whether a specific object has been deallocated because after deallocation, the object no longer exist. The only thing you can do is test whether a reference to the suspected object from another object is still non-nil.
Your problem here isn't deallocation per se but rather mismanaged retention. You have an object that has been marked as no longer being in use and the system is killing it as the system should. The only reason that you see it during low memory is that the system stops and drains all the release pool instantly instead of waiting for the normal cycle.
You need to make sure you have properly retained all the objects you need so they won't be improperly released. A retained object is not deallocated even in low-memory situations.
Edit
I would add that the most common cause of low-memory crashes is assuming that a view or a resource in a view is always present even when the view is not displayed. The system will purge undisplayed views and their resources (like images) in low-memory. Check the didReceiveMemoryWarning of the view controllers.
You can add
-(void)dealloc { ... }
And leave it empty if it's the right to do, and add breakpoint in it.
This answer correct to ARC and NON-ARC
Implement the method dealloc inside a UIViewController to see the moment it is being released from memory
- (void) dealloc
Print the reference of any object you want to test.
NSLog("Get pointer: %#", self); // ViewController
Then set a break point at a place where you want to test if the object is still existing. If you ran into the breakpoint, check the objects pointer in the debugger with
`po [pointer_printed_before]
Here you can see, the pointer is not available anymore, there is no object anymore after the dealloc method printed a log.
Apple Developer Reference Library has a class reference for WebPreferences
I've searched SO, Dev Forums and Googled without any relevant results.
EXC_BAD_ACCESS signal is generated.
I can't find a crash report.. its happening on the simulator. The debugger is called, and I don't get a crash report.
EDIT
This is triggered when tapping a UITextField, leaving a UITextField or if a UITextField is set as first responder when loading a view (push on by a navigation controller).
It is not easy to reproduce. I can go for a hundred app-launch/debug cycles before it will happen again. And then it might happen 3 times in 5 launches.
I do have a thread list in the debugger that shows several references to WebPreferences.
You're on the right track if you are using NSZombie. EXEC_BAD_ACCESS is caused by accessing released objects.
It is normal for EXEC_BAD_ACCESS to "crash" in code paths that do not belong to you. Most likely your code created the over-released object.
The key part of using NSZombie is running the malloc_history on the command line. You'll get the call stack showing where the over-released object originated from. For example:
alt text http://static.benford.name/malloc_history.png
The screenshot shows my app crashing at [NSString stringByTrimmingCharactersInSet:] but that is certainly not who caused the crash.
I technique I use is to look at the earliest code path that you own. Most of the time the mistake lies there.
In this case, the object originated from the class [JTServiceHttpRequest requestFinished], in which I was not properly retaining a object.
If all else fails, go through all your code paths listed and verify your use of proper memory management rules.
My bet is that WebPreferences and UITextField behavior have nothing to do with the crash.
For any EXC_BAD_ACCESS errors, you are usually trying to send a message to a released object. The BEST way to track these down is use NSZombieEnabled.
This works by never actually releasing an object, but by wrapping it up as a "zombie" and setting a flag inside it that says it normally would have been released. This way, if you try to access it again, it still know what it was before you made the error, and with this little bit of information, you can usually backtrack to see what the issue was.
It especially helps in background threads when the Debugger sometimes craps out on any useful information.
VERY IMPORTANT TO NOTE however, is that you need to 100% make sure this is only in your debug code and not your distribution code. Because nothing is ever released, your app will leak and leak and leak. To remind me to do this, I put this log in my appdelegate:
if(getenv("NSZombieEnabled") || getenv("NSAutoreleaseFreedObjectCheckEnabled"))
NSLog(#"NSZombieEnabled/NSAutoreleaseFreedObjectCheckEnabled enabled!");
If you need help finding the exact line, Do a Build-and-Debug (CMD-Y) instead of a Build-and-Run (CMD-R). When the app crashes, the debugger will show you exactly which line and in combination with NSZombieEnabled, you should be able to find out exactly why.
The fact that it's crashing in _integerValueForKey: makes me strongly suspect that it's crashing on an over-released NSNumber. Over-releasing an NSNumber can lead to such bizarre crashes that it's almost humorous. Here's what happens:
You create a NSNumber for the integer "2"
The NSNumber class caches the NSNumber
You over-release it
The NSNumber class's cache now points to bad memory
Some completely unrelated piece of code creates an NSNumber for the integer "2"
The NSNumber class looks it up in its cache, and....
Bang
If you're running Snow Leopard, hit Cmd-Shift-A to let the analyzer look for memory management problems. Otherwise, go hunting in your use of NSNumbers.
agreed with previous responders about NSZombie. Most often this thing happens when you use your class as a delegate of a UITextView(or any else class) and also refer it in IBOutlet variable. when you leave your viewcontroller - it become deallocated. but if you didn't release IBOutlet variable in - (void) dealloc method - UITextView will still send calls to released delegate (your view controller).
Sounds more like an Auto-Release bug. You might be releasing something you don't "own" and the NSAutoRelease pool is running and trying to clean up something that was already released?
Did you release something you didn't "alloc"? For example, you wouldn't do:
NSString *test = #"testing";
[test release];
As this will cause the crash to happen when the Auto Release pool runs and attempts to release the NSString.