I'm developing an app in swift language to reproduce some live streaming or video on demand and I have 3 view controllers, the first is for live streaming, the second is a collection view with video on demand tuhmbnail and selecting one of this, it opens the third view controller for play the video, but when I come back from the third view controller, If I select a new video, the debugger says "received memory warning" and the app crashes, but before, I dismiss previous view controller and set to nil value the AVPlayer object and the AVPlayerLayer and I don't understand why this happen.
May depend on the buffer AVPlayerItem? is possible to set it? or when I dismiss I view controller I don't destroy his instance?
I'd need more information to be sure, but you likely have a retain cycle where you have a strong reference to self inside of a block.
Apple explicitly states that you'll need to use weak self to avoid a retain cycle with addPeriodicTimeObserver.
Hopefully that helps. If not, could you edit and add code?
Related
Some of my view controllers don't get deallocated after being popped from view. I've gotten rid of the other strong references so I'm left with this internal retain cycle held through a reference form _externalObjectsTableForViewLoading. It's a private UIViewController property so I'm unable to clear it myself. I don't know if iOS has an API to clear it or why it's not being cleared after popping the view controller.
I've tested with with my app running in Release mode both in iOS 11 and 12. Running the app in Instruments renders the same stairs pattern seen in Xcode with the view controllers being retained.
Any ideas? Thanks in advance!
In your problem, is one viewController accessing another viewController? Our problem is that there was a non weak reference to a callback in another viewController.
As mentioned in your and in other posts on this, _externalObjectsTableForViewLoading is a viewController private property, but a storyboard related property. This leads me to think that your code has strong references to another object that is a view controller through a callback or through a direct property reference to its instance.
I have two view and second view is pushed from first view. For testing, I go to second view from first view and then I go back to first view. After that, I send nsnotification and in my second view, it receive my notification.
1) May I know why I receive notification in second view after it is pop up? For IBOutlets, I declare weak property also.
2) If it is still in memory, for other data like nsdictionary, nsstring, shall I use strong or weak property? Will those also in memory?
3) If I don't want my second view in memory totally, how shall I do?
If your second view controller is not released when you "go back" to the first view, then either
You are not really "going back" - you are accidentally creating a new first view controller and pushing it, which is unlikely; or:
You have a retain cycle in your second view controller.
I'm betting that you do have a retain cycle. You should try to track this down. You mention notifications: it is very easy to create an accidental extra retain when setting up a view controller as a notification observer, so that's probably the cause.
In particular, see my book's discussion of this topic:
If you called addObserverForName:object:​queue:usingBlock:, you will leak (under ARC) unless take elaborate precautions (such as doing the weak-strong dance in the block, to avoid a strongly retained self).
I'm pushing and popping ViewControllers in UINavigationController.
I'm tracking the memory consumption of my app.
While pushing the new viewController the memory consumption is increasing gradually, but when I'm popping the same ViewController using [self.navigationController popViewControllerAnimated:NO]; the memory consumption does not decrease but the constant.
That particular viewController can be pushed and popped by user many times which can lead the high memory consumption of app in RAM.
What should I do to optimise my memory consumption?
When you dismiss a view controller (or pop it), it will be deallocated if you didn't make any strong pointers to it (that controller is retained by the navigation controller, or the presenting view controller, so you usually don't need to have a pointer to it when you create it and push or present it).
It will be be released if there are no other strong pointers to it
Try to avoid using strong properties for IBOutlets.
Consider reviewing whether you are referencing self in a block. If you do, you risk holding onto the UIViewController reference after you have popped it.
For a more in-depth review of why, check out this answer:
How do I avoid capturing self in blocks when implementing an API?
If your app design allows the user to push and pop the same view controller over and over again, you may want to look at reusing the same view controller and just updating its contents each time it's pushed.
Instead of creating and destroying it over and over, create one, set up its contents and push, when it's popped, keep it around ready to be shown again. Next time it needs to be shown, update its contents and then push it again.
I would like to say, that my last few days were spent on searching the web for my app memory problem. I was switching between 2 UIViewControllers. One of them had a scroll view which kept all subviews on it. It turned out that that UIVC loads a new scroll view without releasing the previous one. It took me several hours to realize it.
What I did was:
Looking for any kind of deadlocks inside the app, then searching for every variable that had a strong atributte and other desperate measures. But what really worked was:
#IBAction func backBB(sender: UIBarButtonItem) {
collectionView.removeFromSuperview()
self.frontView.removeFromSuperview()
eventsPhotos.removeAll(keepCapacity: false)
symbolContainerView.removeFromSuperview()
self.myScrollView.removeFromSuperview()
dismissViewControllerAnimated(true, completion: {})
}
I manually removed some views and contents. I've done it in "Back" button but you can do this in other methods like viewWillDisappear(animated: Bool).
Once I made this, my allocation chart in the developer instruments showed the memory allocation going up and down... And it was solved...
I think you get an error, when you try to pop the view controller because the navigation controller does not have a valid reference to the view controller, as it was released after you pushed it.
Nil the popover on dismiss.
[menuPopup_ dismissPopoverAnimated:YES];
menuPopup_ = nil;
Make sure your viewcontroller (A) has no reference of any other viewcontroller (B) or any object it has. Incase it has then make sure that VC-B is not referencing back VC-A. If it has some reference back to VC-A then make it a weak property. Otherwise strong retain cycle will keep the VC in memory even if its popped.
Another thing is to check wether theres any closure in your VC, check its body if it is referencing any property or method with self then make a Capture list to avoid retain cycle as "Closures are Reference Types"
Check if theres any NSNotification observer you are not releasing
Make a print call in deinit method to check wether its deallocated.
For further understanding on memory management:
https://medium.com/mackmobile/avoiding-retain-cycles-in-swift-7b08d50fe3ef
https://www.youtube.com/watch?v=GIy-qnGLpHU
You should use an unwind segue instead of popping.
I'm creating an app that plays music and has a nice UI for the album art and progress bar. The problem is when the user leaves the player view and goes back, the player UI has to be reloaded and you see a flash while the progress bar is resized and the album art is loaded.
Is there any way to keep items in memory when you leave a controller? Similar to how you go between playlists and player view on the iPhone music app, there is no lag or delay in seeing the artwork or song progress, it's there from the beginning.
Or am I thinking about this the wrong way?
I am assuming you are going back and forth using a UINavigationController, if so the default behavior is that the view controller will be released when you go back, as the only strong reference to it is in the UINavigationController stack, when it is popped the reference is lost, and therefore your controller is deallocated.
If you want to avoid this, all you need to do is have any other object have a strong reference to your view controller. An easy way to do it would be whenever you initialize your controller, in that class have a strong property that holds a reference to the view controller you do not want to lose.
Hope that helps.
I have 2 tabs, one that contains the imagepicker controller, and another that contains a UItableView as a subview to a uiview controller.
I realise that when I call the imagepicker controller (SourceTypeCamera), my page in the other tab is being unloaded ('view didUnload' method) is triggered.
Is this a normal behaviour I should expect? (that other tab's views get unloaded) Or is it due to some memory issue when using the camera which I should take care off?
As you say, viewDidUnload can be triggered at any time, and is normally associated with a low memory warning, a view controller's view otherwise being cached even when not needed for as long as memory will allow. So in a strict sense it's neither expected nor unexpected, as it depends on the sum total state of the rest of the system.
That being said, UIImagePickerController is famously quite memory hungry when capturing an image (see e.g. this image, where each spike is related to an instance of UIImagePickerController "capturing an image" per the related blog), so other views being forced from memory shouldn't be so surprising.
There's no documented mechanism and no reason for a UIImagePicker to force other controllers to dump their views speculatively.