Swift - Elements missing when programmatically instantiating a view controller - ios

First of all, I'm brand new to swift and iOS dev! I've decided to get started with it, and so far so good. Except for today.
So I first created a single view app, following the tuto, then I decided to see what happens if a added another view. Using segue to navigate between views seemed to work fine, so I wanted to see how I could navigate programmatically, having in mind that the "destination view" may be conditional on more than just a user pressing a button. So I added a first view to become my initial view controller, and I've found the following code online to transition to my other view:
let storyBoard = UIStoryboard(name: "Main", bundle: nil)
let nextViewController = storyBoard.instantiateViewControllerWithIdentifier("home")
self.presentViewController(nextViewController, animated:false, completion:nil)
There was no problem, no error or console message, except for one little problem: some UI elements of the "destination view" (nextViewController in my case) are missing when the view loads! And some of them (but not all) show up after I click on some other elements of the view.. Note that there was/is no problem if I set the nextViewController as the initial one.
I haven't been able to find any clue on the internet about that problem, and I would greatly appreciate it if someone could point me in the right direction..

Oh well, 5 more minutes and finally an error message were enough to fix that problem!
I've found my solution on the following thread:
whose view is not in the window hierarchy
As it's said, moving my code from the viewDidLoad method to the viewDidAppear one fixed the issue. And I had the same error as the OP mentioned.

Related

Crash when trying to push view controller in Swift

I am having a weird issue where my app crashes when I am trying to push a new view controller. I have set up a swipe gesture and want to segue to another view controller when a swipe is detected. When I run these 2 lines of code ...
let viewController:ViewController = ViewController()
self.navigationController?.pushViewController(viewController, animated: true)
The app crashes not specifically on either of those lines of code but rather in my ViewController class when in my viewDidLoad method I run this piece of code...
imageView.layer.masksToBounds = true
If I comment that out it crashes when I set the auto-correction type of my textField. What am I doing wrong?
First place I look when the view immediately crashes is in the Outlets for that ViewController in InterfaceBuilder. I look for anything that shows up with an exclamation mark. That usually means I renamed an outlet or broke a connection somehow. Delete anything broken by pressing the little x by the item that's messed up. I'll attach a photo so you can see.
It seems you're loading a ViewController that exists in storyboard with
let viewController:ViewController = ViewController()
which will result in nil outlets , so you have to use
let viewController = storyboard.instantiateViewController(withIdentifier: "VCID") as! ViewController
and give that vc a storyboard identifier like VCID
I think I have solved the issue but it has a weird side effect. Instead of using the line of code in #Sh_Khan's answer, I used ...
let viewController = nav?.storyboard!.instantiateViewController(withIdentifier: "mainVC") as! ViewController
The variable nav is equal to the navigation controller of the current view-controller. This seems to work without any hiccups but for some reason the back button does not disappear from the navigation controller after the segue is preformed. Does anybody know a solution to this, if so leave a comment and I will update my answer.
EDIT:
Another issue is that it wipes everything changed on that ViewController by the user clear. Is there another way to instantiate a ViewController without clearing it?
Follow what #Sh_Khan has said and in addition to that make sure that the view that you are making the push segue from is embedded in a Navigation controller.

Xcode 7 - Some segues not working anymore

I upgraded my Swift app to Xcode 7 / Swift 2.0 and now suddenly certain segues in my app no longer work.
I have a segue popping up a "Check In" modal and it works perfectly, but then I have another segue popping up a "Check Out" modal that's near identical and it doesn't launch and the app is frozen.
I re-created the segue from scratch, confirmed that it is identical to the "Check In" one, and it still doesn't work.
I also, instead, tried launching a blank view instead of my Check Out modal and it works fine.
There are no errors, it just freezes, I did confirm that the "prepareForSegue" portion is being called correctly but the "viewDidLoad" portion of my modal is not being invoked.
FYI, I have auto-layout turned off.
Does your "Check Out" modal have a UITextView? If it does, then there's a bug in Xcode 7 / iOS9 where you cannot launch a modal (or any root view) that contains a UITextView if you have set a default text value in storyboard.
A work around is to make sure your UITextView in storyboard is either blank or has the default Lorem Ipsem value and instead, set the text programmatically in code on viewDidLoad.
Hopefully this bug will be fixed soon.
I suspect there is infinite loop somewhere in you "Check Out" controller code. Try pausing app in debugger after presenting controller (when it freezes) and check stacktrace. If it doesn't help, try commenting-out code line-by-line in viewDidLoad and viewWillAppear to find line causing freeze.
I had this problem, try with this
dispatch_async(dispatch_get_main_queue(), { () -> Void in
let viewController:UIViewController = UIStoryboard(name: "Main", bundle: nil).instantiateViewControllerWithIdentifier("Storyboard Id")
self.presentViewController(viewController, animated: true, completion: nil)
})
You just have to give a storyboard id in your view and normally it's working.
My app was working perfectly in iOS8. Its flow was:
VC: View Controller, NVC: Navigation View Controller, ER: Embedded root relationship between NVC and VC, PS: Push Segue, PG: Programmatic presentation
NVC1---(ER)->VC1---(PS)->NVC2---(ER)->VC2 and so on.
The problem was that VC1-(PS)->NVC2 segue did not work, there was no freeze. vc1.prepareForSegue() was executed, but VC2 was not presented. I experimented and found that I did not have the UITextView problem mentioned here.
By following the breadcrumbs outlined below, I got it work after hours of trying in the following way (code at the end):
NVC1---(ER)->VC1---(PG)->VC2
Here are the steps:
As mentioned in Segue issue in iOS9, multiple NVCs are out of style (shame on Apple for suddenly ditching what is actually recommended in your online tutorial and making apps break!). So I modified
NVC1---(ER)->VC1--(PS)->VC2 while VC2 was still embedded in NVC2. I got errors
similar to the StackOverflow post on view not in hierarchy. So I started doing the transition programmatically and after tackling present vs. push ViewController issue that results in "tried to push modally on active view controller" message and then ViewController lifecycle issues that result in "Unbalanced calls to begin/end appearance transactions" messages, I got the following code working. Based on this experience, I really think Apple should have left a working thing alone in Xcode7/iOS9 update.
//*********** VC1.swift. A translation of working code
class VC1:UIViewController{
private var viewController2:VC2?
private var showVC2: Bool = false
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
if(showVC2) {
showVC2 = false
self.pushVC2()
}
}//viewWillAppear
private var info:String? // info from incoming user action.
#IBAction unwindToVC1FromUserAction(incomingSegue: UIStoryboardSegue?) {
// Do app-specific stuff to get info from incomingSegue and
// store in self.info variables.
let myboard: UIStoryBoard = self.storyboard!;
self.viewController2 = myboard.instantiateViewControllerWithIdentifier(
"VC2 Storyboard ID") as! VC2
self.prepareVC2() // Pass info to VC2.info, stuff you would have done in prepareForSegue
showVC2= true
} //unwind
private func prepareVC2() {
self.viewController2.info = self.info // etc..
}
private func pushVC2() {
self.navigationController!.pushViewController(viewController2!, animated:false)
}
} //class
I had this, but it was none of the above. My segue call happened to be inside a block. When I moved the call to the main thread I saw that I had a 'NSUnknownKeyException' error in the new View Controller. Being inside the block seemed to prevent the error from registering in Xcode, so the app just appeared to hang without any errors.
Once that was resolved the original code worked fine.

Which is the preferred way of doing tutorial page with UIPageViewController in swift for first time entering App only

I am relatively new to IOS interface design, and currently facing this problem:
I am having an app wanted to have a tutorial (UIPageViewController) ahead of the navigationcontroller, which will be the main controller on storyboard that the app will enter with.
Now, what I want to achieve is let the app run my Tutorial Pages ahead for first time of app running, then enter the NavigationController. If it is not the first time, user will go to NavigationController directly.
After some research, I found out there are at least two ways of doing it:
Programming the UIPageViewController totally on code, then in Appdelegate, having an if-else loop to do this.
Insert the UIPageViewController into the storyboard and do it.
So far those are two ways I can find out. For second however, I can't find an optimal way to handle "skipping the tutorial page completely". Or probably there is a better way of doing this. I want the app to be more optimal, and wondering what is the usual way of doing it for an IOS professional's choice.
Thank you!
(p.s. If the question is a repeated one or not clear, please leave me comments. Thanks again! It is possible bonus for if can show some links for github demo.)
The way I normally do this sort of thing is as follows:
Put the tutorial content in a separate storyboard.
In the initial view controller of the main storyboard, check a
dedicated variable in the NSUserDefaults to see if user has ever run
the app before.
If not, then programmatically load up the initial view controller of
the tutorial storyboard and present it.
This way, the main storyboard isn't loaded up with a bunch of view controllers that are only used once, and there is minimal code to write for the transition.
-- EDIT --
Below is a Swift version of the answer to this question: How can I load storyboard programmatically from class?
let storyboard = UIStoryboard(name: "Tutorial", bundle: nil)
let viewController = storyboard.instantiateInitialViewController()
presentViewController(viewController, animated: true, completion: nil)
this link has sample project for that but it is written in Objective-C.
https://github.com/MatthewYork/MYBlurIntroductionView

Multiple types of segues still do not work to move view controller

I recently upgraded to iOS 9 beta / Xcode 7, and one segue just stopped working. I have tried many different things, including completely deleting the view, and class file, and re creating both. For whatever, it gets to the point of the segue, and then it just does not complete that line. I have no idea what to do.
I have tried the regular
self.performSegueWithIdentifier("goToRules", sender: self)
as well as
let storyBoard : UIStoryboard = UIStoryboard(name: "Main", bundle:nil)
let rulesInViewController = storyBoard.instantiateViewControllerWithIdentifier("RulesInViewController") as! RulesInViewController
self.presentViewController(rulesInViewController, animated:true, completion:nil)
as well as
let secondViewController = self.storyboard!.instantiateViewControllerWithIdentifier("RulesInViewController") as! RulesInViewController
self.navigationController!.pushViewController(secondViewController, animated: true)
and none of them work. It is becoming very frustrating, and I just don't know what to do anymore. Is there anything that I could be doing wrong? I completely re did the view controller, and it still doesn't work. ALSO, it is an extremely basic view. All it has is one button, a logo, and a text view of rules for the app... The only code within that class is in the viewDidLoad, and it is defining the rules text.
In storyboard, check the identity inspector tab of your 'RulesInViewController' scene. It should have your custom class 'RulesInViewController' and module should have current -

Switching to New View Controller does not Activate XIB File

I'm new to Swift, and the class I took taught me without storyboards, so just putting that as a caveat.
I'm trying to build my own app now, and I'm trying to push a new viewController onto the main navigation controller. This works fine, but when I go to the new viewController, it doesn't ever load what I put in the xib file. That is, I know it's going to the right place because I can change background color, etc., in code, but I've put some elements in the xib and they're not showing up. I saw this discussion: Load ViewController Swift - Black Screen and did what it said, but it's still not helping.
Here's my push code:
var viewController = CreateViewController(nibName: "CreateViewController", bundle: nil)
self.navigationController?.pushViewController(viewController, animated: true)
What am I doing wrong?
Alternately, and this is probably a better question — I haven't gotten that far yet. Should I just try to learn storyboards? It's not that complicated of an app and everyone seems to say storyboards are better...

Resources