MarkupKit 4.2 Released

MarkupKit 4.2 is now available for download. This release adds support for formatting the result of binding expressions.

In MarkupKit, attributes whose values begin with “$” represent data bindings. The text following the “$” character represents an expression to which the corresponding view property will be bound. Any time the value of the bound expression changes, the target property in the view will be automatically updated. MarkupKit monitors property changes using key-value observing, and evaluates expressions using the Foundation framework’s NSExpression class.

For example, a view controller might define a bindable property called name as follows:

class ViewController: UIViewController {
    @objc dynamic var name: String?

    ...
}

The following markup establishes a binding between the text property of a UILabel instance and the controller’s name property. Any changes to name will be automatically reflected in the label:

<UILabel text="$name"/>

Binding Expressions

Binding expressions are not limited to simple properties, however. For example, a custom table view cell might use an instance of the following class as a model:

class Row: NSObject, Decodable {
    @objc var heading: String?
    @objc var detail: String?
}

class CustomCell: LMTableViewCell {
    @objc dynamic var row: Row!

    ...
}

This markup binds the text property of the heading and detail views to the row’s heading and detail properties, respectively. Any time the value of row changes, the labels will be updated:

<LMColumnView>
    <UILabel text="$row.heading"/>
    <UILabel text="$row.detail"/>
</LMColumnView>

Expression Formatters

Binding expressions are also not limited to string values. For example, they can refer to numeric or date properties, and can even contain mathematical operations. It is not possible to bind the result of such expressions to string-based target properties directly. However, formatters can be used to convert a bound value to an appropriate textual representation.

Formatters are applied by appending a format specifier to a binding declaration. A format specifier contains the name of the formatter to apply, along with any associated arguments to the formatter. The format specification is separated from the actual expression by a double-colon (“::”).

For example, the following markup uses a date formatter to convert a person’s date of birth (represented by an NSDate instance) to a short-format date string:

<UILabel text="$person.dateOfBirth::date;dateStyle=short;timeStyle=none"/>

This markup converts a double value to a string using a maximum of three decimal places:

<UILabel text="$averageAge::number;numberStyle=decimal;maximumFractionDigits=3"/>

Formatters are obtained via the following method, which MarkupKit adds to UIResponder:

- (NSFormatter *)formatterWithName:(NSString *)name arguments:(NSDictionary *)arguments;

This method is called on the document’s owner any time the value of a bound, formatted expression changes. The default implementation provides support for “date” and “number” formatters, which correspond to the NSDateFormatter and NSNumberFormatter Foundation classes, respectively. The arguments represent the properties that will be set on the formatter to configure its behavior. Owning classes can override this method to support custom formatters.

Summary

Binding expressions in MarkupKit allow developers to declaratively establish relationships between a model object and a target view, enabling a simple and intuitive reactive development model. For more information, see the project README.

Project Marzipan?

Rumors have been swirling recently about “Project Marzipan”, an as-yet unreleased Apple project some originally thought might allow iOS apps to run on macOS. I’ve been personally hoping for something along the lines of UXKit, a private framework Apple reportedly used to develop the current version of Photos for the Mac.

However, based on a recent post by Daring Fireball’s John Gruber, it seems as though “Project Marzipan” (which is apparently now being called something else) may actually be a “declarative control API”:

The general idea is that rather than writing classic procedural code to, say, make a button, then configure the button, then position the button inside a view, you instead declare the button and its attributes using some other form. HTML is probably the most easily understood example. In HTML you don’t procedurally create elements like paragraphs, images, and tables — you declare them with tags and attributes in markup.

This sounds a lot like MarkupKit. It will be very interesting to see how this turns out when (or if) it is ultimately announced, which could apparently happen as early as WWDC 2018 but more likely 2019.