可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
enum
is not an Interface Builder defined runtime attribute.
The following does not show in Interface Builder's Attributes Inspector:
enum StatusShape:Int {
case Rectangle = 0
case Triangle = 1
case Circle = 2
}
@IBInspectable var shape:StatusShape = .Rectangle
From the documentation:
You can attach the IBInspectable attribute to any property in a class declaration, class extension, or category for any type that’s supported by the Interface Builder defined runtime attributes: boolean, integer or floating point number, string, localized string, rectangle, point, size, color, range, and nil.
Q: How can I see an enum
in Interface Builder's Attributes Inspector?
回答1:
Swift 3
@IBInspectable var shape:StatusShape = .Rectangle
merely creates a blank entry in Interface Builder:
Use an adapter, which will acts as a bridge between Swift and Interface Builder.
shapeAdapter
is inspectable from IB:
// IB: use the adapter
@IBInspectable var shapeAdapter:Int {
get {
return self.shape.rawValue
}
set( shapeIndex) {
self.shape = StatusShape(rawValue: shapeIndex) ?? .Rectangle
}
}
Unlike the conditional compilation approach (using #if TARGET_INTERFACE_BUILDER
), the type of the shape
variable does not change with the target, potentially requiring further source code changes to cope with the shape:NSInteger
vs. shape:StatusShape
variations:
// Programmatically: use the enum
var shape:StatusShape = .Rectangle
Complete code
@IBDesignable
class ViewController: UIViewController {
enum StatusShape:Int {
case Rectangle
case Triangle
case Circle
}
// Programmatically: use the enum
var shape:StatusShape = .Rectangle
// IB: use the adapter
@IBInspectable var shapeAdapter:Int {
get {
return self.shape.rawValue
}
set( shapeIndex) {
self.shape = StatusShape(rawValue: shapeIndex) ?? .Rectangle
}
}
}
► Find this solution on GitHub.
回答2:
Instead of setting your inspectable enums with ints, you could also set them with strings. Although not quite as preferable as a dropdown, at least this option offers some level of readability.
Swift-only Option:
// 1. Set up your enum
enum Shape: String {
case Rectangle = "rectangle" // lowercase to make it case-insensitive
case Triangle = "triangle"
case Circle = "circle"
}
// 2. Then set up a stored property, which will be for use in code
var shape = Shape.Rectangle // default shape
// 3. And another stored property which will only be accessible in IB (because the "unavailable" attribute prevents its use in code)
@available(*, unavailable, message: "This property is reserved for Interface Builder. Use 'shape' instead.")
@IBInspectable var shapeName: String? {
willSet {
// Ensure user enters a valid shape while making it lowercase.
// Ignore input if not valid.
if let newShape = Shape(rawValue: newValue?.lowercased() ?? "") {
shape = newShape
}
}
}
It is possible to also get this to work with objective-c as well, by adding an initializer to the enum. However, the compiler will only show the "unavailable" error for your IB-only properties in swift code.
Swift Option with Obj-C Compatibility:
@objc enum Shape: Int {
case None
case Rectangle
case Triangle
case Circle
init(named shapeName: String) {
switch shapeName.lowercased() {
case "rectangle": self = .Rectangle
case "triangle": self = .Triangle
case "circle": self = .Circle
default: self = .None
}
}
}
var shape = Shape.Rectangle // default shape
@available(*, unavailable, message: "This property is reserved for Interface Builder. Use 'shape' instead.")
@IBInspectable var shapeName: String? {
willSet {
if let newShape = Shape(rawValue: newValue?.lowercased() ?? "") {
shape = newShape
}
}
}
回答3:
I can't remember the swift syntax, but this is how I solved it in obj-c
#if TARGET_INTERFACE_BUILDER
@property (nonatomic) IBInspectable NSInteger shape;
#else
@property (nonatomic) StatusShape shape;
#endif
回答4:
This is an old thread but useful. I have adapted my answer to swift 4.0 and Xcode 9.0 - Swift 4 has its own little issues with this problem. I am having an @IBInspectable variable with enum type and Xcode 9.0 is not happy, showing me this "Property cannot be marked @IBInspectable because its type cannot be representing in Objective-c"
@Eporediese answers this problem (for swift3) in part; using a property for the storyboard but a straight enum for the rest of the code. Below is a more complete code set that gives you a property to work with in both cases.
enum StatusShape: Int {
case Rectangle = 0
case Triangle = 1
case Circle = 2
}
var _shape:StatusShape = .Rectangle // this is the backing variable
#if TARGET_INTERFACE_BUILDER
@IBInspectable var shape: Int { // using backing variable as a raw int
get { return _shape.rawValue }
set {
if _shape.rawValue != newValue {
_shape.rawValue = newValue
}
}
}
#else
var shape: StatusShape { // using backing variable as a typed enum
get { return _shape }
set {
if _shape != newValue {
_shape = newValue
}
}
}
#endif
回答5:
Swift 3
solution based on SwiftArchitect
enum StatusShape: Int {
case rectangle, triangle, circle
}
var statusShape: StatusShape = .rectangle
#if TARGET_INTERFACE_BUILDER
@IBInspectable var statusShapeIB: Int {
get {
return statusShape.rawValue
}
set {
guard let statusShape = StatusShape(rawValue: newValue) else { return }
self.statusShape = statusShape
}
} //convenience var, enum not inspectable
#endif