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.
Related
Sometimes (but not all the time!) on iPhones (and iPhone simulators) I notice my UITableView header has this 'snapping' behavior that, when I try to drag down from the top of the screen it snaps back up instead of fluidly moving back up like a tableView normally behaves.
I'm wondering if anyone knows of this bug, what causes it, or how I can fix it? I feel like it might have something to do with UITableViewHeader but I'm not sure.
Unfortunately, I cannot share the code, but I don't believe it is something in the code. I manually commented on almost every line of the code and the problem persists!
Here was the problem for me and I'm pretty sure its a bug in XCode/Swift.
At first my navigation controller in the storyboard has this setting:
In my code I have the following method declared:
func navigationController(_ navigationController: UINavigationController, willShow viewController: UIViewController, animated: Bool) {
let hideBar = (viewController == self)
navigationController.setNavigationBarHidden(hideBar, animated: animated)
}
Used to disable the navigation bar on the home screen. The combination of these two (if the method is declared on the home screen) causes a bug as shown above. I am able to repeat this bug in a new project.
The solution to this bug is to check the Show Navigation Bar box on the Navigation Controller
Since code is not provided for this question, I am answering based on my assumption.
Assumption 1 - Using manual layout.
If you have code in layoutSubviews(). Then you might want to check your calculation again. Make sure view frames are calculated one time in layoutSubview() method.
Assumption 2 - View animation is blocked/delayed by some other tasks on main thread.
Make sure to run no-UI/API code in background thread.
Reuse cell instances: for specific type of cell you should have only one instance, no more.
Don’t bind data at cellForRowAtIndexPath: method ‘cause at this time cell is not displayed yet. Instead use tableView:willDisplayCell:forRowAtIndexPath: method in the delegate of UITableView.
Hey, can you move your header view content in first cell of first section, so that you can avoid header view problem. Then check if snappy problem is occurring.
I have been working on an app for some time and just realized the swiping back in the detail view only returns me to the master view the first time. It also isn't smooth, even when it works on the first time. Instead of smoothly going to the master view, it jumps all at once, even when I swipe slowly. It used to work correctly, but I haven't been testing for this specifically, so I don't know when it stopped working and what I changed to cause this.
A little about how my app is setup...
I have a split view controller that is connected to my MasterTableViewController and DetailViewController.
Both of those are have TableViews and are embedded in Navigation Controllers.
I have set it up so that the app originally loads to the MasterTableViewController instead of going immediately to the DetailViewController, but even when I take this out, the interactive pop gesture doesn't work.
I don't believe I've messed with any of the back button controls. I have looked through my code and storyboard and can't find anywhere that I have. This is part of what is most confusing because these questions (1, 2, and 3) all seem to have problems stemming from changing the back button or can be fixed by entering the following line of code:
self.navigationController.interactivePopGestureRecognizer.delegate = nil
Adding that to my code seems to have no impact on how it behaves.
Here is a picture of how it is setup for reference:
I can usually figure out these things on my own, but this problem baffles me because it works the first time, but not any others. As far as I can tell, nothing changes between the first time and the others. I don't know if anybody else has had the same issue, but any help on why this might be happening would be greatly appreciated. I can provide code or answers to questions on how I am doing certain things if needed. I haven't put any in because there are so many different things controlling this piece that I don't know where to start.
When are you calling self.navigationController.interactivePopGestureRecognizer.delegate = nil?
Doing this will definitely disable interactive pop. It sounds like you may be calling this after a certain UIViewController appears.
What other modifications to UINavigationController are you making? Are you using appearance delegate?
Are you subclassing? If so, are you calling super in all of your method overrides?
Also check your overrides of viewWillAppear in child ViewControllers. This method gets called during an interactive pop. If you are doing a lot of computation (or synchronous calls) on the main thread within this method, it could cause frame drop, hence the choppy animation.
Hope this helps
From Alex Chase's answer : Also check your overrides of viewWillAppear in child ViewControllers. This method gets called during an interactive pop.
added it to viewWillAppear and it worked:
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
navigationController?.interactivePopGestureRecognizer?.delegate = self
}
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.
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.
I would like to display a webview useful to unlock a website providing data for the detail view controller in the master controller of the iPad version. Yet when I do so, similarly to what I successfully do with a TableView, just the ViewDidLoad callback gets called, but not the ViewWillAppear and in general it seems nothing happens like the view were not shown. My code seamlessly works in the iPhone version, while I checked the StoryBoard several times without finding anything suspect. Any idea about what is the reason for that and a solution?
At any rate I substituted the MasterController with a PopUp and everything works finely: still doubtful why a WebView cannot be shown in the masterViewController: perhaps just tableviews may show there.