Change key to true then show view in swift - swift

OK, so I've added a view onto my Application that asks the user to accept or decline the Terms of Service. I have it so when they click accept, it changes the key "TermsAccepted" to true. If they close the app, and re-open it, it gives them access. However I'd like to be able to give them access without re-opening the app first.
So in my ViewController (Main Screen), in my viewDidLoad I have the following:
if NSUserDefaults.standardUserDefaults().boolForKey("TermsAccepted") {
// They've been accepted, do nothing.
} else {
let termsView = self.storyboard?.instantiateViewControllerWithIdentifier("FirstLaunchTerms") as! FirstLaunchTermsView
self.presentViewController(termsView, animated: true, completion: null
}
In the 'LaunchTermsView' I have the following code for when they accept the terms.
#IBAction func acceptTerms(sender : AnyObject)
{
NSUserDefaults.standardUserDefaults().setBool(true, forKey: "TermsAccepted")
}
And thi works fine, but they have to re-open the application.
I tried to just have it so the button opens the Main View at the same time as those terms are accepted (After the key is updated) but it gives me the following error.
fatal error: unexpectedly found nil while unwrapping an Optional value (lldb)
I assumed this meant that it was wanting to re-open the launch terms view again, so I tried to move all the code from viewDidLoad to viewWillAppear so it checks each time, but it just gives the same error. (it was a long shot try before I posted on here).
I had a look at some posts on here, but a lot of them were in ObjC or just didn't give me a solution or any form of help to trying to find one myself.

As you're presenting your terms view controller you should simply be able to dismiss it when you're done with it. You don't show any other code so I'm assuming that your 'home' view controller is waiting to be revealed underneath (you don't need to try to show it again).

Related

performSegue(withSender: sender:) does not work - no errors displayed

func checkForRecipes(noRecords: Bool) {
//segue to addNewRecipe page
if noRecords == true{
print("Can't Find any Recipes!")
self.performSegue(withIdentifier: "ToAddNewRecipeVC", sender: self)
}else{
print("error, noRecords not equal to zero")
}
I am able to segue successfully via the storyboard but want to do so programmatically based on information returned from a delegate.
Upon running the app, the information from the delegate is successfully sent to the function "checkForRecipes" -i.e "noRecords" returns TRUE, but for some reason, the below line of code within that function does not seem to execute (and no errors are thrown):
self.performSegue(withIdentifier: "ToAddNewRecipeVC", sender: self)
The app starts up but stops at the main screen, whereas it should segue to the "AddNewRecipe" view controller.
The segue itself definitely has a segue ID of "ToAddNewRecipeVC". I have also tried dispatching to the main queue (to no avail) based on the following thread.
I'm stumped - what's going wrong here?
OK, it looks as though I have solved the problem. I embedded the main view controller into a navigation controller and now everything works as intended. I tried this same tactic earlier and it kept throwing up errors. grrr!
Anyway - thank you to all for the input!

UIWindow endDisablingInterfaceAutorotationAnimated error appears in console when keyboard is dismissed interactively from collectionView in iOS9 only

I am getting this strange error in iOS 9 only:
[UIWindow endDisablingInterfaceAutorotationAnimated:] called on UITextEffectsWindow: ...without matching
-beginDisablingInterfaceAutorotation. Ignoring.
Anytime I dismiss the keyboard interactively by dragging down from within my collectionView. I don't get the error by dismissing the keyboard with a tap gesture or pressing enter. It is very frustrating. Even if I don't observe any keyboard notifications, I still get this error on this interactive keyboard dismissal. I wonder if anybody else has come across this error and found a solution. I have an inputAccessoryView consisting of a textView mounted on the keyboard.
I had the same problem on iOS9 but with a tableView. I implemented this along with self.tableView.keyboardDismissMode = .Interactive and it worked for me.
// Dismiss keyboard when scrolling
func scrollViewWillBeginDragging(scrollView: UIScrollView) {
textView.resignFirstResponder()
}
Things to Check
It appears that several other SO users have had similar experiences under a variety of conditions. Check out this thread. Since there could be a lot of things happening that cause this problem you might want to review the thread provided to see if you can find a matching use-case. It's unclear how you are dismissing the keyboard but you might want to call something like this from a method or as a gesture recognizer (rather than a direct dismissal from a specific object):
UIApplication.sharedApplication().sendAction("resignFirstResponder", to: nil, from: nil, forEvent: nil)
From the thread provided, the nature of the issue in most cases was a duplicate call during presentation or dismissal of the view. I've also seen issues where I have a storyboard segue connected (or in some cases it was removed but the xml was still in the storyboard code view) and a code-based segue (performSegueWithIdentifier...) for the same animation (which causes two display/dismiss calls).
I'd look at the log to see what calls are being logged just before the error and then do a find in the log view to see if there is a redundant call. Again there could also be a redundancy in the behaviors/animations/layouts on the storyboard and calls made in the code.
UPDATE
The comments from the OP, reminded me that in some cases especially those involving calls during presentations/dismissals, I have seen instances where the only way to successfully have a developer function work is to wrap it into a dispatch_async call. There are some critical systems calls that appear to not work well if developer code is introduced during the same frames.
A concrete example is this call which is within willMoveToWindow. In this case I have a weakSelf reference to the view and simply review the newWindow for nil value (indicates the view is being dismissed) before calling my code.
So in this example if one removes the dispatch call, then the developer code would cause the entire app to crash. I'm guessing that the system transition calls (related to transposing to/from the window) may be conflicted with whatever the developer requests at that time.
dispatch_async(dispatch_get_main_queue(), { () -> Void in
//the saved flag is true only when user hits the done button
if !(weakSelf!.saved) {
weakSelf?.completeNotes(nil)
}
})
I encountered this issue and it messes up my view. This is how I solve it.
I was having a viewController being presented on textFieldShouldBeginEditing. In the viewController, a textField was set to becomeFirstResponder in viewDidLoad.
The solution for me is to move the becomeFirstResponder to viewDidAppear.

WKInterfaceLabel.setText not reflecting changes following modal viewController dismissal

I am working on a simple video game for the Apple Watch. In awakeWithContext() I call my own method, startNewGame(), and register for it to be called again when receiving a notification from my modal viewController. This all works fine. Then upon determining the game is over, I call self.presentControllerWithName().
When that controller is dismissed by the player I call self.dismissController(). Then I fire a notification that once again calls startNewGame(). This is where things get weird.
self.score = 0
let scoreString = formatScore(0) //"0000"
self.scoreboard.setText(scoreString)
let hiScore = NSUserDefaults.standardUserDefaults().integerForKey("hiScore")
let hiScoreString = formatScore(hiScore)
self.hiScoreboard.setText(hiScoreString)
The above excerpt from startNewGame() shows me resetting the score and updating both "scoreboards" both WKInterfaceLabels that present scores in a skeumorphic old-timey LCD fashion. Because of this, I call formatScore() which returns a string with leading zeros. Anyway, I then set the text on them both and… nothing happens. Both boards show the same score as before the game over view controller was shown. It is only when they are next updated in response to player's actions that they update to reflect the correct values. Because I only have issues with this when the code runs shortly following the dismissal of a modal viewController, I suspect there is some connection. Anyway, I am stumped, some help would be much appreciated.
I ran into the same problem receiving data from the iPhone using sendMessage.
My code was pretty straight forward:
dispatch_async(dispatch_get_main_queue(),{
if let error = error {
NSLog("showing error: \(error)");
self.lblTitle.setText("Error...");
}
});
For me, the message was being logged, but the interface wasn't getting updated.
Ends up I was showing multiple pages using reloadRootControllersWithNames and when I tried to update a label within a page that wasn't being shown, the update was ignored.
I fixed it by listening to willActivate and didDeactivate to see whether to update the label or whether to save the text so I could apply it when the page is shown.
Apparently this is by design.

Segue following a change in criteria from a local notification in Swift

I have created a local notification in Swift which gives the option to end a current game without having to go back in to the app. That's all fine and works as it should. The issue I'm having is that if the user does this, I don't want them to go back to the Game view controller if that happens to be the last view that was open when the app entered the background. I would like them to go back to the app's Home view controller instead.
I expected to be able to add a perform segue to my Game view controller in the following way, should the criteria match. I tried adding it to viewDidAppear(), but it didn't work:
override func viewDidAppear(animated: Bool) {
if isThereACurrentGame() == false {
performSegueWithIdentifier("unwindToHomeScreen", sender: self)
}
}
Is this something to do with viewDidAppear() not being called when the app comes back to the foreground? If so, what might an alternative be?
P.S. My isThereACurrentGame() function works as it should, as does the performSegueWithIdentifier elsewhere in the view controller, so these aren't the cause of the problem.

Swift and watchkit: pushControllerWithName not being called at all

I have always used the pushControlledWithName method in swift/watchkit to move to another interface controller, basically like this:
self.pushControllerWithName("newinterfacecontroller", context: nil)
In some of my projects, when I put this in a function (like where the user presses a button) it simply doesn't get called at all. No errors, just as if the code isn't there at all. If I create a new test project and try it it works. I am baffled as to what's going on here.
Example of what happens:
#IBAction func button1Action() {
println("test")
self.pushControllerWithName("newinterfacecontroller", context: nil)
}
Pressing the button will print "test" in the console, but it doesn't try to move to the new interface controller (with identifier "newinterfacecontroller") at all.
I think you've figured this out from the comments, but page-based interfaces are technically modals and not navigation-stack interfaces.
You can present modals from anywhere, but you can only push onto a navigation stack from a non-modal.