Latest 0.9
Homepage https://github.com/k-o-d-e-n/Realtime
License MIT
Platforms ios 9.0
Dependencies Firebase/Core, Firebase/Database, Firebase/Storage
Authors

CI Status
Version
License
Platform

Realtime is database framework based on Firebase that makes the creation of complex database structures is simple.
Realtime can help you to create app quicker than if use clear Firebase API herewith to apply complex structures to store data in Firebase database, to update UI using reactive behaviors.
Realtime provides lightweight data traffic, lazy initialization of data, good distribution of data.

Features

:point_right: Simple scalable model structure

point_right: Files

point_right: Collections

point_right: References

point_right: UI support

Usage

Initialization

In AppDelegate in func application(_:didFinishLaunchingWithOptions:) you must call code below, to configure working environment.
Now for cache policy is valid values case .noCache, .persistance only. Cache in memory is not implemented yet.

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
    /// ...

    /// initialize Realtime
    RealtimeApp.initialize(...)

    ///...
    return true
}

Model

To create any model data structure you can make by subclassing Object.
You can define child properties using classes:

  • Object subclasses;
  • ReadonlyProperty, Property, Reference, Relation, ReadonlyFile, File;
  • References, Values, AssociatedValues;
    If you use lazy properties, you need implement class function lazyPropertyKeyPath(for:). (Please tell me if you know how avoid it, without inheriting NSObject).
    This function called for each subclass, therefore you don’t need call super implementation.
    Example:

    
    class User: Object {
    lazy var name: Property<String> = "name".property(in: self)
    lazy var age: Property<Int> = "age".property(in: self)
    lazy var photo: File<UIImage?> = "photo".file(in: self, representer: .png)
    lazy var groups: References<RealtimeGroup> = "groups".references(in: self, elements: .groups)
    lazy var scheduledConversations: Values<Conversation> = "scheduledConversations".values(in: self)
    lazy var ownedGroup: Relation<RealtimeGroup?> = "ownedGroup".relation(in: self, "manager")
    
    override class func lazyPropertyKeyPath(for label: String) -> AnyKeyPath? {
        switch label {
        case "name": return User.name
        case "age": return User.age
        case "photo": return User.photo
        case "groups": return User.groups
        case "ownedGroup": return User.ownedGroup
        case "scheduledConversations": return User.scheduledConversations
        default: return nil
        }
    }
    }

let user = User(in: Node(key: "user_1"))
user.name <== "User name"
user.photo <== UIImage(named: "img")

let transaction = user.save(in: .root)
transaction.commit(with: { state, err in
/// process error
})


### Properties

***ReadonlyProperty*** - readonly stored property for any value.

***Property*** - stored property for any value.

***SharedProperty*** - stored property similar `Property`, but uses concurrency transaction to update value. Use this property if value assumes shared access (for example 'number of likes' value).

### References

***Reference*** - stores reference on any database value. Doesn't imply referential integrity. Use it if record won't be removed or else other reason that doesn't need referential integrity.

***Relation*** - stores reference on any database value. It creates link on side related object. On deletion related object will be deleted reference.

### Files

***ReadonlyFile*** - readonly stored property for file in Firebase Storage.

***File*** - stored property for file in Firebase Storage.

### Collections
```swift
class Some: Object {
    lazy var array: Values<Object> = "some_array".values(in: self)
    lazy var references: References<Object> = "some_linked_array".references(in: self, elements: .linkedObjects)
    lazy var dictionary: AssociatedValues<Object> = "some_dictionary".dictionary(in: self, keys: .keyObjects)
}

Some mutable operations of collections can require isSynced state. To achieve current state use func runObserving() function or set property keepSynced: Bool to true.

References is array that stores objects as references.
Source elements must locate in the same reference. On insertion of object to this array creates link on side object.

Values is array that stores objects by value in itself location.

References, Values mutating:

do {
    let transaction = Transaction()
    ...
    let element = Element()
    try array.write(element: element, in: transaction)
    try otherArray.remove(at: 1, in: trasaction)

    transaction.commit { (err) in
        // process error

        self.tableView.reloadData()
    }
} catch let e {
    // process error
}

AssociatedValues is dictionary where keys are references, but values are objects. On save value creates link on side key object.

AssociatedValues mutating:

do {
    let transaction = Transaction()
    ...
    let element = Element()
    try dictionary.write(element: element, key: key, in: transaction)
    try otherDictionary.remove(by: key, in: transaction)

    transaction.commit { (err) in
        // process error
    }
} catch let e {
    // process error
}

MapRealtimeCollection is immutable collection that gets elements from map function. This is the result of x.lazyMap(_ transform:) method, where x is any RealtimeCollection.

let userNames = Values<User>(in: usersNode).lazyMap { user in
    return user.name
}

Operators

  • <== – assignment operator. Can use to assign (or to retrieve) value to (from) any Realtime property.
  • ====, !=== – comparison operators. Can use to compare any Realtime properties where their values conform to Equatable protocol.
  • ?? – infix operator, that performs a nil-coalescing operation, returning the wrapped value of an Realtime property or a default value.
  • <- – prefix operator. Can use to convert instance of Closure, Assign types to explicit closure or backward.

Transactions

Transaction – object that contains all information about write transactions.
Almost all data changes perform using this object.
The most mutable operations just take transaction as parameter, but to create custom complex operations you can use this methods:

/// adds operation of save RealtimeValue as single value as is
func set<T: RealtimeValue & RealtimeValueEvents>(_ value: T, by node: Node)
/// adds operation of delete RealtimeValue
func delete<T: RealtimeValue & RealtimeValueEvents>(_ value: T)
/// adds operation of update RealtimeValue
func update<T: ChangeableRealtimeValue & RealtimeValueEvents & Reverting>(_ value: T)
/// method to merge actions of other transaction
func merge(_ other: Transaction)

For more details see Example project.

UI

SingleSectionTableViewDelegate – provides single section data source for UITableView with auto update.
SectionedTableViewDelegate – provides sectioned data source for UITableView with auto update.

Local listening

To receive changes on local level use objects that conform this protocol. It has similar RxSwift interface.

public protocol Listenable {
    associatedtype OutData

    /// Disposable listening of value
    func listening(_ assign: Assign<OutData>) -> Disposable

    /// Listening with possibility to control active state
    func listeningItem(_ assign: Assign<OutData>) -> ListeningItem
}

Debugging

Add debug argument ‘REALTIME_CRASH_ON_ERROR’ passed on launch, to catch internal errors.

Limitations

Realtime objects should not passed between threads.

Example

To run the example project, clone the repo, and run pod install from the Example directory first.

Requirements

Xcode 9+, Swift 4.1+.

Installation

Realtime is available through CocoaPods. To install
it, simply add the following line to your Podfile:

pod 'Realtime'

Author

Koryttsev Denis, [email protected]
Twitter: @K_o_D_e_N

License

Realtime is available under the MIT license. See the LICENSE file for more info.

Latest podspec

{
    "name": "Realtime",
    "version": "0.9",
    "summary": "Firebase Realtime Database framework.",
    "description": "Realtime is database framework based on Firebase that makes the creation of complex database structures is simple. :exclamation:nRealtime can help you to create app quicker than if use clear Firebase API herewith to apply complex structures to store data in Firebase database, to update UI using reactive behaviors.nRealtime provides lightweight data traffic, lazy initialization of data, good distribution of data",
    "homepage": "https://github.com/k-o-d-e-n/Realtime",
    "license": {
        "type": "MIT",
        "file": "LICENSE"
    },
    "authors": {
        "k-o-d-e-n": "[email protected]"
    },
    "source": {
        "git": "https://github.com/k-o-d-e-n/Realtime.git",
        "tag": "0.9"
    },
    "social_media_url": "https://twitter.com/K_o_D_e_N",
    "platforms": {
        "ios": "9.0"
    },
    "swift_version": "4.1",
    "pod_target_xcconfig": {
        "SWIFT_VERSION": "4.1"
    },
    "source_files": "Realtime/Classes/**/*",
    "static_framework": true,
    "dependencies": {
        "Firebase/Core": [],
        "Firebase/Database": [],
        "Firebase/Storage": []
    },
    "xcconfig": {
        "FRAMEWORK_SEARCH_PATHS": "'$(PODS_ROOT)'"
    }
}

Pin It on Pinterest

Share This