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.
Related
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];
I'm trying to make a "Delete" button on an "Edit Item" page, which when pressed will go back and remove the relevant entry in an NSMutableDictionary on the previous page, and then update the tableview list of entries.
It starts with an IBAction method on the "Edit Item" page, which basically does nothing but feed the key to be deleted back to the controller for the previous page:
- (IBAction)deleteItem:(id)sender {
[_parentController removeItemWithDeleteButton:[_mainFactoidTextField text]];
}
which is where the action actually starts (on the list page):
- (void)removeItemWithDeleteButton:(NSString *)key {
[_currentItemsDict removeObjectForKey:key];
[self.navigationController popViewControllerAnimated:YES];
}
At the start of that method, _currentItemsDict has 8 objects, which drops to 7 after removeObjectForKey: is called. Then it pops off the top ViewController, which is the "Edit Item" page, returning us to the list of entries.
Then when that method is done, the breakpoint immediately jumps to:
- (void)viewWillAppear:(BOOL)animated {
NSArray *tempArray = [NSArray arrayWithArray:[_currentItemsDict allKeys]];
NSArray *sortedArray = [tempArray sortedArrayUsingSelector:#selector(caseInsensitiveCompare:)];
_currentItemsArray = [NSMutableArray arrayWithArray:sortedArray];
[_tableView reloadData];
}
But by the first line of viewWillAppear:, _currentItemsDict has reverted back to 8 objects. Everything works fine from then on, but it's all working with the original 8 entries, meaning that nothing got deleted.
From my limited experience with these sorts of things (I'm definitely still a beginner), I'm going to guess this has something to do with the popViewControllerAnimated: method, but I cannot figure out what. I've heard distantly of certain variables being stored in different ways that might make them come back as an earlier version of themselves, but I haven't wrapped my mind around the concept. Or maybe it's something else entirely, I don't know. All I can tell is that _currentItemDict has 7 objects, and then one line later it has 8 again.
Can anyone help out a new guy, and explain where I'm going wrong? Or if it's easier, can you suggest a better solution for removing an entry in an NSMutableDictionary from a different ViewController? (Code samples and tutorial links are much appreciated, as I'm currently just noobish enough to sometimes be unable to translate theory into practice on my own!)
Thank you in advance for your help!
Do you know how properties work in Objective-C 2.0? I would declare a property in your parentViewController to contain your _currentItemsArray, declared as a strong reference.
#property (nonatomic,strong) NSMutableArray *_currentItemsArray;
Also, set a weak property in your childViewController (the one you push to for deletion)
#property (nonatomic, weak) NSMutableArray *parentItemsArray;
Set the property on the childViewController upon push
childViewController.parentItemsArray = self._currentItemsArray;
[self.navigationController pushViewController:childViewController animated:YES];
Remove the item inside the array within childViewController instead of calling a method on your parentController
[self.parentItemsArray removeObjectAtIndex:indexOfKey];
Doing this, you don't have to sort the array again in viewWillAppear. Instead, just ask the tableView to reloadData
Does any of this make sense?
It also may be wise to include your logic inside cellForRowAtIndexPath, numberOfRowsInSection and the other tableViewDataSource methods.
I have following code in my project:
RBPPStockChartViewController * stocksController = [[RBPPStockChartViewController alloc] initWithNibName:#"RBPPStockChartViewController" bundle:nil];
stocksController.companyCode1 = selectedCompany.companycode;
stocksController.ticker1Text = selectedCompany.ticker;
stocksController.isMarketIndicator = FALSE;
if (isfromTVIndexes)
{
stocksController.isDJIndexesMenuDisplay = TRUE;
stocksController.isDJIndexesDirectChartDisplay = FALSE;
}
stocksController.closechartdelegate = self;
self.stockchartvc = stocksController;
[[self view] addSubview:stocksController.view];// here retain count is incremented.
// And I am getting leak when I check
//with instrument.
I am using ARC.
I want to know how to overcome this leak.
A couple of thoughts:
This technique of adding a controller to some strong variable and then adding its view as a subview is not a recommended way of present another view. You really should be using
[self presentViewController:stocksController animated:YES completion:NULL]
or
[self.navigationController pushViewController:stocksController animated:YES]
(or, if you're determined to do it the way you have, you should do the view controller containment calls, such a addChildController and didMoveToParentViewController). If you let your view controller hierarchy get out of sync with your view hierarchy, you can end up not getting certain events (notably rotation events; for a lengthy discussion on the problems/risks of not doing this carefully, see WWDC 2011 session - Implementing UIViewController Containment). Also, if you did it properly, you wouldn't have to keep your strong reference in self.stockchartvc nor have a closechartdelegate at all (nor the code that likely calls).
And, by the way, if you adopt one of these well-established patterns (modal/push transitions or view controller containment), that might fix the memory issue there.
Alternatively, if you don't fix this structural problem, then you might need to take a closer look at the code that closechartdelegate calls. I.e. Does it removeFromParentView? Does it nil the stockchartvc variable? If you don't do both of those things, you'll effectively leak.
You don't use any repeating timers or anything else that might result in a strong reference cycle, are you? For example, I hope closechartdelegate is weak.
If you still can't fix the problem, we probably need to see the memory semantics of stockchartvc, closechartdelegate, and see the code that the closechartdelegate is calling.
So I've seen previous questions similar to this but they were of no help. I've read Apple's documentation too but I could not understand where I've gone wrong. AFAIK I did everything logically, but when I click on my done button on an UItoolbar overlay, the button can be pushed but it does not do anything. This obviously means it fails to acknowledge the written code. But how?
I want to bring up the .nib of "TableViewController" when a done button is clicked on my UIToolBar. But the below isn't allowing the click to bring up a new view. How do I rectify this? Please show me where I went wrong and what should be replaced and why.
-(void)doneButtonPressed {
TableViewController *UIView = [[TableViewController alloc]
initWithNibName:#"TableViewController" bundle:nil];
UIView.modalTransitionStyle = UIModalTransitionStyleCrossDissolve;
[self presentModalViewController:UIView animated:YES];
[UIView release];
}
Whoa, you've got some bizarre stuff going on here. In your first line, you're allocating and initiating the TableViewController instance correctly, but you're not giving that instance a unique name. You're naming it with another class's name, which is bound to stir up problems. In fact, I'm surprised it didn't through an error.
Try the following instead:
TableViewController *tableView = [[TableViewController alloc]
initWithNibName:#"TableViewController" bundle:nil];
tableView.modalTransitionStyle = UIModalTransitionStyleCrossDissolve;
[self presentModalViewController:tableView animated:YES];
Now, your TableViewController instance has a unique name that is referenced throughout the rest of the method. Just to be clear--UIView is another class name, and therefore cannot be used as the name of an instance of an object.
EDIT: Additionally, be sure to add your button's selector doneButtonPressed: to your .h file of its view controller. Also, if you like you can toss an NSLog() call in the beginning of the function just to be sure it isn't (or perhaps is) being called.
Something to check when button actions aren't firing is that you've got the appropriate selector. If you've followed the selector correctly. Make sure you aren't using a selector of
#selector(doneButtonPressed:)
which would look for a function like:-
- (void) doneButtonPressed:(id) sender
For your member function, you need
#selector (doneButtonPressed)
The debugger is your friend here. Start with a breakpoint to make sure your function is being called.
If you're getting into the function, then The Kraken's answer is the next thing to check.
There is no restriction on using a class name as a variable name whatsoever. Although you should change it because its confusing and doesnt follow iOS coding conventions.
"Button can be pushed but doesnt do anything", is the selector even being called?
-(void)doneButtonPressed
Show how you created the UIBarButtonItem to verify that you provided the right selector in the init method or that you connected the button directly in interface builder (which it doesnt look like since you didnt use the (IBAction) return signature.
Im struggling to solve in a very clean way a problematic involving memory overload (management).
Im having a serie of view that include other views, in my project I have a situation like this:
MainView
|_PageView
|_CustomButton
soo far soo good, easy as a cake. CustomButton have a delegate (protocol) in it for some reasons, so we have in PageView a "for cycle" that creates N CustomButtons, set the delegate as self in PageView (PageVew extend CustomButtonDelegate) and release the buttons afer attaching them like
{
CustomButton *customButton_ = [[CustomButton alloc] initWithFrame:CGRectMake(100.0,50+(i*55.0),200.0);
customButton.delegate = self;
[self addSubView:customButton_];
[customButton_ release];
}
soo far soo good again. Button will be press, PageView get the protocol method, do some code and voilà, done. One problem is that at one point, MainView must remove PageView, so In a method I call
[pageView_ removeFromSuperview];
[pageView release], pageView_ = nil;
pageView_ = [PageView alloc] initWithFrame.....];
and I recreate the object with other data to display.
I noticed that PageView never gets release and removed from the memory because its retainCount is exactly how many CustomButton I created inside PageView and assign the delegate to self plus one of course. My question is, what is the cleanest way to remove safely all the objects and be able to remove PageView too, free the memory (because Im loading a quite large amount of data to display in it) ?
Right now i'm doing:
Create in PageView a NSMutableArray, that I CustomButton the objects in
it, and before to remove PageView, I cycle it and set the delegate = nil and then release
each object, after I release the NSMutableArray (called "holder").
But the problem is that if I want to add more objects of different types with other protocols, adding to this array, can lead to other problems of retaining the objects.
Where do I lack guys, knowledge so I need to study more (quite sure I can say) or do I need to approach with another OOD?
Thank you guys, im going overload with this problem and my brain is stuck in a close road. :)
Looks like your CustomButton's delegate is a retain property of CustomButton. Delegate should be an assign property, not retain nor copy. See here.