An iOS and OSX Objective-C Library for Xively similar in design to backbone.js.
Requires AFNetworking and SocketRocket.
After adding AFNetworking and SocketRocket to your project, simply add the files within the XivelyObjectiveC to your project.
Documentation is online at http://xively.github.com/XivelyObjective-C.
XivelyFeedModel, XivelyDatastreamModel and XivelyDatapointModel are representations of a single entity on Xively: a feed, a datastream or a datapoint.
Information about the entity is stored in a mutable dictionary called info
(such the id, current_value, tags, title, at, etc.) .
A model can fetch which will load it from Xively; it can save which will create or update it on Xively; and deleteFromXively which will remove it from Xively.
XivelyFeedModel and XivelyDatastreamModel can also subscribe and unsubscribe from Xively. A subscribed feed or datastream model will automatically update with any changes which happen on Xively.
Information about the model's child entities (a feed's datastreams or a datastream's datapoints) are stored in collections.
XivelyFeedCollection, XivelyDatastreamCollection and XivelyDatapoints are container classes for models.
XivelyFeedCollection can also fetch feeds from Xively whilst specifying request parameters so the fetch will return a filtered set of feeds, or feeds based on a historical query.
XivelyDatapointCollection can also save all its new datapoints to Xively.
This should be done as early as possible if only one API Key is used.
[[XivelyAPI defaultAPI] setApiKey:@"<API Key>"];
By default all new models and collections will use this API Key when communicating with the server.
A different API Key may be used by creating new XivelyAPI object and adding to other XivelyModels and XivelyCollections on a case by case basis
XivelyFeedModel *feed = [[XivelyFeedModel alloc] init];
XivelyAPI *alternativeAPI = [[XivelyApi alloc] init];
[feed setApi:alternativeAPI];
See the example code folders for ready-to-use templates of apps that read Xively Feed and Datastreams over socket connections.
Add a new datapoint to Xively
// set your API key
[[XivelyAPI defaultAPI] setApiKey:@"somekey"];
// create and & setup datapoint
XivelyDatapointModel *datapoint = [[XivelyDatapointModel alloc] init];
// set the id of the feed the datapoint belongs to
datapoint.feedId = 100;
// set the id of the datastream the datapoint belongs to
datapoint.datastreamId = @"miles";
// set the value of the datapoint
[datapoint.info setValue:@"2399" forKey:@"value"];
// save it to Xively
[datapoint save];
Multiple datapoints can be saved to Xively in one go by using a datapoint collection
// create & setup a new datapoint collection
self.datapointCollection = [[XivelyDatapointCollection alloc] init];
self.datapointCollection.feedId = 100;
self.datapointCollection.datastreamId = @"miles";
// ..
// later add a datapoint to the collection
XivelyDatapointModel *datapoint = [[XivelyDatapointModel alloc] init];
[datapoint.info setValue:@"13234" forKey:@"value"];
[datapoint.info setValue:@"2010-05-20T11:01:43Z" forKey:@"at"];
[self.datapointCollection.datapoints addObject:datapoint];
// save the new datapoints
[self.datapointsCollection save];
For example, in a table view controller
-(void)viewWillAppear:(BOOL)animated {
// create the a new feed collection
if (!self.feedCollection) {
self.feedCollection = [[XivelyFeedCollection alloc] init]
}
// set this feed collection to only fetch 100 feeds
[self.feedCollection useParameter:@"per_page" withValue:@"100"];
// set it to only fetch feeds from the user "joebloggs"
[self.feedCollection useParameter:@"user" withValue:@"joebloggs"];
// become the delegate so we know when the feedCollection has fetched
self.feedCollection.delegate = self;
// fetch the feeds
[self.feedCollection fetch];
To know when the collection has fetched, implement the methods of the XivelyFeedCollectionDelegate protocol.
- (void)feedCollectionDidFetch:(XivelyFeedCollection *)feedCollection {
// feeds were fetch so reload the table view
[self.tableView reload];
}
- (void)feedCollectionFailedToFetch:(XivelyFeedCollection *)feedCollection withError:(NSError*)error json:(id)JSON {
// feeds failed to fetch
NSLog(@"The feed collection failed to fetch.")
NSLog(@"The error is %@", error)
// and if we spoke to the Xively server, there is a good
// chance we will have JSON that describe the error
NSLog(@"Xively said %@", JSON);
The feed collection will now have an array of feed models which can be use to populate the table cells
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
// get the feed model
XivelyFeedModel *feed = [self.feedsCollection.feeds objectAtIndex:indexPath.row];
// we can query things about this feed
NSString *title = [feed.info valueForKeyPath:@"title"];
// the feeds also has a datastream collection with all the datastreams
XivelyDatastreamCollection *datastreamCollection = feed.datastreamCollection;
// this contains an array of XivelyDatastreamModels and we can get the last one as it is an array
XivelyDatastreamModel *datastream = [datastreamCollection.datastreams lastObject];
// then we can get information about the datastream
NSString *datastreamID = [feed.info valueForKeyPath:@"id"];
NSString *unitLabel = [feed.info valueForKeyPath:@"unit.label"];
float currentValue = [[feed.info valueForKeyPath:@"current_value"] floatValue];
// or, we could just log all the info about the stream
NSLog(@"%@", feed.info);
Feeds can be created and saved
// create the feed model
XivelyFeedModel *feedModel = [[XivelyFeedModel alloc] init];
// add a title
[feedModel.info setObject:@"Example Feed" forKey:@"title"];
[feedModel save];
After this a delegate will be notified via either of these methods
- (void)modelDidSave:(XivelyModel *)model;
- (void)modelFailedToSave:(XivelyModel *)model withError:(NSError*)error json:(id)JSON;
A feed on Xively can be retrieved from Xively by
// create a feed model
XivelyFeedModel *feedModel = [[XivelyFeedModel alloc] init];
// set the feed's id
[feedModel.info setValue:@"100" forKey:@"id"];
[feedModel.info fetch];
After this a delegate will be notified via either of these methods
- (void)modelDidFetch:(XivelyModel *)model;
- (void)modelFailedToFetch:(XivelyModel *)model withError:(NSError*)error json:(id)JSON;
A datastream can be created at the same time as feed
// create the datastream model
XivelyDatastream *datastream = [[XivelyDatastream alloc] init];
// add some information
[datastream.info setObject:@"id" forKey:@"Room"];
[datastream.info setObject:@"id" forKey:@"current_value"];
// add the datastream to the feed's datastream collection
[feedModel.datastreamCollection.datastreams addObject:datastream];
[feedModel save];
A new datastream may be made directly
// create the datastream model
XivelyDatastream *datastream = [[XivelyDatastream alloc] init];
// provide its feed's id
datastream.feedId = 101;
// give the datastream a new id
[datastream.info setValue:@"Temperature"];
[datastream.feedId save];
A datastream can retrieved by providing a feedId
and the datastreams 'id' key to the info dictionary and calling fetch
// Create a new datastream model
XivelyDatastreamModel *myDatastream = [[XivelyDatastreamModel alloc] init];
// Set the datastream's id
[myDatastream setValue:@"Temperture" forKey:@"id"];
// Also add the datastream parent feed id
myDatastream.feedId = 100;
// Finally, fetch the datastream from Xively
[myDatastream fetch];
// ...
// Later, after feed has called `modelDidFetch:` on its delegate
NSString *currentValue = [myDatastream.info valueForKeyPath:@"current_value"];
The below example also applies to feeds
A datastream may be updated with live updates from Xively by subscribing a XivelyDatastreamModel to Xively.
*It is not nessicary to fetch the XivelyDatastreamModel first, however without doing so there will be no information about the datastream until it is next changed on Xively.
- (id)init {
self = [super init];
if (self) {
// set up the datastream
self.datastream = [[XivelyDatastream alloc] init];
self.datastream.feedId = 100;
[self.datastream.info setValue:@"miles" forKey:@"id"];
}
}
- (IBAction)subscribeTouched:(id)sender {
self.datastream.delegate = self;
// toggle the datastream being subscribed
if (self.datastream.isSubscribed) {
[self.datastream subscribe];
} else {
[self.datastream unsubscribe];
}
}
- (void)modelUpdatedViaSubscription:(XivelyModel *)model {
myLabel.text = [self.datastream.info valueForKeyPath:@"current_value"];
}
- (void)modelDidSubscribe:(XivelyModel *)model {
NSLog(@"Web socket connected, now receiving live changes to datastream");
}
- (void)modelDidUnsubscribe:(XivelyModel *)model withError:(NSError *)error;
NSLog("Web socket disconnected...");
if (error) {
NSLog(@"...because something went wrong");
} else {
NSLog(@"...because we successfully unsubscribed");
}
}