performSegueWithIdentifier not working if called from viewDidLoad - swift

I have a simple app with a loading screen. Here I check for some user details in NSUserDefaults and jump to either the login or the sign up screen.
The viewDidLoad() for the loading screen looks like this:
override func viewDidLoad()
{
super.viewDidLoad()
loadingVM = LoadingVM() as LoadingVM
print("LoadingVC")
checkStoredUser()
}
Here is the checkStoredUser()
func checkStoredUser()
{
storedUserStatus = loadingVM.returnStoredUserStatus()
if(storedUserStatus == true)
{
performSegueWithIdentifier("loadingToLoginVC", sender: self)
}
else
{
performSegueWithIdentifier("loadingToSignUpVC", sender: self)
}
}
As you can see, I decide where to go from here based on what the loadingVM.returnStoredUserStatus() returns. I am sure this returns what it's supposed to return but nothing happens.
Here is the prepareForSegue()
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?)
{
print("prepareForSegue")
if(segue.identifier == "loadingToSignUpVC")
{
let signUpViewCotroller = (segue.destinationViewController as! LocalSignUpVC)
}
else if(segue.identifier == "loadingToLoginVC")
{
print("loadingToLoginVC")
let loginViewCotroller = (segue.destinationViewController as! LoginVC)
}
}
I did some digging and found a weird suggestion that seems to be working but It's not very practical not to mention right to do it like this:
func checkStoredUser()
{
storedUserStatus = loadingVM.returnStoredUserStatus()
let delayTime = dispatch_time(DISPATCH_TIME_NOW, Int64(1.0 * Double(NSEC_PER_SEC)))
dispatch_after(delayTime, dispatch_get_main_queue())
{
if(self.storedUserStatus == false)
{
self.performSegueWithIdentifier("loadingToSignUpVC", sender: self)
}
else
{
self.performSegueWithIdentifier("loadingToLoginVC", sender: self)
}
}
}
Can anyone explain to me what's going on here, why doesn't this work and how to make it work properly? It's the first time I encounter this and I can't seem to be able to find any info on this.

EXPLANATION:
Your View hasn't appeared yet when you call your checkStoredUser().
EASY FIX:
Put it in viewDidAppear() like this:
override func viewDidAppear(animated:Bool) {
super.viewDidAppear(false)
checkStoredUser()
}

Related

Unable to get buttons currentTitle from UIStoryBoardSegue

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "Choose Theme" {
if let themeName = (sender as? UIButton)?.currentTitle {
if let theme = themes[themeName] {
if let cvc = segue.destination as? ConcentrationViewController {
cvc.theme = theme
}
} else {
print("something went wrong")
}
} else {
print("couldnt get current title")
}
}
}
There is the code. I'm trying to get senders current title. I tried debugging and it prints "couldn't get current title", the value that I'm getting is nil.
What am I doing wrong?
Thanks in advance
Instead of using currentTitle, you might want to try titleLabel?.text. It seems to be more reliable. I got your program to work (tested in Xcode) using this change.

Switch control to toggle isHidden

I have an app with two switch controls to hide or show some textfield depending on their state on or off.
The problem is the first switch seems to control the second one.
If the first switch is off, the second switch is off also. I would like them to work independently from each other.
Any advice?
Thanks guys
#IBAction func switchP(_ sender: UISwitch) {
if (sender.isOn == true) {
textFieldP.isHidden = false
} else {
textFieldP.isHidden = true
}
}
#IBAction func switchT(_ sender: UISwitch) {
if (sender.isOn == true) {
textFieldT.isHidden = false
} else {
textFieldT.isHidden = true
}
}
First, replace
if (sender.isOn == true) {
textFieldP.isHidden = false
} else {
textFieldP.isHidden = true
}
by a simple single line:
textFieldP.isHidden = !sender.isOn
Second, use Connections Inspector (right panel, the arrow in the circle) and make sure your Referencing Outlets are not mixed or duplicated under the same IBAction.
Other than specifying the .isHidden = true using if/else statements, you should use an opposite property reference which is a lot nicer way of doing it.
#IBAction var switchP: [UIView] {
didSet {
textFieldP.forEach {
$0.isHidden = true
}
}
}
And to change based on a click:
#IBAction func switchP(_ sender: UISwitch) {
UIView.animate(withDuration: 0.2) {
self.switchP.forEach {
$0.isHidden = !$0.isHidden
}
}
}
That's the best I can generically answer without seeing all of your code.

Swift, core data, add item from modally presented view

I am updating an app into Swift and have a tableView to which items can be added from a modally presented view. This works fine when the Save button is pressed, but when cancel is pressed the table view is presented with a blank line at the top, showing that an empty item was added. What am I missing?
The AddViewController protocol is:
protocol NewGaugeDelegate {
func didFinish(viewController:AddGaugeViewController, didSave:Bool)
}
and the didSave function is:
extension AddGaugeViewController {
#IBAction func cancelButtonWasTapped(_ sender: AnyObject) {
delegate?.didFinish(viewController: self, didSave: false)
}
#IBAction func saveButtonWasTapped(_ sender: AnyObject) {
addGauge()
delegate?.didFinish(viewController: self, didSave: true)
}
}
in the tableView controller, the protocol is accessed like this:
extension GaugeTableViewController: NewGaugeDelegate {
func didFinish(viewController: AddGaugeViewController, didSave: Bool) {
guard didSave,
let context = viewController.context,
context.hasChanges else {
dismiss(animated: true)
return
}
context.perform {
do {
try context.save()
} catch let error as NSError {
fatalError("Error: \(error.localizedDescription)")
}
self.coreDataStack.saveContext()
}
dismiss(animated: true)
}
}
Suggestions as to why the cancel function is not working properly would be appreciated.

Login Screen Always Shown

I have a login screen that prompts the user to login. After successful login the first time, I need the app to eliminate the login screen when the user opens the app again. I am using NSUserDefaults to set the successful login as true. However, the login screen is always shown to the user. Please help. Thanks.
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
if (NSUserDefaults.standardUserDefaults().objectForKey("onoroff") != nil) {
self.performSegueWithIdentifier("segue", sender: nil)
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#IBAction func button(sender: AnyObject) {
if ((loginid.text == "Hussain") && (passwordText.text == "1234" ))
{
NSUserDefaults.standardUserDefaults().setBool(true, forKey: "onoroff")
self.performSegueWithIdentifier("segue", sender: nil) }
else
{
failedtext.hidden = false }
}
Try adding
if (NSUserDefaults.standardUserDefaults().boolForKey("onoroff"))) {
self.performSegueWithIdentifier("segue", sender: nil)
}
in viewDidAppear method instead of viewDidLoad
Change objectForKey to boolForKey
if (NSUserDefaults.standardUserDefaults().boolForKey("onoroff")) {
self.performSegueWithIdentifier("segue", sender: nil)
}
Also do this
#IBAction func button(sender: AnyObject) {
if ((loginid.text == "Hussain") && (passwordText.text == "1234" ))
{
NSUserDefaults.standardUserDefaults().setBool(true, forKey: "onoroff")
NSUserDefaults.standardUserDefaults().synchronize()
self.performSegueWithIdentifier("segue", sender: nil)
}
else
{
failedtext.hidden = false
}
}

prepareForSegue in SWRevealViewController with Swift

I'm trying to write prepareForSegue in SWRevealViewController with Swift.
Here is my code:
override func prepareForSegue(segue: UIStoryboardSegue!, sender: AnyObject!)
{
if(segue!.identifier == "segueName")
{
var someText = "Text"
var rvc:newViewController = segue!.destinationViewController as newViewController
rvc.topText = someText
}
}
In newViewController I have topText as NSString
Of course I got nil text because I should make SWRevealViewControllerSegue but I don't know how it should look in Swift
I've found the solution.
First of all need to configure SWRevealControllerSegue. In swift it should looks like:
if(segue.isKindOfClass(SWRevealViewControllerSegue))
{
var rvcs: SWRevealViewControllerSegue = segue as SWRevealViewControllerSegue
var rvc:SWRevealViewController = self.revealViewController()
rvcs.performBlock = {(rvc_segue, svc, dvc) in
var nc:UINavigationController = dvc as UINavigationController
rvc.pushFrontViewController(nc, animated: true)
}
}
Second. XCode beta works bad right now with IBOutlet and segue like this. With variable everything is ok.
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if(segue.isKindOfClass(SWRevealViewControllerSegue))
{
var rvcs: SWRevealViewControllerSegue = segue as SWRevealViewControllerSegue
var rvc:SWRevealViewController = self.revealViewController()
rvcs.performBlock = {(rvc_segue, svc, dvc) in
var nc:UINavigationController = self.revealViewController().frontViewController as UINavigationController
nc.setViewControllers([dvc], animated: true)
self.revealViewController().setFrontViewPosition(FrontViewPositionLeft, animated: true)
}
}
}
This doesn't work with the latest version. The release notes state:
Took a cleaner approach to storyboard support. SWRevealViewControllerSegue is now deprecated and you should use SWRevealViewControllerSegueSetController and SWRevealViewControllerSeguePushController instead.
There aren't any swift examples anywhere I can find that explain this though.
The performBlock method no longer exists.
Appreciate any help. It seems impossible to do swift without first learning objective c at the moment :)
What was newViewController? This should work:
override func prepareForSegue(segue: UIStoryboardSegue!, sender: AnyObject!)
{
if(segue.identifier == "segueName")
{
let someText = "Text"
let rvc = segue.destinationViewController as SWRevealViewController
rvc.topText = someText
}
}