-
Notifications
You must be signed in to change notification settings - Fork 1
Home
Beacon provides bindings specific for the binding target, for example for the text of a label or text field. The most important categories of such specialized bindings are view bindings. Binding extensions for existing views are integrated as text properties defined in categories (named AKAIBBindingProperties). You use them typically by setting these properties in the properties inspector of Xcode's interface builder.
Beacon also provides some binding types which are specific to the bound value, such as formatter-, font- or predicate bindings. These bindings are typically property bindings. Property bindings are primarily used by view bindings to customize the binding configuration or the binding target.
-
UIView
- styleBinding - customize background color (later other properties)
- gesturesBinding - create tap gesture recognizer
-
UILabel
- textBinding - bind a source value to a label's text, configure formatters, etc.
- fontBinding - dynamic type the easy way
- UIImageView
- UITableView
-
UIControl
- enabledBinding
- UITextField
- UITextView
- UIPickerView
- UISwitch
- UISlider
- UIStepper
- UISegmentedControl
All bindings use a DSL (domain specific language). This is the most ambivalent feature of Beacon, because it's a rather powerful mechanism but also rather difficult to use, because there is no auto completion in Xcode and binding expressions can become somewhat complex (f.e. the data source binding for table views).
Don't be scared however, for most use cases, binding expressions are not too bad. Here three example upfront:
person.name
This just references the value at the key path. You could have specified $data.person.name
too, which is the same thing if the current data context is the top level context or $root.person.name
to get a key path relative to the top level view model.
In addition to the source data, binding expressions can specify binding attributes to provide additional information or to customize the behavior of a binding. Attributes are nested binding expressions
Labels support formatters, here an example where a label uses a shared formatter that is provided by the view model:
account.balance { numberFormatter: $root.pathToSharedFormatters.currencyFormatter }
You can also create a custom formatter on the fly by just providing its configuration:
account.balance { numberFormatter: { numberStyle: $enum.CurrencyStyle } }
Binding expressions consist of a primary expression which defines the binding source (where the data is coming from) and attributes which provide additional information which is either required by the binding or which customizes the behavior of the binding. Both are optional, if neither is specified (empty binding expression) no binding will be created.
Here is a grammar fragment:
<bindingExpression> ::= <primaryExpression>? ( '{' <attributeList>? '}' )?
<attributeList> ::= <attribute> | <attributeList> ',' <attribute>
<attribute> ::= <identifier> | <identifier> ':' <bindingExpression>
As you can see, attribute values are also binding expressions, so they can have their own attributes.
For some primary types (enumerations, options and structures) the constant values are specified as parameters in the attribute part of the expression. For these types, attribute values can be specified in addition to parameters, for example: $CGPoint { x:0, y:0, someAttribute:"value" }
, where x
and y
are parameters for the CGPoint and "someAttribute" is an attribute.
There are two categories of primary expressions, constant expressions and key path expressions. Key path expressions need a binding context to provide their value (arrays may be constant or not, depending on their content).
Key path expressions use a slightly extended syntax, you can prefix them with "$data." or "$root.". $data is the current data context, "$root" is the top-level (form-) data context. See the section about "Data contexts". These are called scopes. If no scope is specified, $data is assumed (unless otherwise specified).
Beacon currently supports the following types
Beacon type | Examples | Objective-C type |
---|---|---|
KeyPath | name, model.value, $data.name, $root.top | id (any type) |
Boolean | $true, $false | NSNumber (BOOL) |
Integer | 123, -4 | NSNumber (long long) |
Double | .0, 1., .3e-5 | NSNumber (double) |
String | "a\nb\tc" | NSString |
Class | <NSNumberFormatter> | Class |
Enum | .Value, $Type.Value | id (any type) |
Options | {.Value1, .Value2} $Type{.Value} | NSNumber (long long) |
Array | [ v1{ A1:4 }, v2, $true, "Hey!" ] | NSArray |
CGPoint | $CGPoint { x:1, y:2 } | NSValue (CGPoint) |
CGSize | $CGSize { w:10, h:20 }, $CGSize{width:1,h2} | NSValue (CGSize) |
CGRect | $CGRect { x:1, y:2, w:3, h:4 } | NSValue (CGRect) |
CGColor | $CGColor { r:255, g:255, b:255, a:255 } | CGColor |
UIColor | $UIColor { r:255, g:255, b:255, a:255 } | UIColor |
UIFont | $UIFont { name:"Courier new", size:15.0 } | UIFont |
..
Please note that the old syntax for enumeration ($enum.Type.Value
) and options ($options.Type {Value}
) types is still working but will probably be removed in some future version.
Binding contexts are used to evaluate a key path to a concrete binding source value.
The Beacon binding behavior determines the root binding context used for top level view bindings. If you add the binding behavior like this:
- (void)viewDidLoad {
[super viewDidLoad];
[AKABindingBehavior addToViewController:self];
}
then the view controller serves as root data context (or in MVVM terms as view model) and if it implements the protocol AKABindingBehaviorDelegate also as binding delegate.
You can also specify a separate view model like this:
- (void)viewDidLoad {
[super viewDidLoad];
[AKABindingBehavior addToViewController:self
withDataContext:self.viewModel
delegate:self.bindingDelegate];
}
The binding delegate allows you to monitor control many aspect of the binding process and AKAControl instances involved in bindings. Please take a look at the corresponding delegate methods to learn about the details.
Some view types, such as UITableView provide a nested data context for bindings declared in cells. If a table view section is bound to an array, then cells in that section will use the corresponding array item as data context. Bindings can however still access the root data context using the "$root" prefix.