iPhone SDK: SDWebImageDownloader Crashing - iphone

I'm using the SDWebImageDownloader library to download images asynchronously.
The problem i'm having is when I click the back button before the images finish download the app is crashing on the following line in the SDWebImage Class:
if([delegate respondsToSelector:#selector(imageDownloaderDidFinish:)])
This is how i'm using it in my code:
sdDownloader = [[SDWebImageDownloader downloaderWithURL:headerImgURL delegate:self]retain];
What is causing it to crash? I'm retaining it and i'm not releasing it anywhere.

When you say you are retaining "it", what do you mean by "it"? If it's crashing with EXC_BAD_ACCESS when you try to send a message to delegate, it's likely that delegate is a dangling pointer because it's being released prematurely. What is retaining delegate? What is releasing delegate?

Related

Parent ViewController deallocated upon memory warning

I have a MainViewController, from which a new VideoPageViewController is presented modally.
In the ViewPageViewController, it will load a web page and launch the video, which is a heavy operation and sometimes causes memory warning. When it is ready to return to the MainViewController by dismissModalViewController, it says the MainViewController is already deallocated! The app thus crashes.
This happens sometimes, but not always.
Is there any exception handling I can take on it? Can I recreate the parent view controller? HELP!
Thanks
Just retain the MainViewController so it's not released when that happens.
You can probably do that in your application delegate, or in the class that owns it.
Remember to release it when/if you are done using it, so it's properly disposed of.

button click crashes

I have below code in a IBAction linked to a UIButton to change the background image on Button Click.
UIImage *imageGreen=[UIImage imageNamed:#"bgGreen.png"];
[clickButton setBackgroundImage:imageGreen forState:UIControlStateNormal];
[imageGreen release];
after clicking the button three times it crashes the app in iPhone Simulator 4.0. I am alreading releasing the imageGreen object, what else can i do to prevent this.
No, you should not release imageGreen.
This variable is received with a convenient method, thus will autorelease itself. Calling -release will cause double-release error and crash the program.
Please read the memory management guide.

Stop lazy-loading images?

Here's the issue – I followed along with the Apple lazy-load image sample code to handle my graphical tables. It works great. However, my lazy-load image tables are being stacked within a navigation controller so that you can move in and out of menus. While all this works, I'm getting a persistent crash when I move into a table then move immediately back out of it using the "back" button. This appears to be a result of the network connections loading content not being closed properly, or calling back to their released delegates. Now, I've tried working through this and carefully setting all delegates to nil and calling close on all open network connections before releasing a menu. However, I'm still getting the error. Also – short posting my entire application code into this post, I can't really post a specific code snippet that illustrates this situation.
I wonder if anyone has ideas for tasks that I may be missing? Do I need to do anything to close a network connection other than closing it and setting it to nil? Also, I'm new to debugging tools – can anyone suggest a good tool to use to watch network connections and see what's causing them to fail?
Thanks!
Have you run it through the debugger (Cmd-Y)? Does it stop at the place where the crash is happening? That should show you in code where the issue is happening. I'm betting the issue has to do with over-releasing something rather than cleaning up connections. Are you getting EXC_BAD_ACCESS? Check any delegates and make sure they are nil when -viewWillDisappear gets called. That way, if anything tries to call back to a delegate, it will just be a no-op.
You may also want to try enabling zombies (NSZombieEnabled) which will tell you when an object that has been released is being accessed again. It's very helpful in finding over-released objects.
Ah ha... after a large zombie hunt (thanks, Matt Long), I discovered that the issue stems from an error in Apple's LazyTableImages sample code. That example provides the following implementation for canceling all image loads, which I turned into a general-purpose stopAllImageLoads method...
From RootViewController.m in LazyTableImages sample code:
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// terminate all pending download connections
NSArray *allDownloads = [self.imageDownloadsInProgress allValues];
[allDownloads performSelector:#selector(cancelDownload)];
}
There is in error in the last line of the above method where performSelector is called on an array of objects. The above implementation calls the selector on the array itself, rather that on each object in the array. Therefore, that last line should be this:
[allDownloads makeObjectsPerformSelector:#selector(cancelDownload)];
Once that line was changed, everything else fell into place. It turns out I wasn't calling my stopAllImageLoads method where I meant to – I had disabled it at one point because it was causing an error. Once that was back in place, the memory issues cleared up because image loads were successfully canceled before the table delegate was released.
Thanks all for your help.
If you're doing ANY asynchronous function (network requests, Core Location updates, etc), you run the risk that your view controller that is the delegate of that action is deallocated by the time the async function returns. i.e. you back out of the view and take the delegate target away from the background process. I've dealt with this several times.
Here's what you do. Use the ASIHTTPRequest library (which you should be doing anyway--it's brilliant). Create a synthesized property to hold your request. Then in viewWillDisappear, call -cancel on your request. To be safe, I also set its delegate to nil, but that should be unnecessary.
Here's a sketch of what you want to do. Note I typed this right here, haven't syntax-checked it or anything.
#implementation MyViewController
#synthesize req //this is an ASIHTTPRequest *req.
-(void)viewDidLoad
{
//make an NSURL object called myURL
self.req = [ASIHTTPRequest requestWithURL:myURL];
self.req.delegate = self;
[self.req startAsynchronous];
}
-(void)viewWillDisappear
{
[self.req cancel];
}
-(void)requestFinished:(ASIHTTPRequest *)request
{
NSString *string = [request responseString];
}

NSZombieEnabled hides EXC_BAD_ACCESS error entirely

So I have a subclass of a UIView that starts causing EXC_BAD_ACCESS errors when I go through a specific set of conditions (run on iPad instead of iPhone or simulator, first login only). It throws the exception when the UIView subclass gets autoreleased from the pool (i.e. the pool is releasing, not when I'm calling [view autorelease], during the last line, where I have [super dealloc]. I heard about using NSZombieEnabled, so I tossed that on to see if I could get any more information about it, but now it hides the error completely!
Does anyone know a bit more about this type of situation? I thought NSZombie would start spewing stuff into my console like before, but I'm hoping that the nonexistance of errors would tell me some sort of information as well.
- (void)dealloc
{
[loadingLabel release];
[indicatorView release];
[super dealloc];
}
Edit: Ok, so I sorta solved the underlying problem:
One of my properties was:
#property (nonatomic,retain) NSString * title;
However, the code for that property is as follows (loadingLabel is a UILabel):
- (void)setTitle:(NSString *)title
{
loadingLabel.text = title;
[loadingLabel sizeToFit];
[self setNeedsLayout];
}
- (NSString *)title
{
return loadingLabel.text;
}
I don't actually retain anything, but rather only do a UILabel.text, which is a copy property. So I changed my own title property to reflect this, and the error has disappeared.
However, I still don't really know how or why this error popped up in the first place, and why it only appears on the iPad platform (not the iphone, or even the ipad simulator).
So I have a subclass of a UIView that starts causing EXC_BAD_ACCESS errors when I go through a specific set of conditions (run on iPad instead of iPhone or simulator, first login only). It throws the exception when the UIView subclass gets autoreleased from the pool (i.e. the pool is releasing, not when I'm calling [view autorelease], during the last line, where I have [super dealloc]. I heard about using NSZombieEnabled, so I tossed that on to see if I could get any more information about it, but now it hides the error completely!
You get EXC_BAD_ACCESS because you tried to work with a dead object.
NSZombieEnabled makes objects not die. Since the object never died, your app didn't crash. Instead, you'll get a message in the Console log (the Debugger Console when running under Xcode), telling you what you did wrong and suggesting a breakpoint to set.
To be more specific, the NSZombie message will tell you what class of object you sent a message to, and what message you sent it. If you set the breakpoint and run your app with the debugger active, the debugger will interrupt (“break”) your app at that point, so that you can look around and see what sent the zombie object the message.
I don't actually retain anything, but rather only [assign to] a UILabel.text, which is a copy property.
Thus, the string presumably died off for not being owned by anything. With NSZombieEnabled and the above technique, you can confirm the theory that it was the string that was dying off prematurely.
A better and easier way, though, is to use Instruments's Zombies template. Instead of a message appearing in Xcode's Debugger Console, a flag in will appear Instruments's timeline with the information. That flag will have a go-to-iTunes-Store (➲) button you can click for more information about the problem.
Could you clarify - do you mean that you throw an EXC_BAD_ACCESS exception or you (on purpose) cause the system to throw an EXC_BAD_ACCESS exception? How do you do this? Please show some code. NSZombie will spew to the console if you try to call an instance method on it. Are you doing that?
NSZombie should produce output to the console in the same location a crash would have occurred.
Have you tried also running Instruments with the ObjectAlloc tool, and enabling both retain count and zombie detection in there (you need it both in the executable and configure the ObjectAlloc instrument, click on the "i" next to ObjectAlloc). When a message is sent to a zombie that instrument will flag you with a special popup saying a zombie was detected.
Remember the iPad SDK is still beta, maybe you should report this but to apple if you can confirm this to be a bug. Unfortunately their bugtracker is horrible from my experience.
The behavior of NSZombie is to never decrease an objects retain cound if release is called. However it keeps track of the would-be retain count and logs acess to the object after it would have been deleted on the console. It puts the Object adress alongside the error message, together with Instruments you can easily locate the Object at that adress and determine where it has been alocated and who retained/released it.

iPhone Simulator crash with WebPreferences in the thread list

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.