I'm concerned about tiny lags and memory issues, and how they might scale.
My app is programmed using Swift and I've been doing everything in the app programmatically, including page navigation using presentViewController and dismissViewControllerAnimated.
Note: the app's page hierarchy can be several pages deep and each page contains quite a number of images.
I started experiencing tiny, occasional, lags which could appear more often on older phones; I can only test on iPhone 6 right now. I also noticed a small increase in memory while navigating through pages. Of course the memory level on the app (as observed in XCode) is not the same as opening the app in fresh state compared to going back to the first page after navigating through tens of pages, I'm expecting the memory level comparison could come at least close.
Now, my question: is there a proper way to "destruct" my page views (including UIKit elements, images, etc.) when such page view is dismissed?
I assume that by "page" you mean a viewController: There is no way to directly destroy objects with ARC (automatic reference counting), as they are deallocated automatically when their strong reference counter is zero. Since you experience unusual memory increase, it might be that you have some strong reference cycles in your code. Make sure to declare properties as weak wherever necessary. You should check out the ARC Guide for detailed explanation. I hope this helps.
Related
I am building an iOS app with one of those "hamburger menu" type drawers that open up to a list of options of the left. Like this:
Each time you click on an item, for example "settings" it loads a new viewcontroller and displays it on the main view controller. Now, the question I'm wondering is whether or not I should be releasing the viewcontrollers each time a new item in the menu is clicked.
For example:
You are viewing Inbox
You click Settings
I release InboxViewController and alloc init the SettingsViewController
I make the SettingsViewController the main viewcontroller
I'd like to keep all the viewcontrollers in memory, because I think it would provide for a more smooth transition from one to the next if it was previously allocated, instead of having to wait each time to allocate it.
I am using ARC
Is this bad practice? I might have 6-7 viewcontrollers in memory.
Looking at the SDK, Apple makes both choices: UINavigationController keeps the whole stack of VCs below the top, while UIPageViewController aggressively releases any page except the current one.
This is an example of a "speed/space" trade. Precomputing and caching objects will be faster (once running) but occupy more memory. Releasing more aggressively and building (or rebuilding) will incur some run time cost but occupy less memory.
The question might also be an example optimizing too soon, or unnecessarily. For a handful of typical VCs the allocations are quick and the memory footprints are (ought to be) small. Changing approach will likely have insignificant impact on either speed or space.
I'd start with whichever way is simpler (probably allowing VCs to be released passively is simpler) and see if there's a demonstrable problem that needs solving.
If you consider what you're doing, it's really no different than a UITabBarController. The views don't load until they are viewed the first time, but then are kept "alive" indefinitely. I would think as long as you keep the number of loaded view controllers reasonable (single digits) you'll probably be fine, with the one caveat that if they are all doing some intensive processing/loading/etc., it could become problematic.
I don't necessarily think keeping all the ViewControllers in memory is a good thing, unless the View contains objects that take a long time to fetch (i.e. opening a UIDocument or from a NSURLRequest).
Hope that helps!
I am quite beginner in development and I'm making an application that have about 150 ViewControllers ! Each one have a UIImageView.
I've been doing a bit of testing, and after a use the app for a while on the iPhone itself, it Crashes when I keep viewing the ViewControllers.
I've been analyzing this in instruments, and I have no leaks, however my memory allocation just goes up and up and when I keep viewing the ViewControllers on my iPhone the usage just goes up and up until a crash.
I think it's clear that it's crashing because the app is simply taking up too much memory.
So could any one explain how to release viewControllers in order to free up the memory so there will be no crash
Thanks in advance !
The first question you need to ask yourself is why do you need 150 ViewControllers.
Do you want to present 150 different images?
If so, then multiple ViewControllers is not the way to go. You probably need to use a UIScrollView that will contain your images (not all of them at once, of course. Use lazy loading).
What's probably happening in your case is that you call "pushViewController" each time you need to display a new ViewController, but this doesn't release the previous ViewController. It simply stacks all of the previous ViewControllers and retains their pointers.
You see, the way Navigation Controllers work is that they have an array of view controllers. Every time you present a new view controller, it is added at the end of the array. When you click on "Back" or call "popViewController" the last item of the array is removed (and then released automatically from memory).
See this and this questions to learn how to create a UIScrollView to scroll images.
In developing my current app, I ran into some issues that I eventually traced back to a low memory warning. Part of the low memory is coming from my (liberal) use of UIWebViews, which are apparently consuming a lot of memory.
I didn't think this would be an issue, since a view that isn't currently visible should just vanish when the low memory warning is thrown, unfortunately it turns out that anything connected to the UITabBarController remains in the heirarchy and doesn't release. By manually releasing (and then recreating in viewWillAppear) the views, I make things work decently. But it doesn't completely solve the memory warning issue.
So what I need to do is manually release the view -- and the large amount of memory that winds up connected to it -- and then restore it. Since I don't want to build it programmatically (that's what IB is for!), I need to somehow reload it from storyboard.
Or, alternatively, I'm being an idiot and there's something really obvious to make my life easy.
After more experimentation, it turns out that on the one hand, my understanding of view life cycles was slightly flawed, and on the other my experiments were tainted by having accidentally let zombie objects on.
Views will, in fact, unload their contents in a low memory condition and reload them later -- that's part of what 'viewDidLoad' and 'viewDidUnload' are designed for! Putting init code in them, as some tutorials I read did, was a major error. That init code should go in the designated initializer -- even if that can be annoying to figure out which initializer is designated.
I just started learning the instruments tool, and I'm pretty sure what I am seeing is not good. When I look at allocations, specifically the column "Live Bytes" and "Overall Bytes", I see the number continually increases as the app runs...
My app has two view controllers. A table view, and the second view controller displays detailed information about the row they selected in the table view, downloaded from the internet.
I kept clicking a row in the table view, followed by clicking the back button in the navigation bar... and LiveBytes continued to increase.
I'm guessing this means that my objects aren't being released from memory... but please correct me if I'm wrong.
MY QUESTION IS: How do I use the data in instruments/allocations to track down this memory issue? How do I find the objects not being released from memory?
I'm looking for tips on how to use these tools to clean up any memory problems my app has.
Thanks!
XCODE 4.2.1, deploying to iOS 5.0+
EDIT: I'm looking at the #living column and seeing objects like UIScrollView continuously increase... and never decrease. When I click the back button in a navigation bar, are objects automatically released from memory? When are objects released, or do I need to do it manually? Or could I be running into an issue due to using strong pointers, causing objects to not be released?
Whenever you want to observe memory usage in a cyclic pattern, there's the wonderful Heapshot analysis in the "Allocations" instrument.
Start your app and go to a default state.
In Instruments, press the "Mark Heap" button to create the "Baseline".
Do something in your app like pushing a view controller.
Return to the default state.
Press the "Mark Heap" button again to create a heapshot.
Repeat about five times from step 3.
This will result in a list of heapshots, each showing the objects that are still alive from that cycle. If your app has no leaks there will be no objects left in the middle heapshots.
The first one or two cycles might have warmed up some caches, the last two might not have cleaned up some reused resources. That's why it's usually a good idea to make four to six heapshots.
The magic in the heapshot analysis lies in the fact that the heapshots show you the leaked objects from previous cycles and remove them automatically when the objects are released later. In contrary to the "Leaks" instrument it also finds abandoned memory, not only leaks.
Most Probably you have discarded the arm64 and are running your app with armv7 only. Add both arm64 and armv7 as architectures
I think one of the best ways to solve memory issues is to use ARC.
Edit -> Refactor -> Upgrade to Objective-C ARC.
ARC will handle the majority of memory management in your app. Especially sice your app doesn't sound too complex, it might totally eliminate your problem. You still need to watch out for retain cycles and listen to memory warnings though. If you don't want to use ARC (which you should) at least run the static analyzer. Your problem might be something simple that the static analyzer can show you how to fix.
Edit:
You mentioned scroll views- this might be your problem: Memory leak every time UIScrollView is released
The profile tool has an instrument called 'Leaks'. It is similar to the 'Allocations' instrument but it shows you the object that was not released. May be you can use the 'Leaks' tool to find what is the object that was retained and release these object.
I have this problem with performance of my iPad app..
For developing, I use MonoDevelop, which takes care of Garbage collecting. Still my questions are rather generic, I'd say.
OK, I use TabBarController with 5 NavigationControllers. Inside nav controllers there are some controllers, whose views are TableViews or ScrollViews. Next child is always just regular view.
I have a few questions:
1) TableViews never scroll smoothly. I have some alpha transparency, but since I did my graphics in Photoshop and not programmatically, this transparency should not cause much problems. It doesn't matter whether I have few or many results in table.
On the other hand, I have ScrollView which serves same purpose, i.e. to be a table with different layout and buttons have Photoshop generated transparency as well. It works perfectly.
For tables I applied DequeueReusableCell() which works fine (I see that memory usage is not increasing after scrolling). So why would tables scroll so jerky?
2) My app supports rotation. When I scroll table or scrollView and simultaneously tilt the device a bit, I get maybe 1 or 2 FPS. What is the best way to implement rotation? As I understand, ShouldAutorotateToInterfaceOrientation has to be overridden in all controllers in NavigationController chain. Also, I need to add observer in View I want some changes to happen. Do I have to use BeginGeneratingDeviceOrientationNotifications() in all views or is it enough to do it in Main.cs? Maybe this slows it down?
3) After some time app starts getting memory warnings and then crashes eventually. I tried to read logs and run app with Instruments, but can't find the cause of crash.
4) What exactly happens to a View popped from NavigationController stack? I can't reuse it. But could it be that Monotouch (or me) doesn't dispose it correctly?
I have almost same app for iPhone without support for rotation which never crashes. I think I'm doing something wrong with this rotation, but I'm not sure what.
Any help will be appreciated the most. So, thank you in advance.
Regards
1 - transparencies are always a problem. Even if you're not rendering the images in code, the phone still needs to do the compositing of the image, and that may take a lot of time. UITableViews have to calculate the final composite image every time a new cell is displayed, or the table is scrolled, while UIScrollViews can calculate only once, since the image won't change. So be very careful about it, turn the transparency off, and check if performance improves.
2 - You shouldn't need to notify every uiview in your application. Receive the notification in the controllers that you want to update only, like for example if you want to rearrange items in the UIViewControllers view.
3 - you have one (or many) memory leaks. My guess is that MonoTouch probably can't garbage collect UIViews or UIViewControllers, because they're still being linked from somewhere in UIKit, like a UINavigationController
4 - UIViews are not disposed by UIKit until the app gets a memory warning notification.
Like Eduardo said, alpha transparency in Views comes at a price. There are some tools that you can use to identify the bottlenecks discussed in these WWDC 2011 talks from:
https://developer.apple.com/videos/wwdc/2011/
iOS Performance and Power Optimization with Instruments
Understanding UIKit Rendering
In the "Debug" menu of the iOS simulator you can find various debugging tools that will color different regions of the screen indicating where some problematic rendering is taking place. The WWDC 2011 talks show what you can do to fix those problems.
For your memory problems, it is very likely that you have something pointing out to your objects around, so you need to make sure those objects are gone. While we currently are not shipping our new profiler for MonoTouch that can show the source of the problem, I wrote a "poor man's" debug utility that will help you narrow down which objects are alive. It is available here:
http://tirania.org/tmp/HttpDebug.cs
Call HttpDebug.Start () from your application and as you run, connect with a web browser to http://localhost:5000 to get a list of live Objective-C objects surfaced to C#. The tool is not perfect and shows a lot of irrelevant data, but it would at least give you an idea of what is going on.