webinar - developing with couchbase lite and ios
DESCRIPTION
Learn how to develop with Couchbase Lite for iOS in this technical lecture led by Jens Alfke, lead Couchbase Lite iOS developer. The session will include a look into the Objective-C native APIs, using a walkthrough of a demo app. Other topics include: A 5-minute recap of the Couchbase Lite architecture A step-by-step demonstration on how to develop an iOS application with Couchbase Lite An explanation of the future plans for Couchbase Lite iOSTRANSCRIPT
![Page 2: Webinar - Developing with Couchbase Lite and iOS](https://reader033.vdocuments.net/reader033/viewer/2022042614/558fcd051a28abf8388b47ae/html5/thumbnails/2.jpg)
“Tell Them What You’re Going To Tell Them”
• InstallaFon and setup walk-‐through
• Demo of Grocery Sync sample app
• Tour of Grocery Sync code with digressions about the API
and the document model
and querying
• Beyond Grocery Sync
![Page 3: Webinar - Developing with Couchbase Lite and iOS](https://reader033.vdocuments.net/reader033/viewer/2022042614/558fcd051a28abf8388b47ae/html5/thumbnails/3.jpg)
GeNng Up And Running
• Download Couchbase Lite
• Download Grocery Sync sample code
• Copy framework into sample app folder
• Build & Run
![Page 4: Webinar - Developing with Couchbase Lite and iOS](https://reader033.vdocuments.net/reader033/viewer/2022042614/558fcd051a28abf8388b47ae/html5/thumbnails/4.jpg)
![Page 5: Webinar - Developing with Couchbase Lite and iOS](https://reader033.vdocuments.net/reader033/viewer/2022042614/558fcd051a28abf8388b47ae/html5/thumbnails/5.jpg)
1. Download Couchbase Litewww.couchbase.com/download#cb-‐mobile
![Page 6: Webinar - Developing with Couchbase Lite and iOS](https://reader033.vdocuments.net/reader033/viewer/2022042614/558fcd051a28abf8388b47ae/html5/thumbnails/6.jpg)
Download Grocery Syncgithub.com/couchbaselabs/Grocery-‐Sync-‐iOS
![Page 7: Webinar - Developing with Couchbase Lite and iOS](https://reader033.vdocuments.net/reader033/viewer/2022042614/558fcd051a28abf8388b47ae/html5/thumbnails/7.jpg)
Plug In The Framework
option
![Page 8: Webinar - Developing with Couchbase Lite and iOS](https://reader033.vdocuments.net/reader033/viewer/2022042614/558fcd051a28abf8388b47ae/html5/thumbnails/8.jpg)
Run & Sync
![Page 9: Webinar - Developing with Couchbase Lite and iOS](https://reader033.vdocuments.net/reader033/viewer/2022042614/558fcd051a28abf8388b47ae/html5/thumbnails/9.jpg)
Live Demo
![Page 10: Webinar - Developing with Couchbase Lite and iOS](https://reader033.vdocuments.net/reader033/viewer/2022042614/558fcd051a28abf8388b47ae/html5/thumbnails/10.jpg)
A Tour of the Code and the API
![Page 11: Webinar - Developing with Couchbase Lite and iOS](https://reader033.vdocuments.net/reader033/viewer/2022042614/558fcd051a28abf8388b47ae/html5/thumbnails/11.jpg)
IniFalizaFonDemoAppDelegate.m:64
// Initialize Couchbase Lite and find/create my database: NSError* error; self.database = [[CBLManager sharedInstance] databaseNamed: kDatabaseName error: &error]; if (!self.database) [self showAlert: @"Couldn't open database" error: error fatal: YES];
![Page 12: Webinar - Developing with Couchbase Lite and iOS](https://reader033.vdocuments.net/reader033/viewer/2022042614/558fcd051a28abf8388b47ae/html5/thumbnails/12.jpg)
CBLManager
Database “otherdb”
CBLDatabase “db”
CBLDocument “doc3”
CBLDocument “doc2”
Document “doc1”
CBLDocument “doc1” !{ “text”: “Vacuum”, “created”: “2013-10-08”, “check”: false }
thumb.jpg
Manager, Databases, Documents
![Page 13: Webinar - Developing with Couchbase Lite and iOS](https://reader033.vdocuments.net/reader033/viewer/2022042614/558fcd051a28abf8388b47ae/html5/thumbnails/13.jpg)
Manager
• CollecFon of named databases
• Generally a singleton Unless you run on mulEple threads
• Manages database storage (local directory)
![Page 14: Webinar - Developing with Couchbase Lite and iOS](https://reader033.vdocuments.net/reader033/viewer/2022042614/558fcd051a28abf8388b47ae/html5/thumbnails/14.jpg)
Database
• Namespace for documents
• Contains views and their indexes
• Contains validaFon funcFons
• Source and target of replicaFon
![Page 15: Webinar - Developing with Couchbase Lite and iOS](https://reader033.vdocuments.net/reader033/viewer/2022042614/558fcd051a28abf8388b47ae/html5/thumbnails/15.jpg)
Document
• Has unique ID within its database
• Contains arbitrary* JSON object *except keys that start with “_” are reserved
There is no explicit, enforced schema
DenormalizaEon is OK — use arrays or dicEonaries
• May contain binary aaachments Data blobs, can be large, tagged with MIME type
• Versioned MulE-‐Version Concurrency Control (MVCC)
Every update creates a revision ID (based on digest of contents)
Revision ID history is stored
![Page 16: Webinar - Developing with Couchbase Lite and iOS](https://reader033.vdocuments.net/reader033/viewer/2022042614/558fcd051a28abf8388b47ae/html5/thumbnails/16.jpg)
IniFalizaFonDemoAppDelegate.m:64
// Initialize Couchbase Lite and find/create my database: NSError* error; self.database = [[CBLManager sharedInstance] databaseNamed: kDatabaseName error: &error]; if (!self.database) [self showAlert: @"Couldn't open database" error: error fatal: YES];
![Page 17: Webinar - Developing with Couchbase Lite and iOS](https://reader033.vdocuments.net/reader033/viewer/2022042614/558fcd051a28abf8388b47ae/html5/thumbnails/17.jpg)
CreaFng a Database ViewRootViewController.m:101
// Define a view with a map function that indexes to-‐do items by creation date: [[theDatabase viewNamed: @"byDate"] setMapBlock: MAPBLOCK({ id date = doc[@"created_at"]; if (date) emit(date, doc); }) reduceBlock: nil version: @"1.1"];
Not a UIView — a database “view” is like an index.
![Page 18: Webinar - Developing with Couchbase Lite and iOS](https://reader033.vdocuments.net/reader033/viewer/2022042614/558fcd051a28abf8388b47ae/html5/thumbnails/18.jpg)
View “completed”
Views & Queries
CBLDatabase “db”
CBLView “byDate”
function(doc) { emit(doc.created, doc.title); }map function
key value docID
“2013-‐03-‐12” “taxes” “doc17”
“2013-‐09-‐30” “call mom” “doc62”
“2013-‐10-‐17” “cat food” “doc82”
“2013-‐10-‐17” “tea bags” “doc83”
“2013-‐10-‐22” “upgrade” “doc90”
view index
CBLQuery}
![Page 19: Webinar - Developing with Couchbase Lite and iOS](https://reader033.vdocuments.net/reader033/viewer/2022042614/558fcd051a28abf8388b47ae/html5/thumbnails/19.jpg)
Views
• Map/Reduce mechanism Popular in other NoSQL databases
A view is similar to index in relaEonal database
• App-‐defined map funcFon Called on every document
Can emit arbitrary key/value pairs into the index
• OpFonal reduce funcFon Data aggregaEon / grouping
• FuncFons are registered as naFve blocks/callbacks Not stored as JavaScript in “design document” (as in CouchDB)
![Page 20: Webinar - Developing with Couchbase Lite and iOS](https://reader033.vdocuments.net/reader033/viewer/2022042614/558fcd051a28abf8388b47ae/html5/thumbnails/20.jpg)
CreaFng a Database ViewRootViewController.m:101
// Define a view with a map function that indexes to-‐do items by creation date: [[theDatabase viewNamed: @"byDate"] setMapBlock: MAPBLOCK({ id date = doc[@"created_at"]; if (date) emit(date, doc); }) reduceBlock: nil version: @"1.1"];
Not a UIView — a database “view” is like an index.
![Page 21: Webinar - Developing with Couchbase Lite and iOS](https://reader033.vdocuments.net/reader033/viewer/2022042614/558fcd051a28abf8388b47ae/html5/thumbnails/21.jpg)
Driving the Table from a View QueryRootViewController.m:69
// Create a query sorted by descending date, i.e. newest items first: CBLLiveQuery* query = [[[database viewNamed:@"byDate"] query] asLiveQuery]; query.descending = YES; ! // Plug the query into the CBLUITableSource, which will use it to drive the table. // (The CBLUITableSource uses KVO to observe the query's .rows property.) self.dataSource.query = query; self.dataSource.labelProperty = @"text";
@property(nonatomic, strong) IBOutlet UITableView *tableView; @property(nonatomic, strong) IBOutlet CBLUITableSource* dataSource;
RootViewController.h:41
![Page 22: Webinar - Developing with Couchbase Lite and iOS](https://reader033.vdocuments.net/reader033/viewer/2022042614/558fcd051a28abf8388b47ae/html5/thumbnails/22.jpg)
Queries
• Basic feature set Key ranges, offset/limit, reverse, group by key…
No joins or fancy sorEng
but compound keys (and clever emits) allow for some tricks
• LiveQuery subclass Monitors database, pushes noEficaEons
Uses KVO on iOS, can drive a UITableView
• iOS goodies! Full-‐text indexing
Geo (bounding-‐box) queries
![Page 23: Webinar - Developing with Couchbase Lite and iOS](https://reader033.vdocuments.net/reader033/viewer/2022042614/558fcd051a28abf8388b47ae/html5/thumbnails/23.jpg)
Live Queries & Table Data Sources
key value docID
“2013-‐09-‐30” “Pencil shavings”“doc62”
“2013-‐10-‐17” “Mangos” “doc82”
“2013-‐10-‐17” “second” “doc83”
view index CBLLiveQuery
CBLQuery}data source
CBLUI-‐TableSource
![Page 24: Webinar - Developing with Couchbase Lite and iOS](https://reader033.vdocuments.net/reader033/viewer/2022042614/558fcd051a28abf8388b47ae/html5/thumbnails/24.jpg)
Driving the Table from a View QueryRootViewController.m:69
// Create a query sorted by descending date, i.e. newest items first: CBLLiveQuery* query = [[[database viewNamed:@"byDate"] query] asLiveQuery]; query.descending = YES; ! // Plug the query into the CBLUITableSource, which will use it to drive the table. // (The CBLUITableSource uses KVO to observe the query's .rows property.) self.dataSource.query = query; self.dataSource.labelProperty = @"text";
@property(nonatomic, strong) IBOutlet UITableView *tableView; @property(nonatomic, strong) IBOutlet CBLUITableSource* dataSource;
RootViewController.h:41
![Page 25: Webinar - Developing with Couchbase Lite and iOS](https://reader033.vdocuments.net/reader033/viewer/2022042614/558fcd051a28abf8388b47ae/html5/thumbnails/25.jpg)
Combining CreaFng+Querying
// Returns a query for all the lists in a database. + (CBLQuery*) queryListsInDatabase: (CBLDatabase*)db { CBLView* view = [db viewNamed: @"lists"]; if (!view.mapBlock) { // Register the map function, the first time we access the view: [view setMapBlock: MAPBLOCK({ if ([doc[@"type"] isEqualToString:kListDocType]) emit(doc[@"title"], nil); }) reduceBlock: nil version: @"1"]; // bump version any time you change the MAPBLOCK body! } return [view createQuery]; }
![Page 26: Webinar - Developing with Couchbase Lite and iOS](https://reader033.vdocuments.net/reader033/viewer/2022042614/558fcd051a28abf8388b47ae/html5/thumbnails/26.jpg)
Wiring Up The Table ViewRootViewController.xib
![Page 27: Webinar - Developing with Couchbase Lite and iOS](https://reader033.vdocuments.net/reader033/viewer/2022042614/558fcd051a28abf8388b47ae/html5/thumbnails/27.jpg)
Displaying Table CellsRootViewController.m:131
-‐ (void)couchTableSource:(CBLUITableSource*)source willUseCell:(UITableViewCell*)cell forRow:(CBLQueryRow*)row { // Set the cell background and font: ……… // Configure the cell contents. Map function (above) copies the doc properties // into its value, so we can read them without having to load the document. NSDictionary* rowValue = row.value; BOOL checked = [rowValue[@"check"] boolValue]; if (checked) { cell.textLabel.textColor = [UIColor grayColor]; cell.imageView.image = [UIImage imageNamed:@"checked"]; } else { cell.textLabel.textColor = [UIColor blackColor]; cell.imageView.image = [UIImage imageNamed: @"unchecked"]; } // cell.textLabel.text is already set, thanks to setting up labelProperty }
![Page 28: Webinar - Developing with Couchbase Lite and iOS](https://reader033.vdocuments.net/reader033/viewer/2022042614/558fcd051a28abf8388b47ae/html5/thumbnails/28.jpg)
Responding To TapsRootViewController.m:167
-‐ (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { // Ask CBLUITableSource for the corresponding query row, and get its document: CBLQueryRow *row = [self.dataSource rowAtIndex:indexPath.row]; CBLDocument *doc = row.document; ! // Toggle the document's 'checked' property: NSMutableDictionary *docContent = [doc.properties mutableCopy]; BOOL wasChecked = [docContent[@"check"] boolValue]; docContent[@"check"] = @(!wasChecked); ! // Save changes: NSError* error; if (![doc.currentRevision putProperties: docContent error: &error]) { [self showErrorAlert: @"Failed to update item" forError: error]; } }
![Page 29: Webinar - Developing with Couchbase Lite and iOS](https://reader033.vdocuments.net/reader033/viewer/2022042614/558fcd051a28abf8388b47ae/html5/thumbnails/29.jpg)
Adding New ItemsRootViewController.m:248
-‐(void)textFieldDidEndEditing:(UITextField *)textField { // Get the name of the item from the text field: NSString *text = addItemTextField.text; if (text.length == 0) { return; } addItemTextField.text = nil; ! // Create the new document's properties: NSDictionary *inDocument = @{ @"text": text, @"check": @NO, @"created_at": [CBLJSON JSONObjectWithDate: [NSDate date]] }; // Save the document: CBLDocument* doc = [database createDocument]; NSError* error; if (![doc putProperties: inDocument error: &error]) { [self showErrorAlert: @"Couldn't save new item" forError: error];
![Page 30: Webinar - Developing with Couchbase Lite and iOS](https://reader033.vdocuments.net/reader033/viewer/2022042614/558fcd051a28abf8388b47ae/html5/thumbnails/30.jpg)
DeleFng ItemsRootViewController.m:189
-‐ (NSArray*)checkedDocuments { NSMutableArray* checked = [NSMutableArray array]; for (CBLQueryRow* row in self.dataSource.rows) { CBLDocument* doc = row.document; if ([doc[@"check"] boolValue]) [checked addObject: doc]; } return checked; } !!-‐ (void)deleteCheckedDocuments { NSError* error; if (![dataSource deleteDocuments: self.checkedDocuments error: &error]) { [self showErrorAlert: @"Failed to delete items" forError: error]; } }
![Page 31: Webinar - Developing with Couchbase Lite and iOS](https://reader033.vdocuments.net/reader033/viewer/2022042614/558fcd051a28abf8388b47ae/html5/thumbnails/31.jpg)
OK, But Where’s The Sync?
![Page 32: Webinar - Developing with Couchbase Lite and iOS](https://reader033.vdocuments.net/reader033/viewer/2022042614/558fcd051a28abf8388b47ae/html5/thumbnails/32.jpg)
CreaFng ReplicaFonsRootViewController.m:293
_pull = [self.database createPullReplication: newRemoteURL]; _push = [self.database createPushReplication: newRemoteURL]; _pull.continuous = _push.continuous = YES; // Observe replication progress changes, in both directions: NSNotificationCenter* nctr = [NSNotificationCenter defaultCenter]; [nctr addObserver: self selector: @selector(replicationProgress:) name: kCBLReplicationChangeNotification object: _pull]; [nctr addObserver: self selector: @selector(replicationProgress:) name: kCBLReplicationChangeNotification object: _push]; [_push start]; [_pull start];
![Page 33: Webinar - Developing with Couchbase Lite and iOS](https://reader033.vdocuments.net/reader033/viewer/2022042614/558fcd051a28abf8388b47ae/html5/thumbnails/33.jpg)
ReplicaFon
Database “db”
ReplicaFonDir: push Remote: hlp://server/db Auth: <token>
ReplicaFonDir: pull Remote: hlp://server/db Auth: <token>
notifications
![Page 34: Webinar - Developing with Couchbase Lite and iOS](https://reader033.vdocuments.net/reader033/viewer/2022042614/558fcd051a28abf8388b47ae/html5/thumbnails/34.jpg)
ReplicaFon
• Each ReplicaFon is one-‐direcFonal (push or pull)
• ReplicaFons can be one-‐shot or conFnuous One-‐shot: Stops when complete.
ConEnuous: Keeps monitoring changes Ell app quits
• Replicator runs in a background thread It detects online/offline, handles connecEon errors, retries…
You just see document-‐changed or query-‐changed noEficaEons.
• Progress is observable through KVO or NSNoFficaFon
![Page 35: Webinar - Developing with Couchbase Lite and iOS](https://reader033.vdocuments.net/reader033/viewer/2022042614/558fcd051a28abf8388b47ae/html5/thumbnails/35.jpg)
Monitoring ReplicaFonsRootViewController.m:355
// Called in response to replication-‐change notifications. Updates the progress UI. -‐ (void) replicationProgress: (NSNotificationCenter*)n { if (_pull.status==kCBLReplicationActive || _push.status==kCBLReplicationActive) { // Sync is active -‐-‐ aggregate progress of both replications: unsigned completed = _pull.completedChangesCount + _push.completedChangesCount; unsigned total = _pull.changesCount + _push.changesCount; [self showSyncStatus]; // Update the progress bar, avoiding divide-‐by-‐zero exceptions: progress.progress = (completed / (float)MAX(total, 1u)); } else { // Sync is idle -‐-‐ hide the progress bar and show the config button: [self showSyncButton]; } ! // Check for any change in error status and display new errors: NSError* error = _pull.lastError ? _pull.lastError : _push.lastError; if (error != _syncError) { _syncError = error; if (error) [self showErrorAlert: @"Error syncing" forError: error];
![Page 36: Webinar - Developing with Couchbase Lite and iOS](https://reader033.vdocuments.net/reader033/viewer/2022042614/558fcd051a28abf8388b47ae/html5/thumbnails/36.jpg)
Beyond Grocery Sync
![Page 37: Webinar - Developing with Couchbase Lite and iOS](https://reader033.vdocuments.net/reader033/viewer/2022042614/558fcd051a28abf8388b47ae/html5/thumbnails/37.jpg)
Models
Task
List
Task
Task
@interface Task : CBLModel !@property NSString*title; @property NSDate* created; @property bool checked; @property List* list; !@end
@interface List : CBLModel !@property NSString* title; @property NSArray* members; !@end
Document “doc23”
Document “doc82”
Document “doc99”
Document “doc3”
![Page 38: Webinar - Developing with Couchbase Lite and iOS](https://reader033.vdocuments.net/reader033/viewer/2022042614/558fcd051a28abf8388b47ae/html5/thumbnails/38.jpg)
Models
• Kind of like NSManagedObject, but simpler
• Map JSON to naFve @properFes Scalar types (int, bool…), String, Date, Data (blob)
References to other doc models
Arrays of the above
• ProperFes are KV-‐observable
• Models provide mutable state -‐save: writes to underlying document
• No query-‐based relaFon support (yet)
![Page 39: Webinar - Developing with Couchbase Lite and iOS](https://reader033.vdocuments.net/reader033/viewer/2022042614/558fcd051a28abf8388b47ae/html5/thumbnails/39.jpg)
RepresenFng Document Types
• There are no tables to separate different record types! ConvenEon is to use a “type” property
• Map funcFons can pick out docs with the right type if (doc.type == “item”) emit(doc.created, doc.text);
![Page 40: Webinar - Developing with Couchbase Lite and iOS](https://reader033.vdocuments.net/reader033/viewer/2022042614/558fcd051a28abf8388b47ae/html5/thumbnails/40.jpg)
To-‐Do List With ModelsFrom ToDoLite project
Task* task = [Task modelForDocument: row.document]; cell.textLabel.text = task.text; cell.textLabel.textColor = task.checked ? [UIColor grayColor] : [UIColor blackColor];
@interface Task : CBLModel !@property NSString*title; @property NSDate* created; @property bool checked; @property List* list; !@end
![Page 41: Webinar - Developing with Couchbase Lite and iOS](https://reader033.vdocuments.net/reader033/viewer/2022042614/558fcd051a28abf8388b47ae/html5/thumbnails/41.jpg)
Querying With MulFple ListsFrom ToDoLite project
[view setMapBlock: MAPBLOCK({ if ([doc[@"type"] isEqualToString: kTaskDocType]) { id date = doc[@"created_at"]; NSString* listID = doc[@"list_id"]; emit(@[listID, date], doc); } }) reduceBlock: nil version: @"4"];
key docID
[“list1”, “2013-‐09-‐30”] “doc82”
[“list2”, “2013-‐06-‐02”] “doc62”
[“list2”, “2013-‐10-‐17”] “doc83”
[“list2”, “2013-‐10-‐28”] “doc90”
[“list3”, “2013-‐01-‐01”] “doc01”
![Page 42: Webinar - Developing with Couchbase Lite and iOS](https://reader033.vdocuments.net/reader033/viewer/2022042614/558fcd051a28abf8388b47ae/html5/thumbnails/42.jpg)
Querying With MulFple ListsFrom ToDoLite project
CBLQuery* query = [view query]; query.descending = YES; NSString* myListId = self.document.documentID; query.startKey = @[myListId, @{}]; query.endKey = @[myListId];
key docID
[“list1”, “2013-‐09-‐30”] “doc82”
[“list2”, “2013-‐06-‐02”] “doc62”
[“list2”, “2013-‐10-‐17”] “doc83”
[“list2”, “2013-‐10-‐28”] “doc90”
[“list3”, “2013-‐01-‐01”] “doc01”
{
![Page 43: Webinar - Developing with Couchbase Lite and iOS](https://reader033.vdocuments.net/reader033/viewer/2022042614/558fcd051a28abf8388b47ae/html5/thumbnails/43.jpg)
Whew!
hlp://developer.couchbase.com/mobile/develop/guides/couchbase-‐lite/index.html
hap://github.com/couchbaselabs/Grocery-‐Sync-‐iOS
haps://github.com/couchbaselabs/ToDoLite-‐iOS
![Page 44: Webinar - Developing with Couchbase Lite and iOS](https://reader033.vdocuments.net/reader033/viewer/2022042614/558fcd051a28abf8388b47ae/html5/thumbnails/44.jpg)
![Page 45: Webinar - Developing with Couchbase Lite and iOS](https://reader033.vdocuments.net/reader033/viewer/2022042614/558fcd051a28abf8388b47ae/html5/thumbnails/45.jpg)
Q & A