WKInterfaceLabel.setText not reflecting changes following modal viewController dismissal - swift

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.

Related

Change key to true then show view in 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).

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.

Label takes a couple of seconds to unhide

So I recently started using Swift and basically I have a UILabel I use to display error messages. This label is intially hidden (through storyboard's hidden checkmark, I tried setting it to hidden in viewDidLoad also).
When a user clicks login an apicontroller class posts to a backend server to check credentials. The apicontroller has a delegate which is called in the completionHandler in (NSURLSession.dataTaskWithRequest). The protocol method in the viewcontroller checks to see the http status and if it's 200 it moves on to the next view. However, if it's not 200, the view controller unhides the error label
(self.errorLabel.hidden = false and self.erorLabel.text = "ERROR MESSAGE HERE").
Here is my issue:
When the erorrlabel is supposed to be unhidden, I set it's hidden property to false, println("should be unhidden now") and display an alert. The alert and print statement are executed instantly. However, the label takes a couple of seconds before it is displayed.
I've tried this on the 4s, 5, 5s and 6 in simulator and an actual 5s and I still get this issue. I've also tried manually refreshing the view with self.view.setNeedsDisplay() and it still doesn't work.
Any ideas?
You are probably updating the label in a thread which is not the main thread.
Enclose the code inside this block:
dispatch_async(dispatch_get_main_queue()) {
// Update the label here
}
Thanks to Antonio for reffering me to this question. It has indeed resolved my problem which I asked here: https://stackoverflow.com/questions/26800093/setting-iboutlet-in-closure-result-in-swift
This is the final block of code which worked for me:
homeModel.GetHomeData({(textResult:String!) in
dispatch_async(dispatch_get_main_queue())
{
// Update the textview in the ui here
self.homeTextView.text = textResult
}
});

Bizarre GameKit behavior. Anyone else seeing this?

I am running Xcode 4.3.3 and am targeting iOS 5.1. I am attempting to include Game Center functionality in a game.
When authenticating the GKLocalPlayer the user is presented with the Sign in to Game Center alert view or shown to be logged in. So far this is all fine, but if the user presses the Create New Account button then any open modal views are moved behind the root view controller and the following error is spit from the console:
Unbalanced calls to begin/end appearance transitions for
<GKModalRootViewController: memory address>.
I have tried moving the GKLocalPlayer authentication code between the app delegate and the root view controller. I have also tried implementing the authentication in a new, blank project. I have tried it with and without Storyboards and ARC. In all of these cases the results were the same: modals hidden behind the root view controller and error given.
Here is the GKLocalPlayer authentication method I am calling from my app delegate’s application:didFinishLaunchingWithOptions: method:
- (void)authenticateLocalPlayer
{
GKLocalPlayer *localPlayer = [GKLocalPlayer localPlayer];
[localPlayer authenticateWithCompletionHandler:^(NSError *error) {
if (localPlayer.isAuthenticated) {
// Perform additional tasks for the authenticated player.
} else {
// Disable Game Center features.
}
if (error) {
// Handle error.
}
}];
}
Here is a screenshot of it. In this picture the root view controller has a background with a 50% alpha value. The modal has been pushed behind the root view controller by this bug.
This stackoverflow question contains the only reference to this error (regarding GKModalRootViewController) I can find, and it doesn't fit since (a.) I’m not using cocos2d. (b.) It happens whether or not I perform a segue, and I am not touching viewWillAppear: or viewDidAppear:. (c.) No acceptable answer was given.
This question and this one seem to involve the same issue (with the view hierarchy being destroyed) but are unanswered and don’t mention the console error message.
Does this happen for anyone else? Any ideas on what could be causing this?
UPDATE 1: I went so far as to put the authentication code into an IBAction connected to a button in the modal view so as to avoid any initialization conflicts. It didn't help.
UPDATE 2: I tried moving the authentication code into a GCD background queue. he results were the same.
Here is the test project (which is GameCenter ready with my app's Bundle ID already entered).
To test:
Log out of Game Center on the test device/simulator (if you are
logged in).
Build and run the app.
Press the info button.
Press Authenticate.
When the Sign in to Game Center alert appears press Create New
Account.
Press Cancel.
Did the “Unbalanced calls...” message appear in the console? Did the
modal view (with the Authenticate button) disappear?
Press the info button.
Did the modal display again?
This bug appears on the list of "bugs Apple fixed in 6.0". I understand you would love a workaround, but when its the APIs you depend on that are buggy, chances of that are slim.
You can however rejoice that 5.x users are slowly dying out.
Best of luck with your app.

Multiple AVPlayers with AVPlayerLayers disappears second time push viewcontroller

I have a viewcontroller with four (4) AVPlayers (with AVPlayerLayers like APPLE example).
If I pop this viewcontroller and the push a new instance of the same type. I'm not able to play video in one or two AVPlayers. No errors and code runs fine, AVPlayerLayers also says it has a superLayer.
And to the most strange thing if I push home button, coming back to springboard and the enter the app all video players like magic start playing. It's like it rerender the view tree or something.
Any hints or clues?
PS. I wait for assets to be ready using loadValuesAsynchronouslyForKeys.
We had a similar problem. Following answer lead to the solution:
AVplayer not showing in ScrollView after 2-3 times
You have to call: [AVPlayer replaceCurrentItemWithPlayerItem:nil]; when your viewcontroller gets unloaded. This might be tricky as you might have added an observer or used addBoundaryTimeObserverForTimes:queue:usingBlock:
Also you have to be careful when checking agaings superlayer: Better check against uiview.window when determing whether your view is still attached to the view hierarchy.
yours
phil