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
}
});
Related
I'm given an arbitrary NSAttributedString (parsed from markdown, not that it matters here) which may contain URLs that I want to be clickable in a text field within an NSTableView cell. The requirements state that if the user clicks the URL, they be taken to it with the default browser. IF they click anywhere else in the cell, we have default behavior (displaying an additional info popup).
I'm attempting to use a NSTextView to display the content. However, clicking outside the URL but within the view selects the text and eats the mouse click. Making the view not selectable won't allow clicking the URL either. I also don't really want the text to be selectable but that's a minor side problem.
So... I decided to make my view controller an NSTextViewDelegate so I could use some of those callbacks. But my app crashes if I set the NSTextView's delegate property to 'self'. This happens even if I don't implement any of the functions, even though they are all optional.
I'm using Swift 3 and wonder if there's some bug or other issue there? The call stack appears to be sending a textView:willChangeSelectionFromCharacterRanges:toCharacterRanges: message even though it's not implemented. And incidentally, implementing that method isn't helping either.
Any help, or sample code in Swift 3 using the delegate protocol, would be greatly appreciated.
Here's the crash I get by simply setting the delegate property on NSTextView:
By request, here's the code that set's the delegate. Currently I just set it whenever the message changes. This can obviously be optimized but for now I just want to see it work.
var notification: SSNotification! {
didSet {
guard let notificationCellView = self.view as? SSNotificationCellView else { return }
notificationCellView.subjectLabel.stringValue = notification.subject
if let description = notification.message , description != "" {
let attrString = TSMarkdownParser.standard().attributedString(fromMarkdown: description)
notificationCellView.messageLabel.textStorage?.setAttributedString(attrString)
notificationCellView.messageLabel.isHidden = false
notificationCellView.messageLabel.delegate = self
} else {
notificationCellView.messageLabel.isHidden = true
}
}
}
I never did figure out why I was crashing but I was able to come up with a workaround. I was originally trying to make the view controller for the table cell which contained NSTextView be the delegate. I changed it so that the cell's view subclass itself was the delegate and all is well.
I don't get it but it works, so that's what matters.
I'm having this weird situation over my app. I'm calling performSegueWithIdentifier over the main thread :
dispatch_async(dispatch_get_main_queue()){
self.performSegueWithIdentifier("toFrame", sender: nil)
}
I've set breakpoints thru the process, and even cleaned prepareForSegue.
Only for the first time when i'm calling this(to this specific VC),it's delayed for about 6 seconds, and than moving to the VC. After this delay, if i'm navigating back and forth, it runs smoothly
Any suggestions? Ive tried everything :\
It can be fonts issue: if you select them in IB and didn't check target membership - system will look for them before retrieving default font - and
thus will create delay before presenting controller.
Please check font's target membership.
It’s famous bug with modal presentation:
http://openradar.appspot.com/19563577
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).
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.
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.