0

I have a custom UItextView subclass where I override canBecomeFirstResponder():

class MyTextView: UITextView {

    /*
    // Only override drawRect: if you perform custom drawing.
    // An empty implementation adversely affects performance during animation.
    override func drawRect(rect: CGRect) {
        // Drawing code
    }
    */

    override func canBecomeFirstResponder() -> Bool {
        return false
    }

}

I'm doing this to allow the data detected links (phone numbers are URLs) in a UITextView to function without any of the other text in the view to be selectable, but that is unrelated to the question.

canBecomeFirstResponder() is the only property/method I want to override, so subclassing seems like overkill. I use this custom class with a view created with Interface Builder. Is there a way I can lazily override an IBOutlet's of a UIKit object's properties? Something like this:

@IBOutlet weak var contactTextView: UITextView! {
    override func canBecomeFirstResponder: Bool = {
        return false
    }
}

I do not want to use an extension on UITextView because I only want to override canBecomeFirstResponder() for a specific UITextView, not every one used in my project.

JAL
  • 41,701
  • 23
  • 172
  • 300
  • 1
    I can already achieve the expected behavior by subclassing, I'm looking for a better way. Hence this question. – JAL Jul 28 '15 at 20:11
  • If you return false for canBecomeFirstResponder you won't even be able to tap on your URLs anyway. – Nate Lee Jul 28 '15 at 20:27
  • @NateLee Not true, I tested this today and I can tap on the URLs without selecting the text in the `UITextView`, which is my desired behavior. The touch events on the links are higher in the `UIResponder` chain than the text selection. – JAL Jul 28 '15 at 20:28

2 Answers2

6

If you want to override, you have to subclass. These two concepts are connected. You cannot override without subclassing.

Your "like this" idea wouldn't work in any language. Basically, you are describing an anonymous subclass which is available in Java, for instance (not in Swift). However, that would have to be used during class instantiation, not when declaring a variable.

Of course, you could swizzle canBecomeFirstResponder with a method returning false in didSet but that's much more complicated than subclassing.

Sulthan
  • 128,090
  • 22
  • 218
  • 270
  • Thank you for your answer. So you're saying the best/simplest way to achieve my desired behavior is to subclass. There are no simpler alternatives. – JAL Jul 30 '15 at 20:02
  • @JAL I was trying to find a way to block selection and keep URLs to be clickable without overriding but overriding seems the only way to do it. And overriding = subclassing. – Sulthan Jul 30 '15 at 20:05
0

The answer is that with the current versions of swift, there is no way to do that.

Based on what you are describing, it might be possible that you could make your view controller implement UITextViewDelegate and implement textViewShouldBeginEditing to return false. This is just a guess based on the fact that you're seemingly trying to override canBecomeFirstResponder to disallow typing.

That all being said, as was pointed out if you return false from canBecomeFirstResponder I think the expected behavior is that the UI element will no longer allow itself to capture user input. From your responses in the comments, it seems that its capturing user input for you anyway, but that might just be a the particular version of iOS you're running. It could also be that my understanding of the first responder chain is incorrect.

Alpine
  • 1,347
  • 12
  • 13
  • I'm not trying to disallow typing. I'm trying to disallow text selection and the copy/define actions. I've tested the behavior on iOS 8 and 9, so I'm not sure if I'm missing something. – JAL Jul 30 '15 at 20:35