-
Notifications
You must be signed in to change notification settings - Fork 79
Usage without Core Data
Connecting to a Meteor server is done through a WebSocket URL that needs to be specified when creating an METDDPClient
:
METDDPClient *client = [[METDDPClient alloc] initWithServerURL:[NSURL URLWithString:@"ws://localhost:3000/websocket"]];
[client connect];
A client can then be used to subscribe to sets of documents:
METSubscription *subscription = [client addSubscriptionWithName:@"playersWithMinimumScore" parameters:@[@20] completionHandler:^(NSError *error) {
}];
The client keeps a local cache of documents sent by the server. These can be accessed through the METDatabase
and METCollection
classes. Documents are represented by METDocument
s and identified by a METDocumentKey
. (Keys encapsulate a collectionName
and documentID
).
A document stored in the local cache can be accessed using METDatabase#documentWithKey:
. Alternatively, documents can be accessed by documentID through the collection:
METCollection *players = [database collectionWithName:@"players"];
METDocument *lovelace = [players documentWithID:@"lovelace"];
All documents in a collection can be accessed as an NSArray:
METCollection *players = [database collectionWithName:@"players"];
NSArray *allPlayers = [players allDocuments];
(More complex fetches will be supported by passing a METFetchRequest
to METDatabase#executeFetchRequest:
, but this has not been implemented yet.)
METDocument
s are immutable and data can only be modified through method invocations. Collections are used to encapsulate modification method invocations:
METCollection *players = [database collectionWithName:@"players"];
id documentID = [players insertDocumentWithFields:@{@"name": @"Ada Lovelace", @"score": @25}];
[players updateDocumentWithID:documentID changedFields:@{@"score": @30, @"color": [NSNull null]}];
[players removeDocumentWithID:@"gauss"];
Under the hood, the above code calls three methods on the server, modifying the local cache through a predefined stub in the process.
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.)
- (void)databaseDidChange:(NSNotification *)notification {
dispatch_async(dispatch_get_main_queue(), ^{
// If updating the UI, make sure this happens on the main thread
METDatabaseChanges *databaseChanges = notification.userInfo[METDatabaseChangesKey];
[databaseChanges enumerateDocumentChangeDetailsUsingBlock:^(METDocumentChangeDetails *documentChangeDetails, BOOL *stop) {
...
}];
});
}
A METDatabaseDidChangeNotification
contains a METDatabaseChanges
object that can be asked for information about the changes that occurred. Information about changes to an individual document is encapsulated in a METDocumentChangeDetails
. (This mechanism is modeled somewhat after the PHChange
and PHObjectChangeDetails
classes used by the iOS 8 Photos framework.)
A METDocumentChangeDetails
knows its fieldsBeforeChanges
and fieldsAfterChanges
, and can also be asked for the changedFields
. It reflects the changes to a document since the last notification. Changes are consolidated and a METDocumentChangeDetails
is only included if the fields before and after are actually different. If a document is first added and then removed, or if a field is changed back to its original value, before the notification is posted, no METDocumentChangeDetails
is created and a METDatabaseDidChangeNotification
may not be posted.
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.
Method invocations that change documents will also post a METDatabaseDidChangeNotification
. If a stub has been defined, changes to the local cache are posted first and another notification will only be posted when server updates have been flushed (and if the effects are different from that of the stub).
METDatabase#performUpdates:
can be used to group batches of updates to only post a single METDatabaseDidChangeNotification
(or none if no net changes have occured, like below):
[database performUpdates:^{
id documentID = [collection insertDocumentWithFields:@{@"name": @"Ada Lovelace", @"score": @25}];
[collection updateDocumentWithID:documentID changedFields:@{@"score": @30, @"color": [NSNull null]}];
[collection removeDocumentWithID:documentID];
}];
Methods are called on METDDPClient
and an optional completionHandler
can be specified to receive a result:
[client callMethodWithName:@"doSomething" parameters:@[@"someParameter"] completionHandler:^(id result, NSError *error) {
...
}];
If a stub has been defined, it will be executed first and could call more methods in the process (and so on). If at any point a data modification method is called, it will make changes to the local cache and participate in latency compensation:
[client defineStubForMethodWithName:@"doSomething" usingBlock:^id(NSArray *parameters) {
[[client.database collectionWithName:@"players"] updateDocumentWithID:@"lovelace" changedFields:@{@"score": @20}];
return nil;
}];