0

I am using a UITextView and have the UITextViewDelegate attached to the View Controller. When the user clicks on the TextView I have a "placeholder" label over the text view that I want to hide/un-hide depending on whether the user has any text in the text view. However, there seems to be an issue with executing UI operations in the UITextViewDelegate textViewDidBeginEditing and textViewDidEndEditing methods. In unit tests everything runs fine, but when running the app the UI doesn't update. I even tried wrapping the UI in a dispatch_async block to force the UI thread, but it seems slow and fickle (sometimes it works and sometimes it doesn't). Had anyone else seen this? Am I missing something that is blatantly right in front of me?

public func textViewDidBeginEditing(textView: UITextView) {
    switch(textView) {
    case self.descriptionTextView:
        self.activeTextView = self.descriptionTextView
        break
    case self.detailTextView:
        self.activeTextView = self.detailTextView
        dispatch_async(dispatch_get_main_queue(), { () -> Void in
            self.detailsRequiredButton!.hidden = true
        })

        break
    default:
        break
    }
}
JamWils
  • 785
  • 7
  • 17
  • check out this answer on how to make a placeholder text inside textView. http://stackoverflow.com/questions/27652227/text-view-placeholder-swift – rakeshbs Feb 02 '15 at 16:50
  • Actually that is the first approach that I had taken (or at least a derivative of it). The inconsistent calls I am getting during textFieldDidBeginEditing and textFieldDidEndEditing are giving me the same issue. So instead of hiding a button like I am on this one, the placeholder text wouldn't clear because the calls weren't being reflected on the UI properly. – JamWils Feb 02 '15 at 17:37

1 Answers1

0

Rather than using the delegate methods, I have had much better luck using the NSNotificationCenter notifications. I'm going to share obj-c code, but should work just fine in Swift as well.

I handled this with a separate UILabel called _placeholderLabel over the UITextView.

This is on a subclass of UITextView, but I don't see any reason why it wouldn't work to actually change the content/color of the UITextView as well. You would need to check for the range of the string in _placeholderLabel and would run into trouble if you didn't have more logic and someone actually typed that string in. There was additional code in the actual production code that isn't shown here, which is why textViewDidEndEditing: and textViewDidChange: look exactly the same.

- (void)addObservers 
{
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(textViewDidEndEditing:) name:UITextViewTextDidEndEditingNotification object:self];
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(textViewDidChange:) name:UITextViewTextDidChangeNotification object:self];
}

- (void) removeObservers
{
     [[NSNotificationCenter defaultCenter] removeObserver:self name:UITextViewTextDidEndEditingNotification object:self];
     [[NSNotificationCenter defaultCenter] removeObserver:self name:UITextViewTextDidChangeNotification object:self];
}

- (void) textViewDidEndEditing:(NSNotification *) notification
{
    if ([notification object] == self)
    {
        _placeHolderLabel.hidden = ([[self text] length] > 0);
    }
}

- (void) textViewDidChange:(NSNotification *) notification
{
    if ([notification object] == self)
    {
        _placeHolderLabel.hidden = ([[self text] length] > 0);
    }
}
dmorrow
  • 5,152
  • 5
  • 20
  • 31
  • Unfortunately, I am seeing the same behavior with the notification methods. Both the delegate and notification methods are getting called all the time yet the UI still isn't updating properly. This should be such a simple thing to implement. Looking at the debugger in Xcode it looks like the message is being sent on the Main Thread, so I am baffled. – JamWils Feb 04 '15 at 16:52