Here is an example of a property delegate I would want to express to get rid of the shortcomings and a lot of programmer mistakes in projects on apple platforms:
@propertyDelegate
struct DelayedImmutableView<View: UIView> {
private unowned let _controller: UIViewController
private var _value: View? = nil
init(controller: UIViewController) {
self._controller = controller
}
var value: View {
get {
guard _controller.isViewLoaded else {
fatalError("controller's view must be loaded before accessing the view")
}
guard let value = _value else {
fatalError("property accessed before being initialized")
}
return value
}
// Perform an initialization, trapping if the
// value is already initialized.
set {
if _value != nil {
fatalError("property initialized twice")
}
_value = newValue
}
}
}
Then I would write something a property like this:
@IBOutlet lazy var label: UILabel by DelayedImmutableView
It would translate into this:
lazy var $label = DelayedImmutableView<UILabel>(controller: self)
var label: UILabel {
get { return $label.value }
set { $label.value = newValue }
}
And can be safely used from here:
func viewDidLoad() {
super.viewDidLoad()
// No more optionals, no more silly mistakes updating a view
// before the controller was woken from `Nib` where you just lose
// that data.
self.label.text = "Swift is awesome"
}
If we could also get rid of lazy here and create multiple delegates that are also composable that would be amazing. We can potentially make @IBOutlet into a property delegate as well and move it from the language surface into UIKit. But then we definitely need a way to compose multiple delegates var label: UILabel by [IBOutlet, DelayedImmutableView].
Sad story that @IBOutlet requires the type to be optional otherwise we could already use the above delegate type.
class Controller: UIViewController {
private lazy var __label = DelayedImmutableView<UILabel>(controller: self)
@IBOutlet var label: UILabel { // error @IBOutlet property has non-optional type 'UILabel'
get { return __label.value }
set { __label.value = newValue }
}
}