Giter VIP home page Giter VIP logo

meteor-ios's Introduction

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:

  • Initialize a METCoreDataDDPClient with a WebSocket server URL and call its connect method. It is often convenient to set the client up as a singleton so you can access it from anywhere.
  • Call addSubscriptionWithName:parameters: at any time to invoke a publish function on the server and receive a specific set of documents. (If you use autopublish, the Meteor server will publish all of its collections automatically, without the need to subscribe. It has serious downsides, but can be great to get started during development.)
  • You'll need to set up a managed object model in Xcode, as you would normally do when using Core Data. Entities correspond to collections (with an automatic singular-plural name mapping a la Rails), and properties to fields. The default mapping will often work fine, but you can specify a different collectionName or fieldName as userInfo in the model editor. All types of relationships – one-to-one, one-to-many and many-to-many – are supported. By default, references are stored in documents on both sides (two-way referencing). But you can specify storage = false as userInfo for a relationship end in the model editor.
  • You can now use normal Core Data methods to access and modify documents. The client keeps a mainQueueManagedObjectContext and automatically merges changes, which is often what you need, but more complex setups (e.g. background contexts, child contexts) are also possible.
  • If you use NSFetchedResultsController, all changes that affect the specified fetch request will be propagated automatically, whether they were made from Core Data, directly to documents, or come from a different client and were sent by the server. You can use this to automatically update a UITableView or UICollectionView for instance (which gives you some nifty animations for free). You can of course also observe NSManagedObjectContextDidSaveNotification notifications yourself and decide what to do with changes as they happen.
  • Changes you make from your own code, either through Core Data or directly to documents, are immediately reflected in the local cache and a change notification is posted (so the UI can be updated). This is known as latency compensation because we don't have to wait for a server response. If a response from the server comes back later and it agrees with the changes, nothing more will happen. But if there are differences, the local cache will be ammended with the changes sent by the server and another change notification will be posted.
  • If you call a custom method on the server, you normally have to wait for possible server changes to come back. But you can define your own method stubs (defineStubForMethodWithName:usingBlock:) that can make local changes and thus participate in latency compensation.
  • If you log in a user (using loginWithEmail:password:completionHandler for example), publications on the server that depend on the userID will automatically run again and the server will send changes to the document set (if any). (The Todos example uses a privateLists publish function for instance, that automatically publishes lists owned by the currently logged in user.)

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

  • Full support for latency compensation, faithfully (I hope) reproducing the semantics of the original JavaScript code. Modifications to documents are reflected immediately in the local cache and will be ammended by server changes only when the server completes sending data updates for the method (multiple methods concurrently modifying the same documents are handled correctly).
  • Posting batched and consolidated change notifications at appropriate times, instead of relying on fine grained updates. This helps keep UI work on the main thread to a minimum without sacrificing responsiveness.
  • Core Data integration using an NSIncrementalStore subclass. Mapping between documents and NSManagedObjects is performed automatically (but can be customized). Different types of relationships are also supported, both for fetching and saving (with configurable storage). Modifications made to documents (possibly from other clients) will lead to the posting of an object change notification that is used to merge changes into NSManagedObjectContexts.
  • Subscriptions are shared and reused whenever possible. If a subscription is no longer in use, we don't actually unsubscribe until after a configurable timeout. This means data won't have to be removed and added if it is needed again later.
  • Correct handling of reconnection. Data updates on the new connection will be buffered until all subscriptions that were ready before have become ready again. Only then are updates applied and is a change notification posted (if anything actually changed).

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

  • Data updates from the server are buffered and applied in batches. Buffering uses a GCD dispatch source to coalesce events, meaning data updates that arrive before the buffer has had a chance to be flushed will be applied together.
  • Unless specified explicitly, document IDs are randomly generated on the client and a shared randomSeed is included with the method DDP message to keep generated IDs synchronized between client and server even in complex scenarios (such as method stubs recursively calling other stubs).
  • Data access and modification should be thread safe. The local cache supports concurrent reads and blocking writes. (Note that using Core Data will not allow you to take advantage of concurrent reads however, because NSPersistentStoreCoordinator serializes access.)
  • Calls to login methods act as a barrier so no other methods can execute concurrently. On reconnection, if logged in before, a login method with a resume token is sent before other in-progress methods. In the future, accounts should also survive app restarts and will be stored in the Keychain. Services like Facebook and Twitter should also be supported and preferrably integrate with iOS ACAccounts so users don't have to supply login credentials but only have to give permission to link the account.
  • When the connection to the server is lost (detected either through connection close, network error or failed DDP heartbeat), the client automatically atempts to reconnect. If the reconnect isn't succesful, it is tried repeatedly using an exponential backoff (with a randomization factor). The client also listens for network reachability changes and doesn't reconnect repeatedly when the network isn't reachable. It attempts to reconnect immediately when the network seems to have become reachable again.
  • When an app moves to the background, the connection isn't closed immediately but kept alive as long as possible (this is ultimately decided by the OS, but currently means 180 seconds). If the connection is lost while in the background, no attempts to reconnect are made. Moving the app to the foreground however, always immediately attempts to reconnect.
  • Currently, all Core Data relationships are expected to be defined on both sides, and documents on both sides should contain relationship details and be kept in sync. Using Core Data to save objects will take care of this automatically. If you change one side of a many-to-many relationship for instance, changes will also be made to all other documents participating in the relationship. This probably has to be revisited based on practical usage scenarios, but seems to work well as a default at the moment.
  • The way Core Data fetching has been implemented is fairly naive and although usable seems really inefficient. All documents in a given collection are instantiated as NSManagedObjects before a predicate and sortDescriptors are applied. At least some of this work should be offloaded to the local cache, so we only have to perform further processing on a subset of objects. This isn't easy however, if we want to support predicates referring to relationships at the model level.

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.

meteor-ios's People

Contributors

gibex avatar justinmakaila avatar martijnwalraven avatar yesitsdave avatar

Stargazers

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

Watchers

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

meteor-ios's Issues

Server configuration to set up websocket

I'm curious - how did you open the websocket for the ios app? I can't find any documentation on it anywhere in your readme :( How do I configure my server and get the appropriate URL for my mobile-app

Info: Bug in Cordova affects transfer of information from native side to Meteor

@martijnwalraven: I just wanted to inform you and the Meteor iOS users that I recently found a bug in Apache Cordova (not Meteor iOS) that also affects the transfer of information from the native side to Meteor:

https://issues.apache.org/jira/browse/CB-9485

This bug occurs at a central point, where information is sent back from the native side using the handleOpenURL method. Due to a strange behaviour of Apple's NSURL implementation, the URL used to encode the data is being truncated with an ellipsis (...). The Cordova team is not to blame here, I would never have expected Apple's framework to do such weird things...

JesseMacFayden from the Cordova team has now fixed this problem, but as far as I can tell from the Apache JIRA, the fix is planned to be included in the 4.0 version of Cordova. For the meantime, it could be an idea to apply the patch to Meteor's Cordova version manually, as it is just a one-liner.

I am not sure how severe this is for common Meteor iOS usage, but for me, it was a deal breaker, since the information I wanted to deliver to the Meteor side was too long and had been truncated because of this.

No user data

When subscribing to users collection i receive no data for users.

I'm using FetchedResultsTableViewController class from the example.
Configuring subscription loader with:

override func configureSubscriptionLoader(subscriptionLoader: SubscriptionLoader) {
    subscriptionLoader.addSubscriptionWithName("users")
}

On the server side i publish users data with:

Meteor.publish("users", function(){
  return Meteor.users.find({}, {fields: {emails: 1, profile: 1}});
});

But when i log data received on client i get:

<Circuit.User: 0x7f9216050650> (entity: User; id: 0x7f9213c21750 <x-coredata://21A947C1-FE9A-4828-A450-031F2E7249F0-80740-00009D910A641498/User/pjk5LMRygJSwCuBKzn> ; data: {
    createdAt = nil;
    emailAddresses = nil;
    items = nil;
    name = nil;
    profile = nil;
    services = nil;
})
<Circuit.User: 0x7f92160482d0> (entity: User; id: 0x7f9213c88f50 <x-coredata://21A947C1-FE9A-4828-A450-031F2E7249F0-80740-00009D910A641498/User/pP3dxmjoXD5mTedfXa> ; data: {
    createdAt = nil;
    emailAddresses = nil;
    items = nil;
    name = nil;
    profile = nil;
    services = nil;
})

This is my user class:

import CoreData

class User: NSManagedObject {
    typealias NamedValues = [String:AnyObject]

    @NSManaged var createdAt: NSDate?
    @NSManaged var name: String?
    @NSManaged var items: NSSet!

    @NSManaged var emailAddresses: [NamedValues]?
    var emailAddress: String? {
        return emailAddresses?.first?["address"] as? String
    }

    @NSManaged var profile: NamedValues?
    @NSManaged var services: NamedValues?
}

I get similar results with currentUser function from FetchedResultsTableViewController

Thanks

Paginated Subscriptions?

How can I use pagination with lots of records? I did try to implement it my self by modifying the todos example and connecting it up to a very basic meteor application which simply publishes a list of meteor users.

The problem is:
I use
override func configureSubscriptionLoader(subscriptionLoader: SubscriptionLoader) {
subscriptionLoader.addSubscriptionWithName("something", parameters: skip, limit)
}

In my load more function I use something like this:
skip=self.tableView.numberOfRowsInSection(0)
self.loadContent()

I did play around with adding it like this aswell

override func configureSubscriptionLoader(subscriptionLoader: SubscriptionLoader) {
skip=self.tableView.numberOfRowsInSection(0)
subscriptionLoader.addSubscriptionWithName("something", parameteres: skip, limit)
}

Everything seems to work fine records are pagination but as soon as I add a new record on the server side it basically reloads everything in the table and because skip is using self.tableView.numberOfRowsInSection(0) it removes everything else from the tableview and just shows everything what was added last.

Is there anyway I can add pagination support / fix this issue?

Corrupt user object after logging in and out (using Core Data)

When I was developing an application using your library, I stumbled upon a problem where the object representing the current logged in user became corrupt. I noticed that after logging out and then logging in again, the relations to the currently logged in user suddenly disappeared.

When I was trying to solve the problem I saw that it also appeared in your todos example project. Here is a reproduction of the problem using your own todos app:

  1. Go to meteor-ios-todos.meteor.com and make sure you have an account on the website
  2. Run the todos example project in the iOS simulator and do the following steps inside the running iOS app
  3. Log in to your account
  4. Create a new list and open it
  5. Mark your list as private
  6. Add one or more todo items
  7. Go back to the overview and log out
  8. Log in again to the same account
  9. Open your newly created private list
  10. Notice that your todo item(s) from step 6 are gone

Can you help me solve this problem?

Saves to server but not core data

Hey again, when I try to save some data, it crashes at runtime on the second line below (let round = ...) , with no real messaging on what is wrong:

        let managedObjectContext = Meteor.mainQueueManagedObjectContext        
        let round = NSEntityDescription.insertNewObjectForEntityForName("Round", inManagedObjectContext:managedObjectContext) as Round
        round.courseId = "1"

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

If I try instead to save via the following, it saves to the server, but not to core data:

        let managedObjectContext = Meteor.mainQueueManagedObjectContext
        let fetchRequest = NSFetchRequest(entityName: "Round")

        var error: NSError?
        let fetchedResults = managedObjectContext.executeFetchRequest(fetchRequest, error: &error) as [NSManagedObject]?

        if let results = fetchedResults {
            results[0].setValue("Red", forKeyPath: "tees")

            var error: NSError?
            if !managedObjectContext.save(&error) {
                println("Could not save \(error), \(error?.userInfo)")
            }

        } else {
            println("Could not fetch \(error), \(error!.userInfo)")
        }

Relations are not working

So far everything is working accept for relations. Relations are always nil for. Should I use a special package on meteor server for relations to work?

How do documents get stored in Xcode?

Hello,

I successfully integrated the package and was able to login and call methods on the server with Meteor.loginWithEmail and Meteor.callMethodWithName

But now I am wondering about the integration with Core Data, how to get and display documents

I know you can subscribe to a publication with the code:

Meteor.addSubscriptionWithName("notes")

Typically when you subscribe to a publication in the browser, the server sends you all the documents which is stored in Minimongo.

Since we have no Minimongo here, where are the documents stored once you subscribe, and how do you retrieve them?

How to search and retrieve documents we subscribe too?

Thanks!

Is it possible to use localhost ip when creating DDP

Hello

I can't get a connection between a local ip and my app running in simulator or device..
And the Meteor part of the project is running on different computer with that local IP.

I make my Meteor like this

    let Meteor = METCoreDataDDPClient(serverURL: NSURL(string: "wss://192.168.100.68:3000/websocket")!)

I dont get any error or anything when I try to call loginWithEmail

     Meteor.loginWithEmail("admin", password: "admin", completionHandler: { (NSError) -> Void in
            if(NSError != nil){
                println(NSError)
            }else{
                println(Meteor.userID)
                println("logged in")
                self.dismissViewControllerAnimated(true, completion: nil)
            }})

But it dont print out any error or print out my Meteor.userID and logged in..

Object not being sent to server

Hi,

I am trying to create a test object locally in swift and send it to my Meteor server, whilst i am getting no errors i'm also not seeing the object appear on the server.

I am setting meteor-ios up as follows:

let Meteor = METCoreDataDDPClient(serverURL: NSURL(string: "wss://localhost/websocket"))
    func startMeteor () {
        Meteor.connect()
        let subscriptionLoader = SubscriptionLoader()
        subscriptionLoader.addSubscriptionWithName("Tasks")

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

        NSNotificationCenter.defaultCenter().addObserver(self, selector: "objectsDidChange:", name: NSManagedObjectContextObjectsDidChangeNotification, object: managedObjectContext)
    }

To which i get a successful connected message, i am then trying to create an object using the following, for which i get a successful notification from core data, but nothing appear in Mongo/Meteor, i'm obviously missing something here so help greatly appreciated!

    @IBAction func createTask(sender: UIButton) {
        let managedObjectContext = Meteor.mainQueueManagedObjectContext

        let task = NSEntityDescription.insertNewObjectForEntityForName("Tasks", inManagedObjectContext:managedObjectContext) as Tasks
        task.text = "Test Text"

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

    }

Thanks

Gareth

Can I use SQLite as the database with Core Data?

I am working with a developer who has never used Meteor before and he is creating the iOS app. He says he has a lot of experience with SQLite.

Does this package work with SQLite? Any consideration or things to change from the normal if using SQLite?

Getting the current user object

I am struggling to work out how to create a UI to edit the current user's profile. If I create a string attribute for the User entity, it gets populated by the right json data. I am trying to write a custom method to request the actual managed objects, but it isn't clear how to bridge the gap between core data relationships and meteor _ids. Ideally I wouldn't have to think about ids at all.

One work around (and I've done this in the past) would be to create a new Profile collection, and store all profile info in there, and then the relationships would be set up like others, but I still think there will be times when I will want to query the DB based on a list of meteor _ids.

One possible solution would be to always store meteorId in each object so that they can be queried.

Am I missing something?

CD error: Property 'incompleteCount' is a scalar type...does not match its Entity's property's scalar type.

I get this error when I run the project (xcworkspace), from what I can understand it is something wrong with the CD model?

2015-06-19 14:22:56.660 Todos[532:117700] CoreData: error: Property 'incompleteCount' is a scalar type on class 'Todos.List' that does not match its Entity's property's scalar type.  Dynamically generated accessors do not support implicit type coercion.  Cannot generate a getter method for it.
2015-06-19 14:22:56.661 Todos[532:117700] -[Todos.List incompleteCount]: unrecognized selector sent to instance 0x14653f70
2015-06-19 14:22:56.662 Todos[532:117700] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[Todos.List incompleteCount]: unrecognized selector sent to instance 0x14653f70'
*** First throw call stack:
(0x25aa6fef 0x33d58c8b 0x25aac409 0x25aaa327 0x259d9e78 0xf95d4 0xf9a8c 0xf564c 0xf7d50 0xf56fc 0xf7e30 0xf5784 0xf7e68 0xf558c 0xf53f0 0xf4010 0xf412c 0x293cc36b 0x293cc42f 0x293c1013 0x291c28c5 0x291c27bb 0xd05fc 0xcddec 0xce000 0xd32a8 0xff720 0x768173 0x76815f 0x76be45 0x25a6c609 0x25a6ad09 0x259b7201 0x259b7013 0x2d296201 0x2915ba59 0xe2cb0 0x342e4aaf)
libc++abi.dylib: terminating with uncaught exception of type NSException
(lldb) 

InflectorKit.framework not found

After installing meteor-ios with Carthage and running my app, I get this runtime error:

dyld: Library not loaded: @rpath/InflectorKit.framework/InflectorKit
Referenced from: [...].app/Frameworks/Meteor.framework/Meteor
Reason: image not found

I assume it's referring to a dependency to https://github.com/mattt/InflectorKit

Todos scheme crashes

I'm not able to run the todos scheme:

CoreData: error: Property 'incompleteCount' is a scalar type on class 'Todos.List' that does not match its Entity's property's scalar type. Dynamically generated accessors do not support implicit type coercion. Cannot generate a getter method for it.
2015-06-01 16:15:07.462 Todos[10611:799384] -[Todos.List incompleteCount]: unrecognized selector sent to instance 0x7a1754d0
2015-06-01 16:15:07.468 Todos[10611:799384] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[Todos.List incompleteCount]: unrecognized selector sent to instance 0x7a1754d0'

Need access to METAccount.h -> resumeToken

Hi Martin,

I lost a couple of hours yesterday because I didn't realize METAccount.h was a private file. I thought my Swift bridging header was acting weird for some reason.

I need access to the resumeToken, so I can use it as a key in a HTTP cookie. Is there a particular reason the file is private? Can you make it possible to access the resumeToken, like you've done for the userID?

Thanks,

Jeff

Per method invocation stub definition

Often it helps to define a programmatic method API for each meteor method defined by the server. However in practice it seems that having the stub be defined in a lexically separate scope from the exposed API itself makes me feel a little scatterbrained. Here's an example

    init(meteor: METCoreDataDDPClient) {
        self.meteor = meteor
        meteor.defineStubForMethodWithName("makeSelection", usingBlock: { (args) -> AnyObject! in
            assert(NSThread.isMainThread(), "Only main supported for now")
            for (selection, documentId) in (args.first as [String: String]) {
                if let entity = Entity.findByDocumentID(candidateId) {
                    entity.delete()
                }
            }
            return true
        })
        // Multiply the above by # of methods defined
    }

    // many lines later
    // ....

    func makeSelection(entity1: Entity, entity2: Entity) {
         meteor.callMethod("makeSelection", params: [[
            "yes": entity1.documentID!,
            "no": entity1.documentID!
        ]])
    }

I'd love to do something like the following

    func makeSelection(entity1: Entity, entity2: Entity) {
         meteor.callMethod("makeSelection", params: [[
            "yes": entity1.documentID!,
            "no": entity2.documentID!
        ]], withStub: {
            entity1.delete()
            entity2.delete()
        })
    }

I think this involves storing a stub object on the MethodInvocation itself and invoke that if defined instead of the default stub. I'm happy to make the pull request for this, but just want to start a discussion and get some feedback.

`carthage update` does not build framework

Output:

*** Cloning meteor-ios
*** Checking out meteor-ios at "0.1.2"
*** xcodebuild output can be found in /var/folders/pj/0_h5pbg1787dcz5j24_rs36m0000gn/T/carthage-xcodebuild.JQWjmo.log
Project "Pods.xcodeproj" has no shared schemes

Link to web app in README

As a user, it would be significantly easier to reason about how the library works with a link to the Todos and Leaderboard web apps.

Booleans mapped to numbers on backend

I have a model:

class Update: MeteorCoreDataDocument {
    @NSManaged var createdAt: NSDate
    @NSManaged var endedAt: NSDate?
    @NSManaged var createdBy: String
    @NSManaged var isAvailable: Bool
    @NSManaged var update: Update?

    var isLive: Bool {
        return endedAt == nil
    }
}

When I create an instance of this model on the backend, it's done like so:

let newUpdate = NSEntityDescription.insertNewObjectForEntityForName("Update", inManagedObjectContext: managedObjectContext) as! Update
newUpdate.createdBy = Meteor.userID!
newUpdate.createdAt = NSDate()
newUpdate.isAvailable = true

saveManagedObjectContext()

In my test web app, I retrieve updates with this query:

Updates.find({
  createdBy: { $in: friends },
  isAvailable: true,
  update: null
}, { sort: { createdAt: -1 } }).fetch()

No updates will come back, because isAvailable is mapped to a 1 or 0, and is not picked up to be truthy or falsey by the mongo query.

Is there anyway to map this to a raw boolean value?

great

wow, this is really impressive! the meteor community is just amazing.
thanks!

Detecting currentUser

Hey again, the app I'm developing requires intermittent usage--a common use-case is for the user to unlock their phone, enter some data, then lock their phone again for 5-15 minutes before unlocking the phone again and entering more data, and so-on and on. The first problem is the connection to the server doesn't persist for too long (you mention as much in your 'implementation details' section). So each time the user unlocks the phone, the app resets to the startup screen. This has caused me to develop a 'recovery' solution where on the startup screen I want to detect if a task wasn't completed, and send the user directly back to the proper screen.

The second problem I'm now encountering with this solution is that I want to perform a fetch request as soon as possible after loading the startup screen to check for the user's incomplete tasks and send them on their way, but when I check for the currentUser in viewDidLoad, it returns nil. If I check currentUser again at viewWillDissapear, I do get the user object, so it is working. What I'm looking for is a callback (delegate?) that I can use to execute code the second the currentUser object is found. I'm using most of the swift code from your demo app for the FetchedResultsDataSource and FetchedResultsTableViewController (but not FetchedResultsTableViewDataSource as I'm not loading the data into a table). I'm checking the following in FetchedResultsTableViewController:

var currentUser: User? {
    if let userID = Meteor.userID {
        let userObjectID = Meteor.objectIDForDocumentKey(METDocumentKey(collectionName: "users", documentID: userID))
        return managedObjectContext.existingObjectWithID(userObjectID, error: nil) as? User
    }
    return nil;
}

I guess I have 2 questions.
1: I thought of the recovery solution which will work ok, and I'll likely need the feature anyway so I'm going ahead with it now, but is there a better solution to this problem that you know of?
2: How do you recommend executing code on app startup as soon as the user is detected?

Thanks in advance for your help

meteor _id and ios entity attributes

Hey,

First off, awesome work! This is a huge help in my project.

I'm trying to fetch a record using the meteor auto-generated '_id', but I can't add the same attribute to the corresponding Core Data entity because it won't allow me to start an attribute with anything other than a letter. Is there a graceful solution to this?

Problem with Boolean collection2/simple-schema

Hi There

I have problems updating Boolean values with meteor-ios. I tried to set the CoreData datatype to Boolean and the simple-schema datatype to Boolean as well. It syncs well from Meteor to iOS but when I try to sync a change to the boolean value through save from iOS to Meteor, the update fails without any error.

Bests

Pascal

Server side code for meteor-ios-todos example

Can you upload js, html and css for your version of the todos example?
I am a beginner trying to implement meteor-ios with CoreData in one of my existing apps.
I need to set up the server environment and mongo db as per my iOS app.
It would be really great if i could run your version of todos code locally and compare the database to my code data model.

Allow Deny required for security

When not using custom method calls, does Meteor iOS rely on the developer using Meteor's Allow Deny functions for secure insert, update, and remove functions when using Meteor iOS with CoreData? I intend to have a web client too, but hoped to avoid the security issues with allow-deny by just using custom methods.

Support for Numtel subscription payloads

Hi Martijn,
I've been using your DDP Client for the past week and it's just awesome - thanks for putting it out.
I'm currently using it in a project that requires a MySQL database in the back-end, so I've opted to use the popular Numtel package:
https://github.com/numtel/meteor-mysql

This sends some additional JSON through prior (as well as in) subscription payloads. While this isn't an issue with the Client more than it is with the way the Numtel package sends subscription data, I am curious if you or someone else has used the DDP client without having to write a custom JSON serialiser to support this?

Cheers -

Call method on server and get result back

Hello

I got a method on server, that gives a result back. And over in my swift project I want to call the method on the server and get the result back from the server, so I can use it in my swift project.

How do I best do this?

React Native Bridge?

Any plans on having a react native bridge so people can write IOS apps with all the JS goodness.

error: ~/Library/Developer/Xcode/DerivedData/~/Meteor.framework: No such file or directory

Hi Martijn,

I've tried building your ToDos examples with pod install (version 0.37.2) and Swift 1.2, Xcode 6.3.2. Encountered a no Meteor.framework error at the end of the build:

error: ~/Library/Developer/Xcode/DerivedData/Todos-bqmmymcvbhbifwbvbuwfcutrazyh/Build/Products/Debug-iphonesimulator/Meteor.framework: No such file or directory

Tried checking the same directory and only see these files listed:

Pods Pods.framework Pods.framework.dSYM Todos.app Todos.app.dSYM Todos.swiftmodule

Any suggestions?

Application crashes when running on iPhone

App crashes when running on iPhone with the message:

dyld: Library not loaded: @rpath/InflectorKit.framework/InflectorKit
  Referenced from: /private/var/mobile/Containers/Bundle/Application/*****
  Reason: no suitable image found.  Did find:
    /private/var/mobile/Containers/Bundle/Application/*****/Frameworks/InflectorKit.framework/InflectorKit: mach-o, but wrong architecture
    /private/var/mobile/Containers/Bundle/Application/*****/Frameworks/InflectorKit.framework/InflectorKit: mach-o, but wrong architecture
    /private/var/mobile/Containers/Bundle/Application/*****/Frameworks/InflectorKit.framework/InflectorKit: mach-o, but wrong architecture

Works fine on iPad. Both devices are running iOS 8.4. I installed meteor through cocoapods. Running the latest version of cocoapods, 0.38.2, and did both pod installand pod update.

How to map embedded data from Meteor responce?

Hello

Could someone please tell me how should be CoreData model designed to work correctly with the following Meteor responses:

{
    collection = users;
    fields =     {
        profile =         {
            accountType = student;
            birthday = "<null>";
            firstName = YuryTestStudent3;
            fullName = YuryTestStudent3;
            lastName = "";
            level = 1;
            parentId = R72enQ6CMus7w95gn;
            teacherId = ggGggDkQvQYFqzojT;
        };
        username = "@child_R72enQ6CMus7w95gn_06327e8c-1def-4e0c-ba1e-019666ff969f";
    };
    id = MMn5PeQiTyoPgM7KF;
    msg = added;
}

As you can see some data is not directly inside fields but is in profile. How this response should be mapped? Should I create a separate profile table? Or should mapping logic be changed? meteor-ios lib is great but quite complex so if anyone could help me or show the right direction it will be great.

Thank you

Core Data Questions

I'm trying to get a better understanding of how MongoDB, subscriptions, and Core Data all work together (I've worked with iOS before but I'm no expert).

Its my understanding that when you create a subscription, (somehow) it all ends up in Core Data with the right relationship connections. When you edit, insert, or remove a managedObject in a managedObjectContext and save that context, then an appropriate update is sent to the server all under the hood.

So my question here is how all the correct relationships end up in Core Data. Does it simply use the name of the key, i.e. listId means it points to a list? Or do we have to manually set all this stuff somewhere? Also, when you create a new subscription and data starts coming, how do you know which managed object the document applies to?

Great package by the way.

Thanks

Module 'Meteor' not found

Hey!

I'm niether being able to run the examples nor run my own project with meteor-ios installed with cocoa pods. I'm getting a "Module 'Meteor' not found" error. I've checked Build Setting and both "Enable Modules" and "Link Frameworks Automatically" are enabled. Do you have any idea about what could be happening?

Thanks!

Edit: I'm programming in Objective C and my Xcode version is 6.3

Compile to OS X

After a very quick glance at the code, it seems as though this could be made to target OS X. What do you think?

METDDPConnection.h included as project header, needs to be public.

I need to initialise METCoreDataDDPClient using an existing managed object context.
I am trying to use initWithConnection: managedObjectModel: but i am not able to create METDDPConnection instance because METDDPConnection.h is included as a project header.
Is there a specific reason you have not exposed METDDPConnection or have i misunderstood the intended purpose of the initialiser?
If not, is it ok to include it METDDPConnection.h as a public header?

Auto publish support?

It appears that I'm having issues with the autopublish module used in my web app. Whenever I subscribe to one of the collections, I get an error saying that the subscription could not be found. Any advice?

Searching records

How would i go about searching records in a project based on the code from todos example?

For instance trying to search core data:

func updateSearchResultsForSearchController(searchController: UISearchController) {
        let fetchRequest = NSFetchRequest(entityName: "User")
        let predicate = NSPredicate(format: "emails contains[c] %@", searchController.searchBar.text)

        fetchRequest.predicate = predicate

        var error: NSError
        var searchResults: [AnyObject] = managedObjectContext.executeFetchRequest(fetchRequest, error)

        self.tableView.reloadData()
}

i get an error: Cannot invoke 'executeFetchRequest' with an argument list of type '(NSFetchRequest, NSError)'
And there is still the issue on how to display searchResults in table view.

Another idea i had for searching goes something like this:

// Globally set search text variable
var searchText: String = ""

// Then check for searchText and add predicate when creating fetched request
override func createFetchedResultsController() -> NSFetchedResultsController? {
        let fetchRequest = NSFetchRequest(entityName: "User")
        if (self.searchText != "") {
            fetchRequest.predicate = NSPredicate(format: "emails contains[c] %@", self.searchText)
        }

        fetchRequest.sortDescriptors = [NSSortDescriptor(key: "createdAt", ascending: true)]

        return NSFetchedResultsController(fetchRequest: fetchRequest, managedObjectContext: managedObjectContext, sectionNameKeyPath: nil, cacheName: nil)
}

// And then call the function that creates fetched results controller whenever text changes
func updateSearchResultsForSearchController(searchController: UISearchController) {
        self.searchText = searchController.searchBar.text
        self.createFetchedResultsController()

        self.tableView.reloadData()
}

But nothing happens when searching, i get no errors either.

method callbacks should be called on main queue by default or configurable queue

Right now METMethodInvocation executes both _receivedResultHandler and _completionHandler. On the queue associated with the METMethodInvocationCoordinators NSOperationQueue.

This isn't a bug because you dont make any guarantees that callbacks be called on the main thread. But I'm going to suggest that this is much clearer to the users of the lib. API when calling methods in METDDPClient currently looks like this:

[self.ddpClient logoutWithCompletionHandler:^(NSError *error) {
      // WE'RE ON SOME BACKGROUND QUEUE HERE       
}];

This forces the user to dispatch back to main queue where in fact I believe that will be the most common use case.

What do you think @martijnwalraven ?

Access mongo id?

Is there a way to access the mongo id of an object saved in CoreData? Can this be accomplished by adding a fieldName mapping to userInfo of the NSManagedObject?

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.