I have a weird problem which causing crash, when I touch textfield quickly when my UITableviewContrller shows up.
It doesn't not always happen. maybe about 2 crashes of 10 tests.
It works fine previously, but I don't know why it sometimes crash now.
iPhone4 on iOS7.1.
crash message. It crash in OrderTableViewController. Before crash, I check that the retainCount is 1, so I don't know how this happen. I have no idea why it's deallocated.
2014-04-01 09:35:57.628 [17027:60b] *** -[OrderTableViewController respondsToSelector:]: message sent to deallocated instance 0x17fef520
Here's my code for pushing viewController.
I believe it's correct. I use it all the time.
OrderTableViewController *orderViewController = [[OrderTableViewController alloc] initWithNibName:#"OrderTableViewController" bundle:nil];
orderViewController.hidesBottomBarWhenPushed = YES;
[self pushViewController:orderViewController animated:YES];
[orderViewController release];
I don't declare textfield as retain. I'm not sure if it's the problem.
UITextField *uname;
UITextField *utel;
uname = [[UITextField alloc] initWithFrame:CGRectMake(180, 8, 120, 30)];
uname.BorderStyle=UITextBorderStyleRoundedRect;
uname.keyboardType=UIKeyboardTypeNamePhonePad;
uname.delegate=self;
utel = [[UITextField alloc] initWithFrame:CGRectMake(180-40, 8, 120+40, 30)];
utel.BorderStyle=UITextBorderStyleRoundedRect;
utel.delegate=self;
utel.keyboardType=UIKeyboardTypeNumberPad;
- (void)dealloc {
[uname release];uname=nil;
[utel release];utel =nil;
[super dealloc];
}
I tried profile by instrument with zombie template, but I can't find something useful.
Here're questions.
1. Any ideas for this issues?
2. How to workaround this kind of issues. I tried remove the code of [orderViewController release]; and retainCount become 2, it seems OK for 20 tests. But, it causes memory leak. how to reduced this leak issues. Could I release it in the navigation controller, when I don't need it? I know it's more complicated, but I don't know better way to workaround.
Form message of crash , it seems related to OrderViewController over-release, but I can't find the problem. Is there other problem causing the error message?
Thank you for your help.
don't use retainCount. It can never return 0, for example.
the problem is that your delegate is being deallocated before the view controller is done mucking with it. You could fix that by setting the delegate to nil in dealloc, but that may likely not be correct either in that it indicates that your view controller will live longer than the thing that it delegates behavioral decisions too.
your dealloc method is wrong; in non-ARC, you must call [super dealloc];
you should use ARC
First check to make sure you aren't calling dealloc directly on it.
Then try running the Xcode Analyzer as it might find the problem for you.
Then try to enable an Exception Breakpoint and see if it stops somewhere useful.
If those don't work try implementing the -retain and -release methods on the OrderTableViewController and then place breakpoints in each of them. You can then track who is retaining and releasing it and you should be able to find who is overreleasing it.
- (id)retain
{
return [super retain];
}
-(oneway void)release
{
[super release];
}
You should nil the delegate. That is, uname.delegate = nil in dealloc.
Most likely the problem is you're releasing your viewController before the Navigation Controller has a chance to claim ownership. There are two ways around this:
release your controller after pushing it to the Nav Controller
autorelease your controller before pushing it. If you do this, the active NSAutoreleasePool (which you don't need to worry about) will take care of releasing your controller at a later time.
[orderViewController autorelease];
Related
This is a basic memory management code. I am dealing with an old app that does not have ARC implemented.
My question: Is it ok to access an instance variable after adding it to a view & releasing it.
In my opinion it is probably not right to access an instance variable after calling release on it, but can anyone advice ?
demoView = [[DemoView alloc] initWithFrame:[self demoRect:newType]];
[self addSubview:demoView]
[demoView release];
Later in code access it:
[demoView setBackgroundColor:[UIColor whiteColor]];
demoView.title = #"something";
object is released later on like this:
[demoView removeFromSuperview];
demoView = nil;
When this line is called, the retainCount of demoView is 1.
demoView = [[DemoView alloc] initWithFrame:[self demoRect:newType]];
after this line
[self addSubview:demoView]
retainCount gets increased to 2.
If nothing else is done but the demoView is released later in dealloc, or just removed, it will still have a retainCount of 1.
That is why the developer calls the
[demoView release];
to keep the retainCount at 1.
P.S.
In the older retain/release paradigm, you would have to maintain the retainCount and keep that in check. retainCount gets increased on alloc, on getting added to a UIView/NSArray/NSDictionary and on calling retain
And retainCount decreases when you call release, remove from a UIView/NSArray/NSDictionary.
When you add a subview to a view, subview is retained by view.
So, if you use a subview after you release a subview, it will work. But it is a really bad practice to use some object you had already released.
It's generally best to use accessor methods rather than directly manipulating ivars in manually reference counted code. Consider rewriting the implementation along the following lines:
self.demoView = [[[DemoView alloc] initWithFrame:[self demoRect:newType]]
autorelease]];
[self addSubview:demoView];
This way, if you remove the demo view from its superview you can safely keep it in memory should you ever want to add it back to the view hierarchy later, or move it to a different superview. In any case, the demo view should get a release message in dealloc so it can get cleaned up at the end of its owner's lifetime.
my code snippet:
- (void)viewDidUnload{
[super viewDidUnload];
self.statusView = nil;
self.tableView = nil;
self.noDataView = nil;
}
In a rare situation, my app crashed in line self.noDataView = nil;. When I debug by po self, it seemed that it's pointing something other than current controller. What is possible reason?
PS:self.tableView's delegate and dataSource is set to self in init method. Does that have any relation to this?
First, [super viewDidUnload] should be used as the last statement. However, that won't fix your error, probably.
The reason for your problem is quite simple. Your controller is overreleased somewhere. Do you have zombie detection enabled? The code where the application crashes is usually irrelevant because the problem happened earlier.
viewWillUnload is deprecated now, you can't count on it anymore, any question about it will lead you to the below references.
From Apple:
In iOS 6, the viewWillUnload and viewDidUnload methods of
UIViewController are now deprecated. If you were using these methods
to release data, use the didReceiveMemoryWarning method instead. You
can also use this method to release references to the view
controller’s view if it is not being used. You would need to test that
the view is not in a window before doing this.
And Quote WWDC 2012:
The method viewWillUnload and viewDidUnload. We're not going to call
them anymore. I mean, there's kind of a cost-benifit equation and
analysis that we went through. In the early days, there was a real
performance need for us to ensure that on memory warnings we unloaded
views. There was all kinds of graphics and backing stores and so forth
that would also get unloaded. We now unload those independently of the
view, so it isn't that big of a deal for us for those to be unloaded,
and there were so many bugs where there would be pointers into.
Edit:
For your problem in iOS 5.1, viewDidUnload is used to release anything you have made when the view was created, so unless you are creating or retaining objects it in viewDidLoad or your nib, you may not release them in viewDidUnload.
I can´t find where the problem is, but this code is crashing. Am I over releasing any object?
settings = [[SettingsViewController alloc] initWithNibName:#"SettingsController" bundle:nil];
settings.hidesBottomBarWhenPushed = YES;
NSArray * arrayWithRootController = [[NSArray alloc] initWithObjects:settings, nil];
[(UINavigationController*)([self.tabBar.viewControllers lastObject])setViewControllers:arrayWithRootController];
[arrayWithRootController release];
[settings release];
If I remove the line
[settings release];
The app doesn´t crash. but I am pretty sure its correct. May the problem be in another place?
Any ideas? Thanks a lot
You're not overreleasing in this snippet, but obviously something isn't right. Adding the root view controller to the array will retain it, but only for the life of the array. When the array dies, all the objects within it are released as well (my guess as to what's happening here).
Couple things to try:
First, make sure you're putting your array where you think you are:
[(UINavigationController*)([self.tabBar.viewControllers lastObject])setViewControllers:arrayWithRootController];
What do you expect [self.tabBar.viewControllers lastObject] to be? Are you sure this is where you want to be assigning your new array? If the receiver is invalid, your array won't be retained in your next line which means the view controller will also be released.
I'm not familiar with your architecture, but it appears you're assigning an array of view controllers to a view controller. self.tabBar is a navigation controller, and you can call setViewControllers on it. But self.tabBar.viewControllers lastObject... well presumably that's a view controller, but not neccessarily a navigation controller, it may not respond to setViewControllers (in which case it should crash, unless it's nil, which I'm guessing it might be).
Finally, try using the Instruments tool Zombies to see if you can pinpoint where the unintended release is coming from.
I am working on an iOS SDK 4 project with ARC enabled.
My class MyTextView (derived from UITextView with UITextViewDelegate protocol) implements the following static method:
+ (void)showInViewController:(UIViewController*)viewController
{
MyTextView *textEdit = [[MyTextView alloc] init];
textEdit.delegate = textEdit;
[viewController.view addSubview:textEdit];
// Show the keyboard
[textEdit becomeFirstResponder];
}
In one of my view controllers I call the following:
[MyTextView showInViewController:self]
This crashes with warning: Unable to restore previously selected frame. on becomeFirstResponder. Looks like some stack related crash because of some cycle. I am fairly new to ARC. The delegate property of UITextView is defined as assign (shouldn't ARC interpret that as weak?). I know this approach is rather strange memory-wise. However, I wanted to know if ARC can handle things like that. Obviously it can't. Any idea what might be the problem and how to solve it?
I don't think it has anything to do with the ARC and memory management, but just a more fundamental problem that a UITextView cannot be a delegate of itself. It gets locked in a loop. Put a logging message in textViewDidChangeSelection and you'll see it gets repeatedly invoked. Not a memory issue, methinks, but rather just a logic issue with UITextView delegates. Even if you don't do your problematic showInViewController but just create a standard UITextView subclass and try to set its delegate to itself, you'll see the same curious behavior.
old post, but here is the answer:
http://www.cocoabuilder.com/archive/cocoa/282093-uitextview-as-its-own-delegate-infinite-loop-on-keyboard-select.html
or here aswell
self.delegate = self; what's wrong in doing that?
I am working on a project on iPhone. I am now initiating a new UIViewController from another UIViewController, and then switch between them. Here is my code.
iGreenAppDelegate *delegate = [UIApplication sharedApplication].delegate;
if(checkInViewController) {
[checkInViewController release];
checkInViewController = nil;
}
checkInViewController = [[CheckInViewController alloc] initWithCheckpoint:checkpoint];
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:0.8];
[UIView setAnimationTransition:UIViewAnimationTransitionFlipFromLeft forView:[delegate window] cache:YES];
[[delegate rootTabBarController].view removeFromSuperview];
[[delegate window] addSubview:checkInViewController.view];
[UIView commitAnimations];
The Problem is the second time I initiate the UIViewController, I want to release it to avoid causing memory leak. The Debugger displays
iGreen(916,0x3f60348c) malloc: error for object 0x130350: incorrect checksum for freed object - object was probably modified after being freed.
set a breakpoint in malloc_error_break to debug
This is strange because similar codes in other parts don't return such error. Moreover, I tried autorelease, but the program will immediately crash and the Debugger says I am modifying finalized layers.
I've been working on the problem for a whole night, and still confused about it.
Set a breakpoint in malloc_error_break to debug.
Do that and post the backtrace.
Usually, this means that you corrupted memory, but it may also mean that you have an over-released object. Try Build and Analyze, too.
Apart from setting a breakpoint in malloc_error_break - press Command-6 in xCode to jump to the breakpoints tab - also enable the malloc aids in your scheme.
Go the the schemes selector, choose "Edit scheme" find the "Run" target and go to the "Diagnostics" tab. Below memory management enable scribble, guard edges, guard malloc and zombie objects.
With a bit of luck xCode will catch you writing outside your allocated memory and corrupting memory.
It's like adult supervision for dealing with memory...
Understand the error message: it's saying that something continued using (and modifying) the object after you freed it. This code frees it and does not modify it thereafter, but you have to ask what else could possibly continue using it (without knowing it was already freed).
Each time the code in this snippet runs, it releases (frees) any existing checkinViewController, and allocates a new one, and clearly it never touches the old one again. But who else may have a pointer to the old object?
Possibly other code you wrote, and possibly [delegate window], which gets a reference via "[[delegate window] addSubview:checkInViewController.view];"? Hopefully the latter takes its own reference, meaning release won't immediately free it.
But watch out for anywhere you're copying that pointer without adding a reference. If you do this somewhere, and then elsewhere (such as the above snippet) someone calls release on the same pointer, you may now have a pointer to an object that's been freed.
There are a couple of things going wrong design wise in your code. First your release the checkInViewController without removing its view from its superview (if any), then you remove the rootTabBarController's view from its superview, without doing anything to the controller itself, and you don't add the checkInViewController to the rootTabBarController or the rootViewController property of the window, so it's in the air (just retained by your current object). What happens when this (current) object gets deallocated but the view of the checkInViewController stays put (retained by) on the window?
If you release your checkInViewController but its view is still retained by the window, it is probably going to create some issues...
About the error, I think there's somewhere a weak reference (not retained) to your object that acts on it after it's freed.