3
\$\begingroup\$

There a various examples in UIKit where a class has a property and a corresponding method to set the property along with an animated property.

Examples include the progress and setProgress(_:animated:) of UIProgressView or the isEditing and setEditing(_:animated:) of UITableView.

In Objective-C you implement this by overriding the plain property setter to call the additional setter with the additional parameter:

- (void)setEditing:(BOOL)editing {
    [self setEditing:editing animated:NO];
}

- (void)setEditing:(BOOL)editing animated:(BOOL)animated {
    _editing = editing // set the instance variable

    // The rest of the code
}

The question is about doing this in Swift. The best I can come up requires using a private backing variable for the public computed property in addition to the corresponding animated setter.

private var _editing: Bool

public var isEditing: Bool {
    get { return _editing }
    set { setEditing(newValue, animated: false) }
}

public func setEditing(_ editing: Bool, animated: Bool) {
    _editing = editing

    // The rest of the code
}

Is there a better way to implement this pattern in Swift without the need to wrap a private property with a computed property à la Objective-C?

\$\endgroup\$
2
\$\begingroup\$

The alternative is:

public var isEditing: Bool {
    didSet {
        // do whatever you need when the property changes, e.g.
        updateView()
    }
}

// wrap the changing of `isEditing` in some animation

func setEditing(_ editing: Bool, animated: Bool) {
    if animated {
        someAnimation {
            isEditing = editing
        }
    } else {
        isEditing = editing
    }
}

This basically separates the “do what I need when isEditing changes” from the “by the way, animate that” and it eliminates a private backing stored property.

There are cases where you need to do the “exposed computed property with a private backing stored property” approach, but I generally avoid that pattern where I can.

\$\endgroup\$
  • \$\begingroup\$ This is a nice approach for simple view changes and simple animations. I have a case where I'm implementing a custom view wrapping a collection view. My little animatable property does some complicated updates to the collection view's layout, toggles some cell selections, adjusts the content offset, etc. The animated property is passed to many of the collection view methods at each step. I do not believe my specific use can be neatly adjusted to this suggested answer. \$\endgroup\$ – rmaddy May 21 at 19:58
  • \$\begingroup\$ If that’s what’s actually going on in your situation, then your approach is perfectly good, IMHO. The above is for those simpler scenarios. \$\endgroup\$ – Rob May 21 at 20:28

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.