martijnwalraven / meteor-ios

Meteor iOS integrates native iOS apps with the Meteor platform (http://www.meteor.com) through DDP
MIT License
740 stars 79 forks source link

Meteor iOS

Meteor iOS integrates native iOS apps with the Meteor platform (http://www.meteor.com) through DDP. It offers full support for latency compensation and supports a Core Data programming model. It has been written in Objective-C, but is also perfectly usable from Swift.

If you're a Meteor web developer… it's now easy for a native iOS app to participate in Meteor's full stack reactivity.

If you're an iOS developer… Meteor is an amazing backend for your app that will save you tons of time.

Differences between Meteor iOS and other DDP clients

Meteor iOS is more than a barebones DDP client. Rather than notifying you of individual data updates and leaving it at that, it has been designed to bring full stack reativity to iOS. Currently, this is most easily done by integrating with Core Data. By only writing a few lines of code, we get reactive updates from the database to the UI.

Among other things, it includes full support for latency compensation and supports writing your own method stubs. It has been implemented with concurrent execution in mind and keeps all processing off the main thread, posting batched and consolidated change notifications that can be observed to update the UI.

It keeps as close as possible to the semantics of the original Meteor JavaScript code. Its behavior is covered by over 200 unit tests and it also has some server integration tests that run using a local Meteor test server.

Getting Started

For now, the included Todos example (written in Swift, for both iPhone and iPad) is probably the best way to get an understanding of what Meteor iOS is capable of. If you want to try it out, you should be able to open the Meteor workspace and run the Todos scheme. It connects to a Meteor example app running at http://meteor-ios-todos.meteor.com. If you want to get a quick idea of what it's capable of you may want to have a look at this short screen recording:

Meteor iOS — Todos example

Installation with CocoaPods

The easiest way to use Meteor iOS in your own project is through CocoaPods. Add pod 'Meteor' to your Podfile and run pod install to install the library.

To use CocoaPods with Swift, you'll have to install CocoaPods 0.36 or later and enable framework support in your Podfile:

platform :ios, '8.0'
use_frameworks!
pod 'Meteor' 

With this Podfile, Meteor iOS will be built as a framework and can easily be imported without further configuration (you may need to build the project first before the module is recognized however):

In Objective-C:

@import Meteor;

In Swift:

import Meteor

As an alternative, you should also be able to install the framework through Carthage. Add github "martijnwalraven/meteor-ios" to your Cartfile and run carthage update to build the framework. Then, drag the built .framework file to your application's Xcode project to use it.

Usage

I'm still figuring out usage patterns and I'm actively improving the API. I'm using Meteor iOS with Swift and Core Data in my own projects, so that's what I'll mostly be describing here. You can also use the API at a lower level and deal with documents directly though. See this wiki page for more information about the lower-level API and about using Meteor iOS without Core Data.

Don't expect anything to be stable yet, but please do let me know what you think of the API and what improvements you would like to see.

Basic usage is actually pretty simple:

Example code

The most convenient way to set up a METDDPClient or METCoreDataDDPClient in Swift is as a global variable (Swift uses dispatch_once under the hood for lazy and thread safe initialization):

let Meteor = METCoreDataDDPClient(serverURL: NSURL(string: "wss://meteor-ios-todos.meteor.com/websocket"))

@UIApplicationMain
class AppDelegate: UIApplicationDelegate {
  func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {  
    Meteor.connect()
  }
}

Waiting for subscriptions

The Todos example includes a SubscriptionLoader class that can be used used to wait for subscriptions to become ready (similar to the waitOn option in Iron Router). Using this in viewWillAppear makes it easy to avoid displaying partial data sets (and perhaps show a loading indicator, as in the Todos example). (Subscriptions are shared and reused, so there won't be any extra cost to calling viewWillAppear again, and if all subscriptions are loaded when it is called, whenReady will be synchronous.)

subscriptionLoader.addSubscriptionWithName("publicLists")
subscriptionLoader.addSubscriptionWithName("privateLists")
// Parameter 'list' is an NSManagedObject that will be automatically converted to a documentID
subscriptionLoader.addSubscriptionWithName("todos", parameters: list)

subscriptionLoader.whenReady {
  self.fetchedResultsController.performFetch()
}

Making changes

// The managedObjectContext is preferably set as a property on a UIViewController and passed on to the next one to support child contexts
let managedObjectContext = Meteor.mainQueueManagedObjectContext

let list = NSEntityDescription.insertNewObjectForEntityForName("List", inManagedObjectContext:managedObjectContext) as List
list.name = "Favorite Scientists"
let lovelace = NSEntityDescription.insertNewObjectForEntityForName("Todo", inManagedObjectContext:managedObjectContext) as Todo
lovelace.text = "Ada Lovelace"
lovelace.list = list
list.incompleteCount++

var error: NSError?
if !managedObjectContext.save(&error) {
  println("Encountered error saving objects: \(error)")
}

Features

Swift

Although the framework has been written in Objective-C, it works well with Swift. In fact, both the Todos example and a larger project I work on myself exclusively use Swift. In the future, I plan on updating the API to take better advantage of Swift language features. I'm also planning on including (and documenting!) some utility code written in Swift extracted from the Todos example and my own project code.

I had already started work on this project when Swift was announced. Although I'm impressed by Swift, I decided it was too soon to consider a rewrite. The language was and is evolving, and some potentially useful language features are still missing (in particular around generics and protocols). Performance can be unpredictable (especially when dealing with arrays and dictionaries) and tool support (Xcode) is not as stable as it is for Objective-C. Once the Swift language and implementation stabilize and language idioms become established, a complete or partial rewrite might be a viable option.

Some implementation details for the curious

Author

License

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

The Todos example contains icons provided by Icons8 under the Creative Commons Attribution-NoDerivs 3.0 Unported license.