I have my own UI classes but want to hide inner implementation via private
access level. But I still need some properties for configuration like text
, placeholder
which will be just referencing the inner implementation. But in this case, I have to write a lot of duplicated code {set{...} get{...}}
which do the same things and if I'll have more such properties the number lines of code will grow fast.
class MyTextField: UIView {
@IBOutlet private var innerTextField: UItextField!
var placeholder: String? {
set {
innerTextField.placeholder = newValue
}
get {
return innerTextField.placeholder
}
}
var text: String? {
set {
innerTextField.text = newValue
}
get {
return innerTextField.text
}
}
}
So I've created a Reflection
property wrapper to reduce number of lines and code duplication(the same template).
@propertyWrapper
public struct Reflection<Value, Object: AnyObject> {
private let keyPath: ReferenceWritableKeyPath<Object, Value>
private var innerValue: Value
private weak var _sourceObject: Object? {
didSet {
_sourceObject?[keyPath: keyPath] = innerValue
}
}
public var sourceObject: Object? {
set {
if newValue == nil {
assertionFailure("`sourceObject` should be set up")
}
_sourceObject = newValue
}
get {
if _sourceObject == nil {
assertionFailure("`sourceObject` should be set up")
}
return _sourceObject
}
}
public init(
wrappedValue initialValue: Value,
keyPath: ReferenceWritableKeyPath<Object, Value>
) {
self.keyPath = keyPath
self.innerValue = initialValue
}
public var wrappedValue: Value {
get {
return sourceObject?[keyPath: keyPath] ?? innerValue
}
set {
innerValue = newValue
sourceObject?[keyPath: keyPath] = innerValue
}
}
}
So right now implementation looks like:
class MyTextField: UIView {
@IBOutlet private var innerTextField: UItextField!
@Reflection(keyPath: \UITextField.placeholder)
var placeholder: String? = nil
@Reflection(keyPath: \UITextField.text)
var text: String? = nil
init() {
_text.sourceObject = textField
_placeholder.sourceObject = textField
}
}
So my question is it possible somehow remove lines in init
method? Or may be general question does it really make sence to have such property wrappers? because probably doing _text.sourceObject = textField
is a quite big downside of this solution.