使用 getter/setter 代替 属性 使其不会出现在反射(镜像)中
Using getter/setter for property makes it not appear in reflection (mirror)
我一直在尝试为我的自定义组件实现主题逻辑。我将使用 ZFButton 作为示例。
当应用程序启动时,我实例化 ZFbutton 并设置我希望这个主题具有的任何特征:
let theme = ZFButton()
theme.backgroundColor = .red //UIButton property
theme.cornerRadius = 8 //ZFButton property
theme.borderColor = .green //ZFButton property
theme.borderWidth = 1 //ZFButton property
然后添加到主题数组中:
ZFButton.themes.append(theme)
驻留在 ZFButton 中如下:
public static var themes = [ZFButton]()
在我的 ZFButton 中,我有以下 属性,它允许我从 IB Attributes Inspector 中选择我想为特定 ZFButton 使用哪个主题
@IBInspectable public var theme: Int = 0 { didSet { self.setupTheme() } }
最后,设置主题 属性 后,将调用 setupTheme(),在其中我尝试将给定主题的所有属性的值集复制到 ZFButton 的这个特定实例。为此,我使用反射:
private func setupTheme() {
if ZFButton.themes.count > self.theme {
let theme = ZFButton.themes[self.theme]
let mirror = Mirror(reflecting: theme)
for child in mirror.children {
if let label = child.label,
label != "theme", //check to prevent recursive calls
self.responds(to: Selector(label)) {
self.setValue(child.value, forKey: label)
print("Property name:", child.label)
print("Property value:", child.value)
}
}
}
}
现在我有两个问题:
1 - 具有 setter/getter 的属性不会出现在反射中,例如:
@IBInspectable public var borderColor: UIColor {
set { layer.borderColor = newValue.cgColor }
get { return UIColor(cgColor: layer.borderColor!) }
}
而使用 didSet 的属性可以,例如:
@IBInspectable public var iconText: String = "" { didSet { self.setupIcon() } }
但是,我确实需要一个 getter 来 return layer
中的 borderColor
。
2 - 使用Mirror反射所有ZFButton属性时,除了(1)中描述的问题外,我也没有得到UIButton属性,有没有办法得到ZFButton的超类(UIButton)属性?
对于第一个问题,我最终使用了以下扩展,它确实看到了 getters/setters 与 Mirror 不同的属性:
extension NSObject {
func propertiesNames() -> [String] {
var count : UInt32 = 0
let classToInspect = type(of: self)
guard let properties : UnsafeMutablePointer <objc_property_t> = class_copyPropertyList(classToInspect, &count) else { return [] }
var propertyNames : [String] = []
let intCount = Int(count)
for i in 0..<intCount {
let property : objc_property_t = properties[i]
let propertyName = NSString(utf8String: property_getName(property))!
propertyNames.append(propertyName as String)
}
free(properties)
return propertyNames
}
}
至于第二期,我最终将每个 属性 从主题复制到按钮,因为它们总是相同的。目标是避免每次在 ZFButton 中实现新内容时都必须维护主题 class 来桥接值。
我一直在尝试为我的自定义组件实现主题逻辑。我将使用 ZFButton 作为示例。
当应用程序启动时,我实例化 ZFbutton 并设置我希望这个主题具有的任何特征:
let theme = ZFButton()
theme.backgroundColor = .red //UIButton property
theme.cornerRadius = 8 //ZFButton property
theme.borderColor = .green //ZFButton property
theme.borderWidth = 1 //ZFButton property
然后添加到主题数组中:
ZFButton.themes.append(theme)
驻留在 ZFButton 中如下:
public static var themes = [ZFButton]()
在我的 ZFButton 中,我有以下 属性,它允许我从 IB Attributes Inspector 中选择我想为特定 ZFButton 使用哪个主题
@IBInspectable public var theme: Int = 0 { didSet { self.setupTheme() } }
最后,设置主题 属性 后,将调用 setupTheme(),在其中我尝试将给定主题的所有属性的值集复制到 ZFButton 的这个特定实例。为此,我使用反射:
private func setupTheme() {
if ZFButton.themes.count > self.theme {
let theme = ZFButton.themes[self.theme]
let mirror = Mirror(reflecting: theme)
for child in mirror.children {
if let label = child.label,
label != "theme", //check to prevent recursive calls
self.responds(to: Selector(label)) {
self.setValue(child.value, forKey: label)
print("Property name:", child.label)
print("Property value:", child.value)
}
}
}
}
现在我有两个问题:
1 - 具有 setter/getter 的属性不会出现在反射中,例如:
@IBInspectable public var borderColor: UIColor {
set { layer.borderColor = newValue.cgColor }
get { return UIColor(cgColor: layer.borderColor!) }
}
而使用 didSet 的属性可以,例如:
@IBInspectable public var iconText: String = "" { didSet { self.setupIcon() } }
但是,我确实需要一个 getter 来 return layer
中的 borderColor
。
2 - 使用Mirror反射所有ZFButton属性时,除了(1)中描述的问题外,我也没有得到UIButton属性,有没有办法得到ZFButton的超类(UIButton)属性?
对于第一个问题,我最终使用了以下扩展,它确实看到了 getters/setters 与 Mirror 不同的属性:
extension NSObject {
func propertiesNames() -> [String] {
var count : UInt32 = 0
let classToInspect = type(of: self)
guard let properties : UnsafeMutablePointer <objc_property_t> = class_copyPropertyList(classToInspect, &count) else { return [] }
var propertyNames : [String] = []
let intCount = Int(count)
for i in 0..<intCount {
let property : objc_property_t = properties[i]
let propertyName = NSString(utf8String: property_getName(property))!
propertyNames.append(propertyName as String)
}
free(properties)
return propertyNames
}
}
至于第二期,我最终将每个 属性 从主题复制到按钮,因为它们总是相同的。目标是避免每次在 ZFButton 中实现新内容时都必须维护主题 class 来桥接值。