Change ViewController Swift - iphone

i have an issue. I would like to change the view controller in swift.
This is a part of my code:
if success == "1" {
NSLog("Login SUCCESS");
var prefs:NSUserDefaults = NSUserDefaults.standardUserDefaults()
prefs.setObject(mobile, forKey: "USERNAME")
prefs.setInteger(1, forKey: "ISLOGGEDIN")
prefs.synchronize()
self.presentViewController(OtpVC(), animated: true, completion: nil)
}
my OtpVC file is:
class OtpVC: UIViewController {
#IBOutlet weak var smsfield: UITextField!
#IBAction func continueButton(sender: AnyObject) {
}
}
The problem now is that when is login successful the page change and goes all black!
How i can fix that? Thanks in advance.

The page in blank is an indicator of that your view has not being loaded. And it seems like that's the case:
Please take a closer look, you are creating an instance of that class, but you are not instantiating the view of it.
In swift you can have single classes affecting several views in your
storyboards.
The correct way, should be:
if success == "1" {
NSLog("Login SUCCESS");
var prefs:NSUserDefaults = NSUserDefaults.standardUserDefaults()
prefs.setObject(mobile, forKey: "USERNAME")
prefs.setInteger(1, forKey: "ISLOGGEDIN")
prefs.synchronize()
var storyboard = UIStoryboard(name: "Main", bundle: nil)
"Main" here should be the name of the storyboard in which the OtpVC view is.
var controller = storyboard.instantiateViewControllerWithIdentifier("OtpVC") as! OtpVC
"OtpVC" here should be the storyboard identifier of your view
self.presentViewController(controller, animated: true, completion: nil)
}
Update:
Another root cause may be that your identifier is not well set at storyboard.
At your Identity Inspector settings should be similar to:
Here in Module, like I have no such Class on my targets it says None.
This could be something you may want to have a look at. Maybe in your storyboard you are referencing other target than the one with such OptVC class implementation.

You can also use segues.
Set a segue from one view controller to the one where you want to shift in the storyboard.
Also set the identifier of the segue in storyboard.
Now use below code
self.performSegueWithIdentifier("identifier", sender: self)

self.presentViewController(OtpVC(), animated: true, completion: nil)
With the line above, you'll create a new instance of OtpVC programmatically. It's not a problem if that's what you want and the view controller is coded properly to be initialized like that.
But because it's all black I assume you've created OtpVC in storyboard so you'll either need to use a segue like Sukhdeep Singh Kalra has suggested or instantiate it with:
let destination = storyboard?.instantiateViewControllerWithIdentifier("identifier") as! OtpVC
presentViewController(destination, animated: true, completion: nil)
Both options, you'll have to set an identifier.
To set an identifier for the latter, go to storyboard and click on your view controller. Make sure the view controller is selected by clicking the left yellow button on top of your view controller. Then in identity inspector, type in the identifier name and replace "identifier" in my example with that name.

Related

Quicklook always displays "no file to preview" error (url is valid)

I'm trying to use QuickLookController subclass as a child controller, setting its view as a subview in the parent. However, it always displays "no file to preview" message in the opening window. URL in the data source is valid, but the controller is never trying to get it! func previewItemAt index is never invoked!
func "numberOfPreviewItems" invokes always.
Please, help!
I get it. driven by example in article https://williamboles.me/hosting-viewcontrollers-in-cells/ I loaded my controller from bundle:
static func createFromStoryBoard() -> PreviewControler {
let storyboard = UIStoryboard(name: "PreviewControler", bundle: Bundle(for: PreviewControler.self))
guard let viewController = storyboard.instantiateViewController(withIdentifier: "PreviewControler") as? PreviewControler else {
fatalError("PreviewControler should be present in storyboard")
}
return viewController
}
But QuickLook controller must be created with it's constructor, so change to
let viewController = PreviewController()
solved the problem. Now all is fine.

How to remove duplicate VC in swift?

I am making a game, where I go from the main screen to a ArcadeViewController, which loads up the SKScene, and save the previous VC as prevVC.
I use segues created in storyboard to move between VC.
The problem is that each time I move to a VC, instead of moving into the old one, a copy gets created, and both of them start to run at the same time.
I tried removing them by running the following codes, when I move into the VC:
override func viewDidAppear(_ animated: Bool) {
UIApplication.shared.keyWindow?.rootViewController = self
self.view.window?.rootViewController?.dismiss(animated: true, completion: nil)
prevVC.reloadViewFromnib()
prevVC.dismiss(animated: false, completion: nil)
UserDefaults.standard.set(0, forKey: "since_The_Last_Ad")
}
extension UIViewController {
func reloadViewFromnib() {
let parent = view.superview
view.removeFromSuperview()
view = nil
parent?.addSubview(view) // This line causes the view to be reloaded
}
}
It helped to reduce the number of copies created, but still the are some.
How can I remove duplicate views?
So the solution ended up being to use the normal segue to launch the ArcadeVC from GameVC(start VC) for the first time.
Then set the ArcadeVC as rootVC:
UIApplication.shared.keyWindow?.rootViewController = self
Then use a normal segue to go back to the GameVC.
After the ArcadeVC is set as the rootVC, just use normal segue to the ArcadeVC form GameVC, and unwind from GameVC to AracdeVC.

How to instantiate a view controller programatically, without storyboard

Is there a way to instantiate a view controller programatically without using storyboard identifier. I want to push CNContactPickerController into my root view controller .
let controller = CNContactPickerViewController()
controller.delegate = self
navigationController?.present(controller, animated: true, completion: nil)
i did this but in contactPicker (delegate) i push a VC from storyboard where i save what info i want from that specific contact.
The problem: when i pop the last view controller i want to go on the CNConctactPickerControllerView but i go on the first view controller
i tried with dismiss but nothing happens..
The problem with doing this is that NONE of the UI for your view controller is created. What you are doing is simply instantiating an instance of the class. None of the corresponding UI is created, also your IBOutlets will be nil.
You have 2 options, either you use Interface builder and instantiate from the Nib or Storyboard, or you create ALL your UI manually in code.
For the sake of resuability you could create a static method on CNContactPickerViewController to handle the storyboard instantiation for you. See the following:
class CBContactPickerViewController: UIViewController {
static func fromStoryboard() -> CNContactPickerViewController {
return UIStoryboard(name: "foobar", bundle: nil).instantiateViewController(identifier: "CNContactPickerViewController") as! CNContactPickerViewController
}
}
You can then utilise this as follows:
self.present(viewController: CNContactPickerViewController.fromStoryboard(), animated: true, completion: nil)

Swift - How to pass UInavigationController and also pass variables

What is the best way to pass a UInavigationController and also pass variables to a new viewController. I know how to do one or the other but not both at the same time. Thank you in advance
this is my current code
func(){
let vc = storyboard?.instantiateViewControllerWithIdentifier("messagesViewController") as! UINavigationController
let posts = self.postList[indexPath.row]
//this is the var that i want to past
//vc.previousViewMessageId = posts.postKey
self.presentViewController(vc, animated: true, completion: nil)
}
If I understand you correctly, you have a view controller that can present a second VC. And this VC is embedded in a UINavigationController. What you don't know how to do, is to pass data from the first VC, to the navigation controller, then to the second VC.
Here is a brute force solution. It's not beautiful, but it works anyway.
Make your own UINavigationController subclass:
class DataPasserController: UINavigationController {
var previousViewMessageId: SomeType?
override func viewDidLoad() {
if let vc = self.topViewController as? YourSecondViewController {
vc.previousViewMessageId = self.previousViewMessageId
}
}
}
Now you can add a navigation controller in the storyboard, set its class to DataPasserController, and connect the second VC to it as its root view controller.
Now suppose you have got an instance of DataPasserController by calling instantiateViewControllerWithIdentifier, you can do this:
yourDataPasserControllerInstance.previousViewMessageId = posts.postKey
And present the instance!
To pass a value to your Navigation Controller's Root View Controller, you access viewControllers[0] and cast it to the class of your Messages View Controller (the controller that has the previousViewMessageId property):
func () {
let messagesNC = storyboard?.instantiateViewControllerWithIdentifier("messagesViewController") as! UINavigationController
let messagesVC = messagesNC.viewControllers.first as! MessagesViewController
messagesVC.previousViewMessageId = postList[indexPath.row].postKey
presentViewController(messagesNC, animated: true, completion: nil)
}
What you have there is simply presenting a view controller... You are skipping the navigation controller.
What you need to do is present the new view controller inside the navigation controller. Once you have done that, it will show correctly. You can also pass the variables after you've created the vc variable.
This presents the new viewController (vc) within the navigation controller...
self.navigationController?.pushViewController(vc, animated: false)
This sets the variable in the new viewController (vc) (you are correct)
vc.previousViewMessageId = posts.postKey
So complete:
func(){
let vc = storyboard?.instantiateViewControllerWithIdentifier("messagesViewController") as! MessagesViewController
let posts = self.postList[indexPath.row]
//this is the var that i want to past
vc.previousViewMessageId = posts.postKey
navigationController?.pushViewController(vc, animated: false)
}
PS. While not part of the question, I feel I should still mention... Use of the word self should be left to necessity only. In other words, don't use it when it isn't needed. for example self.postList[indexPath.row] :)
https://github.com/raywenderlich/swift-style-guide#use-of-self

Swift - Access different View Controllers in App Delegate

In app delegate, with a simple app having only 2 screens:
first screen is a Table View Controller embedded in Navigation Controller
second screen is a View Controller which is used to add items to the first screen table via protocol/delegate/segue
And this is the code for didFinishLaunchingWithOptions in app delegate that I can reference the first screen as viewController[0]:
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
let navController = self.window?.rootViewController as! UINavigationController
let courseListController = navController.viewControllers[0] as! CourseListController
courseListController.managedObjectContext = self.managedObjectContext
return true
}
How can I reference the screens at above, below and next to the center sreen? Please suggest me a solution. Thank you!
It's important to keep in mind that the view controller objects for all of the "peripheral" view controllers in your story board won't actually exist until the segue to get to them is executed, so there's no way to get access to them directly from the app delegate. Instead, you need to push state to each child view controller as it's created, from whatever the source view controller is. Segues are the appropriate way to do this.
You will probably want to assign each of the segues from the central view controller a unique segue identifier in Interface Builder. Click on the segue, then enter it here:
In the central view controller, implement prepareForSegue(_:sender:), doing something like the following:
func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject) {
switch segue.identifier {
case "SegueIdentifier1":
guard let destination = segue.destinationViewController as? ViewController1 else {
return
}
// set up your view controller here
case "SegueIdentifier2":
guard let destination = segue.destinationViewController as? ViewController2 else {
return
}
// set up your view controller here
// add additional segues as required
default:
break // unknown segue
}
}
Go to each view Controller you want to reference and in the identity inspector, add some string to its StoryBoard ID.
next to reference it from the new ViewController (say, XViewController) to (say, YViewController)
do this :
var referencedViewController = self?.storyboard.
instantiateViewControllerWithIdentifier("referenceViewID") as! YViewController
self.presentViewController(referencedViewController,
animated: true, completion: nil)