golddove golddove - 4 months ago 34
iOS Question

Use a generic class as a custom view in Interface Builder

I have a custom subclass of UIButton:

import UIKit

@IBDesignable
class MyButton: UIButton {

var array : [String]?

}


It is IBDesignable and I have set it as the custom class for one of the buttons in my storyboard. I would like to make it generic so that the array does not have to be one of String objects. So, I tried this:

import UIKit

@IBDesignable
class MyButton<T>: UIButton {

var array : [T]?

}


However, I am unsure how to set this as the class now in IB. I tried putting
MyButton<String>
or
MyButton<Int>
, but Interface Builder just removes the angle brackets portion and gets the following compile error:

Command /Applications/Xcode6-Beta4.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/swift failed with exit code 254


Is there a way to use a generic custom class, or is it not supported?

Answer

Interface Builder "talks" to your code through the ObjC runtime. As such, IB can can access only features of your code that are representable in the ObjC runtime. ObjC doesn't do generics, so there's not a way for IB to tell the runtime which specialization of your generic class to use. (And a Swift generic class can't be instantiated without a specialization, so you get an error trying to instantiate a MyButton instead of a MyButton<WhateverConcreteType>.)

(You can recognize the ObjC runtime at work in IB when you break other things: Attempting to use a pure Swift class with outlets/actions in a nib/storyboard gives runtime errors about ObjC introspection. Leaving an outlet connected whose corresponding code declaration has changed or gone away gives runtime errors about KVC. Et cetera.)

To ignore the runtime issues and put it in a slightly different way... let's go back to what IB needs to know. Remember that the nib loading system is what instantiates anything in a storyboard at runtime. So even if the parts of your class that take a generic type parameter aren't @IBInspectable, the nib still needs to know what specialization of your generic class to load. So, for IB to let you use generic classes for views, IB would have to have a place for you to identify which specialization of your class the nib should use. It doesn't — but that'd make a great feature request.

In the meantime, if it's still helpful for your MyButton class to involve some generic storage, perhaps you could look into having MyButton reference another class that includes generic storage. (It'd have to do so in such a way that the type of said storage isn't known at compile time, though — otherwise the type parameters of that other class would have to propagate back to MyButton.)