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.
Related
I'm using Instruments to monitor my app's(ARC) memory usage, and found out that
When I pop a view controller from navigation view controller stack, its dealloc method is called.
But the memory usage only drops a little...(like 0.6M), and still much highter than before.
So here is the problem. The memory usage of my app keeps increasing....
How could I decrease the memory cost to the value before the view controller allocation.
Or at lease how could I release more memory.
Also, it seems that the memory cost is much highter when using xib(storyboard).
Should I set the data to nil like someArr = nil in dealloc method?
I have no idea. Anyone help please! Thank you!!
This image is captured when one view controller is allocated, and still alive after its dealloc method is called.......
You can try using #autoreleasepool{ } blocks, though be aware that the memory footprint doesn't necessarily return all the way to where it started. A big caveat is that if dealloc is already called, using autoreleasepool in your code might do nothing because the VC was already released properly.
Though you can consider where to use it within the view controller implementation, perhaps within a dealloc implementation for the VC. To ensure that when the VC's dealloc is called, objects that receive an autorelease within the #autoreleasepool block will be released immediately.
Snippet of mine from OSX code:
- (void) dealloc
{
#autoreleasepool {
// End KVO
[self stopObservingIndexPath];
for (NSView* subView in _treeSubViews)
[subView removeFromSuperview];
[_categoryView removeFromSuperview];
[self.view removeFromSuperview];
_treeSubViews = nil;
_categoryView = nil;
}
}
... that was written in a quest to reduce footprint like yours, by forcibly dismantling the view hierarchy.
And the Apple reference here.
SOLVED BELOW
I'm reading this article from raywenderlich blog:
http://www.raywenderlich.com/23037/how-to-use-instruments-in-xcode
to learn about instruments and figure out if I´m doing something wrong in some old projects.
I've seen that in one particular point of my code, when I'm showing a modal view that eventually is closed, the memory allocated remains there. As you can see in the following image.
The execution have 4 marks generated.
Between the 2n and the 3t mark, the view is showed, as you can see, new memory is allocated.
But between the 3t and the 4th, I've called dismissViewController, and the view no longer remains. But the memory remains allocated.
All the properties, are created as strong (probably no the best approach):
And I´ve an NSTimer, that is initialized in viewDidLoad method, and set to nil at viewWillDisappear:
[self.secondTimer invalidate];
self.secondTimer = nil;
So, do you have any idea about what's happening? From what I know, even the properties are declared as strong, when the UIViewController is released, all of them are going to be released to.
EDIT
Thanks to all, with the information I provided, wasn't enough.
As you can see, QRViewController inherits from BaseViewController.
This controller had a delegate defined as strong storage, terrible.
So that's all.
In the view controller hierarchy, self.view holds ALL his subviews with strong, so everything under self.view (Probably all your IBOutlet properties) can switch to weak. That probably won't solve the problem though.
What might help you is the fact that any block you have holds every single object used in that block as a strong, to make sure the block can run it's code at the time being. If nothing holds that block (like a animationWithDuration:) than no worries. But if you have any block that an object is holding (Like and object's "completion-block" or any other creative use of blocks), everything within that block will be strong, and there's a chance you create a retain cycle that way. For example: the presenting view controller is calling the presented view controller with a completion block, and in that block you use self. Now presented VC is holding a block to perform on dismiss, and the block holds the presenting VC. When dismissed you will end up with a VC that holds a block that holds a VC that holds the presented VC....
A simple solution would be to give the block a weak version of self and only when the block executes, make it strong for the time of running the block (To avoid dealloc while running the block):
__weak myViewController *weakself = self;
[self.someObject setBlockHandler:^(BOOL foo){
myViewController *strongself = weakself;
if (strongself) {
// Do whatever...
}
}];
It's difficult to pinpoint precisely the problem, but usually when things like this happen to me, it winds up being one (or a few) "root" culprits -- you find that one, clear it up, and then lots of others clear up too. So one strategy you can try is to sift through the Instruments data looking for any sort of "hierarchy" (think about how your app is structured and how the objects relate to each other) and look for objects closer to the base, then cross-reference against your code to see if they might have a retain cycle or some other such issue.
One immediate change I would make would be to change your IBOutlet declarations from strong to weak. For the most part, IBOutlet properties should be weak, for objects that are within a hierarchy. So if say you've got some UILabel within your xib's main view, that label should be weakly-retained so as to avoid a retain cycle. But if say that UILabel is standing alone as a root item within the xib, then it would need a strong reference. I'm going to guess most (if not all) of your IBOutlets there are within a hierarchy, so make them weak and try again. It may not solve all the leaks, but see if it makes any difference.
This is called Abandoned Memory, check this link.
TIP:
If you are navigating between view controllers, and you perform the navigation inside a closure, you should use a weak or unowned version of self, example:
//Swift 2.1
//Performing naivgation on the main thread for responsiveness:
dispatch_async(dispatch_get_main_queue(), {[weak self] () -> Void in
if let weakSelf = self{
weakSelf.performSegueWithIdentifier("myOtherView", sender: weakSelf)
}
})
Also, when dismissing the view controller is the same:
dispatch_async(dispatch_get_main_queue(), {[weak self] () -> Void in
if let weakSelf = self{
weakSelf.dismissViewControllerAnimated(true, completion: nil)
}
})
The posted link above shows a practical example on how to catch abanodend memory using Xcode Instruments.
Recently I wrote some code where I tried to refer to an outlet on a UIViewController I'd just instantiated with [storyboard instantiateViewControllerWithIdentifier] and modify the subview that the outlet pointed to before presenting the ViewController. It didn't work because the ViewController's view hadn't loaded its subviews yet, including the one that my outlet referred to, so the property just gave me a null pointer.
After (with some struggle) tracking down the cause of my issue in the debugger, I Googled around and learned, through answers like this one, that I can cause the view to load its subviews without being displayed by calling the myViewController.view getter. After that, I can access my outlet without any problems.
It's a clear hack, though, and Xcode - quite rightly - doesn't like it, and angrily protests with this warning:
Property access result unused - getters should not be used for side effects
Is there a non-hacky alternative way to do this that doesn't involved abusing the .view getter? Alternatively, are there canonical/idiomatic patterns for this scenario involving something like dynamically adding a handler to be called as soon as the subviews are loaded?
Or is the standard solution just to replace myViewController.view with [myViewController view] to shut up Xcode's warning, and then live with the hack?
On iOS 9 or newer, one can use:
viewController.loadViewIfNeeded()
Docs: https://developer.apple.com/reference/uikit/uiviewcontroller/1621446-loadviewifneeded
I agree that forcing a view to load should be avoided but I ran into a case where it seemed the only reasonable solution to a problem (popping a UINavigationController containing a UISearchController that had yet to be invoked causes a nasty console says warning).
What I did was use new iOS9 API loadViewIfNeeded and for pre-iOS9 used viewController.view.alpha = 1.0. Of course a good comment above this code will prevent you (or someone else) removing this code later thinking it is unneeded.
The fact that Apple is now providing this API signals it can be needed from time to time.
Not sure how much cleaner this way, but it still works fine:
_ = vc.view
UPD: for your convenience, you can declare extension like below:
extension UIViewController {
func preloadView() {
let _ = view
}
}
You can read explaination by following URL: https://www.natashatherobot.com/ios-testing-view-controllers-swift/
merged Rudolph/Swany answers for pre ios9 deployment targets
if #available(iOS 9.0, *) {
loadViewIfNeeded()
}
else {
// _ = self.view works but some Swift compiler genius could optimize what seems like a noop out
// hence this perversion from this recipe http://stackoverflow.com/questions/17279604/clean-way-to-force-view-to-load-subviews-early
view.alpha = 1
}
If I understand you correctly, I think there's another fairly standard solution: move the outlet modification/configuration code into a viewDidLoad method (of the recently instantiated VC).
The topic is also discussed in this question.
It would require some restructuring, but it might give you a "cleaner" design in terms of MVC if your incoming VC handled its own configuration, and it would avoid the "You should never call this method directly" stricture on loadView.
You can call [myViewController loadView] to explicitly load the view, instead of abusing the .view getter. The .view getter actually calls loadView if necessary when called.
It's still not a very nice solution, since the UIView Documentation's section on loadView explicitly instructs that
You should never call this method directly
I'm trying to come up with a good way to organize transitioning between UIViewControllers that removes the logic from the controllers themselves. I came up with a pattern based on the Pro ObjC Design Patterns book that I liked, but I'd like to know how to improve it.
The pattern in a nutshell. Forgive the semi-pseudo code.
I subclassed the UINavigation Controller and created a method that all the View Controllers call when they need to transition.
-(void)requestViewChangeByObject:(id)object withData:(object*)someData{
if ([object isKindOfClass:[ViewController1 class]]) {
[self showViewController2Animated:YES withSomeData:nil];
}
if ([object isKindOfClass:[ViewController2 class]]) {
[self showViewController3Animated:YES withSomeData:someData];
}
if...
}
Then I just defined methods for each controller. Some just instantiate and push the controller and some set properties or pass information in.
-(void)showViewController2Animated:(BOOL)animated withSomeData:(object*)someDataVariable{
viewController2 *VC2 = [viewController2 defaultViewController];
[self pushViewController:VC2 animated:animated];
}
-(void)showViewController3Animated:(BOOL)animated withSomeData:(object*)someDataVariable{
viewController3 *VC3 = [ViewController3 defaultViewController];
VC3.someData = someDataVariable
[self pushViewController:VC3 animated:animated];
}
The reason I'm doing it this way is because it makes the application much more flexible in terms of changing around controller order and adding/removing controllers as the design and requirements change. We also tend to re-use apps and this makes it easier to reskin and reorganize to build a new application.
The main problem I have is the more complicated the application gets the bigger that method with all the if statements is going to get. It might get confusing if there's more logic involved than just push viewController2 if the request comes from viewController3. I'd really like to know how I can improve this so that it's more flexible and less likely to cause confusion and errors.
Second, it's not very flexible when you add passing data around to the problem. I ended up taking the parameter out that accepted a data object and just created an separate singleton manager object that handles saving/getting the data that I needed, which I understand is not good design. However, when I tried passing the data back and forth between controllers like Apple suggests(ie setting properties on the controller as in the above code) it just became a confused mess and I feel like there's a better way to do this.
So any suggestions on this would be appreciated thanks.
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.