iOS dealloc crash - ios

find a strange code here
I have a viewcontroller, it has an array with books, and click the cell, then push to a detailViewController, detailVC has a variable infoDict,
#property (nonatomic,retain) NSMutableDictionary * infoDict;
navigationController push
DetailViewController * tDVC = [[DetailViewController alloc] init];
tDVC.infoDict = infoDict;
[self.navigationController pushViewController:tDVC animated:YES];
[tDVC release];
tap the back button, pop back, and inside dealloc of DetailVC
-(void)dealloc
{
[super dealloc];
NSLog(#"before %d",infoDict.retainCount);
[infoDict release];
}
but when I tap back, in this dealloc app crashes randomly, EXC_BAD_ACCESS.
when move [super dealloc] to the bottom of dealloc, it seems back to normal.
pls help me to understand this , many thanks

[super dealloc] deallocates the object itself. If you type dealloc and let Xcode autocomplete, you get this:
- (void)dealloc
{
<#deallocations#>
[super dealloc];
}
Meaning you should release objects and properties before you call [super dealloc]

Your -dealloc implementation is out of order. The call to -[super dealloc] must be the absolute last invocation in the dealloc method. When you access the ivar infoDict, the compiler is really doing something like self->infoDict and by this point, self has been deallocated and is no longer valid.
If at all possible, I recommend using ARC instead of manually managing memory.

Try
its better if you use self.infoDict = nil; instead of [infoDict rlease];
-(void)dealloc
{
NSLog(#"before %d",infoDict.retainCount);
[infoDict release];
[super dealloc];
}

Related

Login flow failing after upgrading to iOS9

After upgrading my app to iOS9 I’am getting an error in my app which says:
: objc[344]: Cannot form weak reference to instance (0x15919e00) of class LoginVC. It is possible that this object was over-released, or is in the process of deallocation.
Below is the function in which i get this error:
-(void)dismissLogin {
self.isLoggingIn = NO;
[self stopLoginAnimation];
[self dismissViewControllerAnimated:YES completion:NO];
[[NSNotificationCenter defaultCenter] removeObserver:self];
[self.appDelegate setLoginVC:nil];
[self.view removeFromSuperview];
//[APPDEL selectTabBar];
}
The app gets stuck at the login screen and doesn't switch to next screens.
This error doesn’t come in iOS8.
Can anyone help me with this issue.
Make sure you are not using instance being deallocated.
I have the same issue. It was not occurring in iOS 8 but occurred in iOS 9. Because I was overriding setDelegate method like this.
-(void)setDelegate:(id<UICollectionViewDelegate>)delegate{
_internalDelegate = delegate;
[super setDelegate:self];
}
So in iOS 9, OS sets delegate to nil on de-allocation, but I was setting it to self. So quick fix was
-(void)setDelegate:(id<UICollectionViewDelegate>)delegate{
_internalDelegate = delegate;
if (delegate) {
//Set delegate to self only if original delegate is not nil
[super setDelegate:self];
}else{
[super setDelegate:delegate];
}
}
I ran into this issue recently and this helped me come to the conclusion that I did. The only issue I have with the solution provided above is that if you need the subclass to gain functionality even when its internalDelegate is nil, it just won't work.
Here's the solution I came up with that both prevents the crash and allows functionality to exist even with a nil internalDelegate. Figured I'd share in case anyone else came across this.
Create a second internal property, I called this weakSelf
#property (nonatomic, weak) LoginVC *weakSelf;
Inside any initialization methods, set weakSelf to self
- (id)init {
if ((self = [super init])) {
self.weakSelf = self;
}
}
Update delegate method
- (void)setDelegate:(id)delegate {
_internalDelegate = delegate;
[super setDelegate:self.weakSelf];
}

Dealloc not called on subview with ARC

I have a not usual architecture. With one UIViewController and many subview's. I use UIView like viewController and UIViewController for transition animation.
UIView with many subview, which i push on main window, i removeFromSuperview and all ok, but subview not call dealloc method. Also i try to clean objects
- (void) dealloc {
NSLog(#"ActivityShowVC dealloc");
[showView removeFromSuperview];
showView = nil;
}
This called.
- (void) dealloc {
NSLog(#"ActivityShowView dealloc");
[mainScroll removeFromSuperview];
[titleView setDelegate:nil];
[titleView removeFromSuperview];
titleView = nil;
[photoView setDelegate:nil];
[photoView removeFromSuperview];
photoView = nil;
[predictionView setDelegate:nil];
[predictionView removeFromSuperview];
predictionView = nil;
[calendarView setDelegate:nil];
[calendarView removeFromSuperview];
calendarView = nil;
[descriptionView setDelegate:nil];
[descriptionView removeFromSuperview];
descriptionView = nil;
}
But this have some problem.
If dealloc is implemented and not called then there is something retaining the instance. You need to rethink the strong references to it.
Dealloc is not a good place to do anything other than releasing resources since the instance is no longer fully functional nor in a complete state. Doing things like: [showView removeFromSuperview]; are best done explicitly prior to deallocation.
As #Greg stated, most or all of what you are doing in dealloc is not needed under ARC. Subviews are now generally weak so no explicit dealloc is necessary. In fact they may be already gone depending on the order of the teardown of the view hierarchy.
I have solved a similar problem. In my Viewcontroller, I have a NSTimer pointer created, when I put the code below in 'viewWillDisappear', 'dealloc' is called.
if (_timer) {
[_timer invalidate];
_timer = nil;
}

Dealloc causing crash in changing between scenes in Cocos2D

I'm building a Cocos2D game in which after two certain sprites collide (by simple bounding box technique), I call
[[CCDirector sharedDirector] replaceScene:gameOverScene];
to change to the game over scene.
Once it initializes the game over scene with everything in it, the game crashes and goes to this method in ccArray.m class:
void ccArrayRemoveAllObjects(ccArray *arr)
{ while( arr->num > 0 )
CC_ARC_RELEASE(arr->arr[--arr->num]);
}
with the message:
Thread 1: Program received signal: "EXC_BAD_ACCESS".
I tried to debug using breakpoints and figured out that once my gameOver scene gets initialized and ready to display, the dealloc method in the previous class (the gameplay class, which called the replace scene) gets called and after which it throws this error.
My update method:
-(void)update:(ccTime)dt
{
if (CGRectIntersectsRect(plane.boundingBox, enemy.boundingBox)) {
CCScene *gameOverScene = [GameOverLayer sceneWithWon:NO];
[[CCDirector sharedDirector] replaceScene:gameOverScene];
} }
My dealloc method:
- (void) dealloc
{
[super dealloc];
[_monsters release];
_monsters = nil;
[mole release];
mole = nil;
[text release];
text = nil;
[mBG1 release];
mBG1 = nil;
[mBG2 release];
mBG2 = nil; }
I have no clue why this is happening. Please help.
Thanking you in anticipation.
You are calling super's dealloc before you are deallocating your gameplay scene.
Call super's dealloc at the end of your dealloc method :
- (void) dealloc {
[_monsters release];
_monsters = nil;
[mole release];
mole = nil;
[text release];
text = nil;
[mBG1 release];
mBG1 = nil;
[mBG2 release];
mBG2 = nil;
[super dealloc];
}
When you are calling super's dealloc first you are releasing your instance making it members invalid so accessing them after the dealloc will create memory bad access issues
because you didn't show enough code,i can only guess that some of these objects,such as _monsters,mole,text,mBG1,mBG2,were autoreleased before you release them in the dealloc funtion.So,they can not be released anymore.This is concerned ARC-automaic reference counting which you should know, it's basis of ios.
try this only:
- (void) dealloc {
[super dealloc];
}

App is crashing while releasing view controller object

My app is crashing while releasing view controller object.
Here is my code.
TagCloudWebViewController *controller=[[[TagCloudWebViewController alloc]init]autorelease];
controller.htmlString=[[notification userInfo] valueForKey:#"url"];
[self.navigationController pushViewController:controller animated:YES];
This is my code from wheny above method is called
-(void)viewDidLoad{
[super viewDidLoad];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(openTextInWebview:) name:#"kTouchTextUrl" object:Nil];
}
and
#pragma mark - UIGestureDelegate
- (void)longPressRecognized:(UILongPressGestureRecognizer *)longPressRecognizer {
CGPoint touchPoint = [longPressRecognizer locationInView:self];
NSArray *subviews = self.subviews;
for (int i=0; i<subviews.count; i++) {
TagView * tagLabel = (TagView *)[subviews objectAtIndex:i];
if ( CGRectContainsPoint( [tagLabel frame], touchPoint ) ) {
NSArray*objectArray=[[[NSArray alloc] initWithObjects:tagLabel.customLink, nil] autorelease];
NSArray*keyArray=[[[NSArray alloc] initWithObjects:#"url", nil] autorelease];
NSDictionary *userInfo = [NSDictionary dictionaryWithObjects:objectArray forKeys:keyArray ];
[[NSNotificationCenter defaultCenter] postNotificationName:#"kTouchTextUrl" object:nil userInfo:userInfo];
//[[UIApplication sharedApplication] openURL:[NSURL URLWithString: tagLabel.customLink]];
break;
}
}
}
and this is notification method
DidLoad method
- (void) viewDidLoad {
[super viewDidLoad];
_webView = [[UIWebView alloc] initWithFrame:self.view.bounds];
_webView.delegate = self;
_webView.autoresizingMask = (UIViewAutoresizingFlexibleWidth
| UIViewAutoresizingFlexibleHeight);
_webView.scalesPageToFit = YES;
[self.view addSubview:_webView];
[self initSpinner];
if (htmlString) {
[self openURL:[NSURL URLWithString:htmlString]];
}
}
WebView delgate method
-(void) webViewDidStartLoad:(UIWebView *)webView {
self.navigationItem.title = #"Loading...";
[spinnerView startAnimating];
isLoading = YES;
}
-(void) webViewDidFinishLoad:(UIWebView*)webView {
self.navigationItem.title = [_webView stringByEvaluatingJavaScriptFromString:#"document.title"];
[self performSelector:#selector(stopSpinner) withObject:nil afterDelay:0.1];
isLoading = NO;
}
-(void) webView:(UIWebView*)webView didFailLoadWithError:(NSError*)error {
[self webViewDidFinishLoad:webView];
[self performSelector:#selector(stopSpinner) withObject:nil afterDelay:0.1];
isLoading = NO;
}
(void) openURL:(NSURL*)URL {
NSMutableURLRequest* request = [NSMutableURLRequest requestWithURL:URL];
[_webView loadRequest:request];
}
Update: The following answer was in response to the original question of why the UIViewController with a UIWebView was not appearing. The OP's original theory was that it was related to some problem regarding the premature releasing of the view controller object. But, as outlined in my answer below, I suspect the problem was related to the creation of the view controller itself. Anyway, my answer to the original question follows (but it unfortunately has nothing to do with the revised question):
I personally don't suspect the problem has anything to do with the
releasing of the controller. I think it is in the creation of the
controller's view. There's nothing in the above code that causes the
object to be released, so you problem rests elsewhere and you need to
show more code. If you're concerned about your notification center
stuff, try bypassing it and just add a button that does your
TagCloudWebViewController alloc/init, sets htmlString and pushes,
and see if that still causes your program to crash, which I suspect it
will.
I notice that you're creating your controller via alloc and init,
but not initWithNibNamed. According to the UIViewController Class
Reference:
"If you cannot define your views in a storyboard or a nib file,
override the loadView method to manually instantiate a view
hierarchy and assign it to the view property."
So, bottom line, either use a NIB, use a storyboard or define a
loadView. Defining a viewDidLoad doesn't preclude the need for a
loadView. You need to create a view for your controller, which is
done for you if you use NIB or storyboard, or you have to do manually
via loadView, if you don't use NIB or storyboard.
See
iPhone SDK: what is the difference between loadView and viewDidLoad?
for a discussion of the differences between viewDidLoad and
loadView.
I don not see any thing that causing crashing.I think you have changed your question.As per question you not using ViewController any where.Please show more details.
Updated: Please check, you are creating autoreleased object, it might be you are releasing some where by mistake.Try to avoid autoreleased object as it remain in the Pool and later releases ,which may causes a memory issue for you.
The above problem is occurs due to WebView delgate. After pressing back button the reference of the object is deallocating from memory due to this app is crashing while releasing the viewcontroller object. I did some thing like
-(void) viewDidDisappear:(BOOL)animated{
if([_webView isLoading]) {
[_webView stopLoading];
}
[_webView setDelegate:nil];
}
due to above code my crashing has been resolved

UIWebView - When (or how) does CFData get released?

after multiple days of banging my head against the wall and having sleepless nights I'm hoping to find some help here. I've gone through various posts here, but none of the answers seem to provide a resolution for me.
In short, my problem is that my App crashes after heavy usage (>10min) of the UIWebView (e.g. opening larger news paper sites in series - one after the other).
To give more details:
I am writing an iPhone App and from the MainViewController I push a browserViewController on the navigationController. The browserViewController loads a nib which contains a UWebView (I do not create the WebView programatically). The UIWebView is wired up using Interface Builder.
When going back to Main and then going again to the browserViewController, I only recreate the browserViewController if it is nil. (I want to keep the content that is loaded i the UIWebView - only if there is a memory warning shoud this view be unloaded and release all memory used).
In both, MainViewController and browserViewController I am responding to memory warnings, but this seems not to provide enough relief.
Looking at Instruments I noticed that for example CFData(store) keeps increasing. And even if I simulate a memory warning (see code below) and call viewDidUnload on browserViewController, CFData remains allocated and does not get freed.
So my biggest question is:
How to free up memory created from "browsing"?
This counts for two cases:
- how do I make sure that viewDidUnload properly frees memory allocated my CFData(store)?
- how to free up memory when the user keeps loading pages in browserViewController?
.
Who manages CFData?
See below for my simplified sample code:
MainViewController.h
// MainViewController.h
#import "myAppDelegate.h"
#import "BrowserViewController.h"
#interface MainViewController : UIViewController {
BrowserViewController *browViewController;
}
- (void) switchToBrowserViewController;
#end
MainViewController.m
// MainViewController.m
#import "MainViewController.h"
#implementation MainViewController
- (void)didReceiveMemoryWarning {
// Releases the view if it doesn't have a superview.
[super didReceiveMemoryWarning];
[browViewController release];
browViewController = nil;
}
- (void)viewDidUnload {
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}
- (void)dealloc {
[browViewController release];
browViewController = nil;
[super dealloc];
}
- (void) switchToBrowserViewController {
// create new browViewController if needed
if ( browViewController == nil ) {
browViewController = [[BrowserViewController alloc] initWithNibName:#"BrowserViewController" bundle:nil];
}
browViewController.navigationItem.hidesBackButton = YES;
[((myAppDelegate *)[UIApplication sharedApplication].delegate).navController setNavigationBarHidden:YES animated:NO];
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration: 1];
[UIView setAnimationTransition:UIViewAnimationTransitionCurlUp forView:
((myAppAppDelegate *)[UIApplication sharedApplication].delegate).navController.view cache:YES];
[((myAppAppDelegate *)[UIApplication sharedApplication].delegate).navController pushViewController:browViewController animated:NO];
[UIView commitAnimations];
}
#end
BrowserViewController.h
// BrowserViewController.h
#import <UIKit/UIKit.h>
#import "myAppDelegate.h"
#interface BrowserViewController : UIViewController <UIWebViewDelegate> {
IBOutlet UITextField *browserURLField;
IBOutlet UIWebView *browserWebView;
}
#property (nonatomic, retain) UIWebView *browserWebView;
- (void) loadURLinBrowser;
#end
BrowserViewController.m
// BrowserViewController.m
#import "BrowserViewController.h"
#implementation BrowserViewController
#synthesize browserWebView;
- (void)viewDidLoad {
[browserWebView setDelegate:self];
[super viewDidLoad];
}
- (void)didReceiveMemoryWarning {
// Releases the view if it doesn't have a superview.
[super didReceiveMemoryWarning];
}
- (void)viewDidUnload {
[super viewDidUnload];
[browserWebView stopLoading];
[browserWebView setDelegate:nil];
[browserWebView removeFromSuperview];
[browserWebView release];
browserWebView = nil;
browserURLField = nil;
}
- (void)dealloc {
[browserURLField release];
browserWebView.delegate = nil;
[browserWebView stopLoading];
browserWebView = nil;
[browserWebView release];
[super dealloc];
}
- (void) switchBackToMainViewController {
[((myAppDelegate *)[UIApplication sharedApplication].delegate).navController setNavigationBarHidden:NO animated:NO];
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration: 1];
[UIView setAnimationTransition:UIViewAnimationTransitionCurlDown forView:((myAppAppDelegate *)[UIApplication sharedApplication].delegate).navController.view cache:YES];
[((myAppAppDelegate *)[UIApplication sharedApplication].delegate).navController popViewControllerAnimated:NO];
[UIView commitAnimations];
}
- (void) loadURLinBrowser {
NSURL *url = [[NSURL alloc] initWithString:browserURLField.text];
NSMutableURLRequest *request = [[NSURLRequest alloc] initWithURL: url];
[browserWebView loadRequest: request];
[request release];
[url release];
}
#end
I have tried various recommendations from other posts. For example:
1) Loading an empty page into the WebView.
NSString *html = #"<html><head></head><body></body></html>";
[browserWebView loadHTMLString:html baseURL:nil];
2) using removeAllCachedResponses on various places in the above code
[[NSURLCache sharedURLCache] removeAllCachedResponses];
3) setSharedURLCache did also not provide relief ( I also used this in the AppDelegate applicationDidFinishLaunching).
NSURLCache *sharedCache = [[NSURLCache alloc] initWithMemoryCapacity:0 diskCapacity:0 diskPath:nil];
[NSURLCache setSharedURLCache:sharedCache];
[sharedCache release];
Unfortunately none of this has helped to "clear the cache" or to free memory allocated by CFData(store).
If anyone could shine some light on this and let me know what I'm missing or doing wrong I would greatly appreciate this.
.
.
Edit:
After the initial reply from KiwiBastard I added a screen shot that shows what I observe in Instruments:
.
.
Edit from June 2010:
I have still not been able to solve this.
In a second attempt, I created the UIWebView completely programmatically.
Still same issue. However I noticed a strange behavior. If I load for example a PDF document into the webView and I do not scroll the PDF page up or down, the webView & data gets successfully released. However as soon as I scroll to the second page, the dealloc won't work any longer and my App ends up running out of memory at some point. This is totally strange and I cannot get this resolved.
Anyone any idea? Help?
To release CFData you only need to call CFRelease(your CFData object name).
I think what could be happening is that your Browser is never deallocated, and the viewDidUnload is probably never being called.
Because your MainViewController has a variable of type BrowserViewController that is never released, that will be resident for the life of your app. Also because you are only switching views, the view will stay in memory too.
Can I suggest you try creating the BrowserViewController variable when you need it, and release it once it has been pushed by the navcontroller eg
BrowserViewController *browViewController = [[BrowserViewController alloc] initWithNibName:#"BrowserViewController" bundle:nil];
browViewController.navigationItem.hidesBackButton = YES;
[((myAppDelegate *)[UIApplication sharedApplication].delegate).navController setNavigationBarHidden:YES animated:NO];
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration: 1];
[UIView setAnimationTransition:UIViewAnimationTransitionCurlUp forView:
((myAppAppDelegate *)[UIApplication sharedApplication].delegate).navController.view cache:YES];
[((myAppAppDelegate *)[UIApplication sharedApplication].delegate).navController pushViewController:browViewController animated:NO];
[UIView commitAnimations];
[browViewController release];
I know that it will slightly effect performance because it has to load the nib everytime, but you distinctly don't want to cache the vc anyway?
Somewhere I read, this is a well known bug with UIWebView. Some says to use a static webview object to avoid initializing it again and again but couldn't find a proper solution. Even you follows the same approach. Luckily my requirement was a plain web view with an image. So I ended up using a custom controller with a UIImageView and a UITextView without editing. Works fine for me.

Resources