Giter Site home page Giter Site logo

mutech / aka-ios-beacon Goto Github PK

View Code? Open in Web Editor NEW
14.0 14.0 1.0 6.05 MB

The missing binding framework for iOS

License: BSD 2-Clause "Simplified" License

Ruby 0.05% Objective-C 97.66% Shell 0.04% Swift 1.85% C 0.40%
data-binding databinding interface-builder ios mvvm mvvm-architecture mvvm-framework mvvm-pattern objective-c picker picker-keyboards swift

aka-ios-beacon's People

Contributors

mutech avatar readmecritic avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

Forkers

capnspellcheck

aka-ios-beacon's Issues

Cleanup UITableView data source binding updates/dispatch

  • Support section insertion/deletion/modification events instead of reloading the TV
  • Refactor array comparer and its use (efficiency, reliability)
  • Support change events for NSSet and NSArray (via KVO) in favor to ArrayComparer - where possible
  • Support a notion of NSArrayController (sorting/filtering support)
  • Support multi-section NSFetchedResultsController

Extract binding expression parser

Extract the binding expression parser and related classes to a separate target/project.

Rationale

Create an external tool that validates binding expressions at compile time (scan through XIB/Storyboard files, extract binding expressions, validate them and integrate the whole thing in Xcode.

Performance Tuning

Until now I did not yet encounter any noticeable performance problems due to bindings.

However, many implementations are far from optimal and performance issues will almost certainly pop up. For example:

  • Some complex bindings unnecessarily trigger events to often (f..e table view updates)
  • Every key path binding creates an instance of AKAProperty and with it a separate key value observation.
  • Collection bindings use array content comparison to identify changes. That's fine for small sets of information but does not scale well.
  • ... (many other things, leaving it at this for now)

Feature: Bindings for auto layout constraints

Rationale

Dynamic layout constraints are one of the last domains where you currently need you write quite a lot of code to change or update presentation aspects from view models (or controllers).

One of the main goals of Beacon is to support the notion of abstract (not presentation specific) view models, that correspond to a user interaction and not so much to a concrete UI design or layout.

Example

For example, a user interaction state could be "define filter criteria" that results in a possible change to properties searchPattern and searchPatternOptions. The editing state could be represented by a property isFilterEditorActive or an enumeration presentationMode having states like Default, FilterEditorActive, ....

The UI designer wants to represent that using a toolbar with a loupe icon that, when tapped, should present a search bar. This can be implemented using a set of constraints that hide the search bar while the the user is not editing the filter criteria.

Currently, the view model or controller would have to track the editing state and update the set of constraints to implement this functionality. In the future, this should be expressible in terms of constraint bindings.

Bindings (Brainstorming)

This part is not thought out, just dumping the idea:

Constraint Property Bindings

This is the easy part. Modifiable constraint properties could simply be updated using property bindings. The only catch here is that the binding would probably have to keep a strong reference to the constraint to ensure that if any party (including the binding itself) removes the constraint from its owner, it will not be released until the binding stops observing changes.

The following constraint properties are candidates for this binding types:

  • active (-Binding_aka)
  • priority (-Binding_aka)
  • constant (-Binding_aka)

UIView Constraint Collection Bindings

Such bindings would allow to:

  • replace all constraints of the target view
  • replace some of the target view's constraints
  • add a set of constraints to the target view

All of these actions would be active as long as a binding is observing changes and the original state would be restored thereafter.

Constraint collection bindings are defined for the view that owns the constraints (the root of a sub hierarchy that is directly affected by constraint (?)).

Constraints to be added could look like:

addConstraints [
"H:|-(margin)-[viewA]-(margin)-|" {
    metrics: { margin: 20.0 },
    views: { viewA: { tag: 4 { optional }, role: "label" } }
]

One of the big challenges is that new constraints have to reference views. This will be supported using a query specification expressed in terms of binding attributes such as:

viewA: {
    tag: 1, role: "label", type: <UILabel>, 
    searchOrder:  [.Siblings,  .SubViews, .SuperView, .SuperViews...],
}

Such a query would look for UILabels having a role "label" and otherwise a view tag 1 starting with siblings, then looking for matching sub view and finally testing the super view (transitively if .SuperViews is specified).

The role would be a textual tag provided as extension property to UIViews (currently a mostly obsolete property aka_controlTags and aka_controlRole is implemented which could be replaced).

Use case

In the example above, a constraint binding could be defined on the UISearchBar (or some layout container view):

{ addConstraints: $whenNot(isFilterEditorActive) [ "V:[self(0)]" ] }

A lot of this functionality is already implemented in the scope of view theming (see AKAEditorControl & friends). These would be made obsolete.

Feature: Conditional Bindings

Rationale

  • Simplify binding expressions already supporting conditionals (f.e. table view data source binding/cell mappings)
  • Make view models even more presentation independent (and thus more flexible and reusable).

Syntax

Introduce a new syntax for conditional bindings:

Example

$when(<TypeA>) 
    "CellForAs"
$when(<TypeB>)  
    <CustomUITableViewCellType> { cellIdentifier: "CellForB" }
$when("SELF someCondition:argument == YES" { argument: 1.2 })
    "CellForSomeConditionSatisfied"
$else
    "DefaultCell"

Currently, cell mappings look like this:

[ { predicate: <TypeA>,
    cellIdentifier: "CellForAs" },
  { predicate: <TypeB>,
    cellIdentifier: "CellForBs", type: <CustomUITableViewCellType> },
  { predicate: "SELF someCondition:argument == YES" { argument: 1.2 },
    cellIdentifier: "CellForSomeConditionSatisfied" },
  { cellIdentifier: "DefaultCell" }
]

Grammar

<conditional> ::= <whenClause> + <elseClause> ?
<whenClause> ::= ('$when' | '$whenNot') '(' <predicateBindingExpression> ')' <bindingExpression>
<elseClause> ::= '$else' <bindingExpression>

Optionally, the key words '$inspect' (or '$switch', '$case', ...) and '$end' could be added. $inspect could be used to change the data context for the when clause and $end would make it possible to nest conditionals (not sure if that should be supported though). Both could be optional.

<conditional> ::= <inspectClause> ? <whenClause> + <elseClause> ? '$end' ?
<whenClause> ::= '$when' '(' <predicateBindingExpression> ')' <bindingExpression>
<elseClause> ::= '$else' <bindingExpression>
<inspectClause> ::= '$inspect' '(' <keyPathBindingExpression> ')'

Semantics

Validation Rules

  • Conditional binding expressions can validly replace binding expressions of all other types as long as all of their result binding expressions are valid according to the surrounding binding type.

Observation

Conditional bindings observe changes that can lead to predicates changing the value (due to predicate configuration or data context changes).

They however only have to observe leading predicates up until the first one that evaluates to true. Succeeding predicates can be ignored unless the active (satisfied) predicate changes its value to false.

Resulting Binding Activation

When the conditional binding starts observing changes, it iterates over when clauses and evaluates their predicates until one is satisfied. The first predicate that is satisfied (by the data context) is selected and the result binding expression is used to create a binding.

If the data context used in when clauses changes or non constant predicates change (f.e. an NSPredicate parameter bound to a key path), the conditional binding re-evaluated invalidated predicates.

When relevant predicates change, a previously used result binding will stopObservingChanges (thus be released) and the new result binding will be created and startObservingChanges.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.