1

I have a subclass of UITextView, which needs to have a specific default appearance. So far, I've been able to achieve this by overriding the initialize() class function, which has been deprecated in Swift 3.1.

public class CustomTextView : UITextView {
    override public class func initialize() {
        self.appearance().backgroundColor = .green
    }
}

Is there a way to achieve the same thing pure Swift?

Davor Bauk
  • 21
  • 4

1 Answers1

1

I'm working around the loss of the class method initialize by using a construct like this:

class CustomTextView : UITextView {
    override init(frame: CGRect, textContainer: NSTextContainer?) {
        super.init(frame:frame, textContainer: textContainer)
        CustomTextView.doInitialize
    }
    required init?(coder aDecoder: NSCoder) {
        super.init(coder:aDecoder)
        CustomTextView.doInitialize
    }
    static let doInitialize : Void = {
        CustomTextView.appearance().backgroundColor = .green
    }()
}

This construct has the advantage that doInitialize will be initialized only once, so the code connected with it will run only once (in this case we'll configure the appearance proxy only once); and it is early enough to affect even the first instance created (that is, every CustomTextView you ever make will in fact be green).

matt
  • 515,959
  • 87
  • 875
  • 1,141
  • Thanks. I tried doing something similar but I realized that it would require instantiating the class first. So, if you were to configure the custom appearance first, and instantiated the class at a later time, the default appearance would override the custom one. Eg.: – Davor Bauk Mar 31 '17 at 20:02
  • ` CustomTextView.appearance().backgroundColor = .orange; let t = CustomTextView()`. The background color of t would be .green instead of .orange. – Davor Bauk Mar 31 '17 at 20:11
  • 1
    @DavorBauk Then you asked the wrong question. You don't customize an _individual_ object by setting its `appearance` proxy. You customize an individual object by customizing that object. If that was really your goal, Leo Dabus' answer was right. – matt Mar 31 '17 at 20:37
  • Thanks for the feedback. You're right, my question wasn't about trying to modify an individual instance; that was really just a simple illustration. In my particular scenario, `CustomTextField` is defined in a shared framework, which is used by several apps. However, each app has a slightly different color palette, so I would want to further customize the appearance of `CustomTextField` in each individual app. For example, have a different default outline color in each app respectively, but keep the default font and background color as defined by `CustomTextView`. – Davor Bauk Mar 31 '17 at 21:15
  • Okay, but your question was not about that! Your question was about doing something that would behave like `initialize` and that's what my answer responded to. – matt Mar 31 '17 at 21:26
  • Again, thank you for the response. But your solution does not behave like `initialize()`. The documentation states: "The runtime sends initialize() to each class in a program just before the class, or any class that inherits from it, is sent its first message from within the program.". This means that any call to a class method is guaranteed to execute _after_ `initialize()`. Your solution suggests that a user should make sure to first create an instance of the class, discard that instance, and _then_ call the class function such as `appearance()`. – Davor Bauk Mar 31 '17 at 23:40
  • Well, if you _really_ want the exact timing of `initialize`, you need to override and implement `initialize` in Objective-C, as described here: http://stackoverflow.com/a/42824542/341994 – matt Apr 01 '17 at 01:21
  • Looks interesting. Working from their solution, I would make my text view class conform to a protocol (eg. `ClassInitializing`) which requires that the class implements `class func initializeClass()`, then on app launch list all classes and for each returned class call `(type as? ClassInitializing)?.initializeClass()`. Is there a way to just check whether a class implements `classInitializing()` and call it using objc runtime functions? – Davor Bauk Apr 03 '17 at 21:27