I use UITabBarController as the root controller, each TabBarItem has its own UINavigationController, the first UITabBar (0) refers to the UIViewController which displays the results from the server. The fifth UITabBar (4) includes the MoreFormViewController (it is the successor of the FormViewController from the Eureka framework) it has several cells (two are currently implemented). Clicking on one of them opens SettingsFormViewController (this is the successor from FormViewController from the Eureka framework), the first cell contains UISlider, which changes the settings for getting data from the server (which are displayed in UITabBar (0)). If this parameter changes, then when we return back to the MoreFormViewController, we automatically make the transition to UITabBar (0). If you quickly switch from UITabBar (0) again to the MoreFormViewController and open the SettingsFormViewController, the application is frozen. Found out the following that at this point SettingsFormViewController is initialized and all life cycle methods are triggered (viewDidLoad, viewWillAppear, viewDidAppear and so on). But the screen is not visible, then I looked at UI View hierarchical in Xcode, and it shows that the very first controller is SettingsFormViewController as it should be. All this time I checked on a real iPhone 7, then I decided to check on the simulator and iPhone 5, they did not find such a bug on it, everything works correctly. During the next test, when the application "froze" on the iPhone 7, I accidentally folded it and unfolded it and I saw this screen and it completely works. But if you repeat the same action, then again the application "freezes."
I was looking for information on this, but at the most I found that people simply "frozen" the application because they were pushing the controller out of the main thread. So I do not know what to do. Can you tell me how to solve this problem?
Also I tried to replace the SettingsFormViewController with a regular UIViewController with a slider, the result is the same. Removed everywhere isUserInteractionEnabled = false even in third-party frameworks to know exactly what is not the problem.
Related
I'm facing a very weird bug. I have a button and I'm pushing a view controller normally, using segues. However, when I push the view controller the whole app layout messes up: it sometimes works, sometimes glitches such as leaving me with a blank view with nothing but the tabbar, or previous view controller still being seen but transformed to somewhere else in the screen etc. If I manage to go back, it always works fine after the first try. Here are some observations:
Problem is specific to device (iPhone X). Simulator (even the same model and same OS version) works perfectly.
Switching to modal doesn't matter. The "glitchy look" animates a bit different, but the problem is still there.
Turning off animation in transition doesn't matter. It presents me a glitchy screen instantly, just without animation.
Pushing/presenting the view controller from code (as opposed to storyboard segue) doesn't matter. Exactly same.
Giving a delay (e.g. half second) after tapping the button before presenting the view controller doesn't change anything. Just wanted to try this to see if some race condition is present on tap, for whatever reason.
The problem is specific to one view controller. Presenting anything else at the same segue/state doesn't cause any problem.
The problematic view controller doesn't have anything special at all: It's actually just a wrapper with three child view controllers, something I commonly do:
When I'm trying to present the problematic controller, I'm always getting this weird log: [Render] CoreAnimation: failed to allocate 1223558576 bytes
My application is definitely not out of memory. It's using ~50MB on iPhone X at the time of problem. It's a media app and can allocate ~500MB with no issues or crashes when shooting/filtering video etc.
The problem occurs if a specific embedded view controller (the second one of three) is present. For example, if I remove the embed segue to that, it seems to run perfectly.
That embedded view controller is a simple UIViewController subclass that just has a table view and some cells.
What might be going on?
I followed this tutorial to create a PageViewController and it works perfectly when I run it on an iOS 9.3 emulator device. However, when I run it on an iOS 10.0 emulator device, it duplicates the first view controller behind the pageViewController - so that when you scroll left on the first slide, you can see the initial viewController peeking out from behind it, and similarly when you scroll right on the last viewController, you can see that same first viewController peek out from behind that too. On the iOS 9.3 device, there is just a white background.
Additional information:
I'm using the UIPageViewControllerTransitionStyleScroll so there is that 'bounce' effect (which is where you can see the white on iOS 9.3 and the duplicated viewController on iOS 10)
I cannot use another transition style (as some other solutions suggest just using a 'curl' transition)
I've already tried UIPageViewController memory leak (see solution by specialvict in that post)
Just to be clear, I want a white background behind the pageViewController so that when you scroll left on the first slide or right on the last one, you see just white.
Found the solution. The function used to create and setup the viewController and its subviews were standard and had nothing significantly different to the code from the tutorial above. The problem I had was that I called this function in viewDidLayoutSubviews without checking if the containerView was not perhaps already initialised (containerView being the view that I add the pageController to).
To check out what is happening, I print a short message to the log when the containerView is initialised. I removed the check if (!self.containerView) and iOS 9 only initialises the containerView once whilst iOS 10 initialises twice. Thus, adding the check if (!self.containerView) before initialising the containerView fixes this problem for 10.
I am building an application in Xcode 6.2, for iOS 8.1. I have a UIViewController (LevelViewController) which contains a UICollectionView whose cells each represent a level in my game (each one has a label w/ a number). Once one of the cells is selected I perform a show segue to an SKScene which loads all the data for that particular level.I also have a "menu" button which performs a show segue back to the main menu.
Functionally this all works, however I am having serious memory problems after performing both segues. After peeking in instruments it appears that when I segue out of the LevelViewController that all of the UILabel that I added for each individual UICollectionViewCell remain in memory, along with everything else contained in the cells. There should only be 192 labels (for 192 levels) but after performing this segue several times they add up to around 1000 in instruments.
Obviously these are not being deallocated in memory, It's my understanding that swift should take care of that, so i'm not sure what the problem is. I should also note that the UICollectionView was added programmatically, and no IBOutlets are used.
So how exactly can I get rid of those labels, and really, the UICollectionView itself when I segue away from the LevelViewController. Im seriously confused about this and it's ruining my St. Patricks Day. So for the love of all things Irish please help a lad out :)
Note: methods I have tried
self.collectionView.removeFromSuperView()
self.collectionView = nil
self.collectionView.deleteItemsAtIndexPaths(path)
It's hard to tell without seeing the code you're using to perform these segues. But I'm guessing that the problem has to do with how you are segueing between the view controllers.
I also have a "menu" button which performs a show segue back to the main menu.
If I had to guess based on your language above, instead of popping the Level ViewController (I'm assuming it is embedded in a UINavigationController), you are trying to segue back to the main menu using performSegueWithIdentifier: This will actually create a new instance of the view controller and push it onto the navigation stack (and retain the existing instance of it leading to your memory woes).
If that's indeed your problem, the solution is pretty simple: When your menu button is tapped, you should be calling popViewControllerAnimated or dismissViewControllerAnimated:completion:.
A simple little thing worth doing while you get accustomed to iOS segueing is to add de-initializers to all your view controllers as follows so as to get ongoing debug messages that objects are being deallocated as expected:
deinit {
debugPrintln("Name_of_view_controlled deinitialized...")
}
Happy St. Paddy's Day!
I have two UIViewController. One is ViewController, and another is GameplayViewController.
ViewController will execute
let gameplayViewCtrl = GameplayViewController()
self.presentViewController(gameplayViewCtrl, animated: true, completion: nil)
in viewDidAppear() function. So it shows then load another UIViewController.
GameplayViewController has UICollectionView as its member. It extends/conforms to UIViewController, UICollectionViewDelegate, UICollectionViewDataSource. I've linked delegate, datasource, and UICollectionView variable as #IBOutlet properly in storyboard.
With above setup, I tested it. It shows white screen for a sec, then shows black screen. The cells in UICollectionView in GameplayViewController are never get loaded (no call in code checked via breakpoint). But if I changed the entry point (an arrow in storyboard) to point at GameplayViewController, then it loads properly and show all data in cells. Things work fine.
What's the problem here? I guess it's about event chain that never get caught in non-default UIViewController.
FYI: I do this in xcode 6 beta 3
Updated
I did some more research, and found out there're at least two possible ways to do this. One is my approach, and another is to use segue.
Segue works, you can find how to do it How do I use performSegueWithIdentifier: sender:?. I tested it.
I also tested to switch from GameplayViewController to ViewController (reverse from my original test). It showed black screen similar to the first test. But it should show white screen as for ViewController, it has white background color. This triggers me to think that something's wrong creeping inside.
For now, I use segue approach. But I still want to know why self.presentViewController() won't do the job for us, and it shows black screen and nothing called or happened.
I changed navigation in my application from using UITabBarController to u UINavigationController. I.e. former solution (1st version) was based only on the TabBarController - 4 ViewControllers (one simple TableView, one simple custom view and one MapView with many overlays). The second version is based only on the UINavigationController.
In case of TabBarController it was clear and simple, everything worked fine, especially MapView. I mean: the MapView was loaded once (with a significant number of overlays) and when I went to another view and back to the MapView the MapView was still there with its overlays already loaded and displayed (simple check: MapView`s viewDidLoad was called just once per app run, I had some debug messages there).
Now I changed navigation logic to the UINavigationController. Everything works fine for the first look - but: the viewDidLoad (for each view) is called everytime I navigate to the view. It is annoying especially in the case of the MapView - the loading of overlays is performed everytime, it takes some time and it causes app crash in some cases.
OK, my questions:
Is it some kind of "common" behavior of NavigationController?
Can I change this behavior so viewDidLoad will be called just once?
And more - How can I influence the "display sequence" of some view?
I understand the logic is probably more complicated but I appreciate any answer or hint ;)
Some related circumstances:
TabBar and Navigation controllers are not combined.
I use storyboards, segues are designed in the UIB, no manual calling like perfomSegue or prepareForSegue in my code. One button triggers segue to MapView.
I use push segues.
I also tried to use modal segues but without any change of that behavior.
any of viewDidUnload is never called during segues among the views.
No memory warning received.
No memory leaks measured both on simulator and iPhone 4.
I tried to build a very simple temporary project / app that is concerned just about the Nav. Controller and other views without ANY coding, just storyboard. It was the same behavior.
There was an issue that causes app crash when I fast and periodically tapped to navigation button and back button between one view and the MapView. In most cases the app crashed when I tapped the back button on the MapView before it was fully displayed (i.e. its overlays). It was fixed when I added a 1 sec. delay method call in the viewDidDisappeared in the MapView. It is not a fair fix, I know ;)
A UITabBarController and UINavigationController are based on fundamentally different paradigms.
The UITabBarController is intended for the UIViewController on each tab to exist independently of each other and for the user to choose which they want to view. viewDidLoad only gets called once for each UIViewController because it is intended that each tab still exists in memory even as the user switches to a different tab.
The UINavigationController is a stack of UIViewControllers where each is related to the one above and beneath itself. The top UIViewController in the stack is always the one that is visible to the user. When a UIViewController is pushed to the stack, its viewDidLoad gets called because it is being loaded into memory. When the top UIViewControllergets poped off the stack, it is unloaded from memory, and viewDidUnload gets called on the way out (viewDidUnload is deprecated in iOS6 and won't get called, but the controller will still get dumped from memory). This is why viewDidLoad gets called every time that the user pushes a particular UIViewController onto the UINavigationController stack.