Developing	
  With	
  
Couchbase	
  Lite	
  on	
  iOS
6/10/14
Jens	
  Al9e
jens@couchbase.com
“Tell	
  Them	
  What	
  You’re	
  Going	
  To	
  Tell	
  Them”
• InstallaFon	
  and	
  setup	
  walk-­‐through	
  
• Demo...
GeNng	
  Up	
  And	
  Running
• Download	
  Couchbase	
  Lite	
  
• Download	
  Grocery	
  Sync	
  sample	
  code	
  
• Co...
1.	
  Download	
  Couchbase	
  Lite
www.couchbase.com/download#cb-­‐mobile
Download	
  Grocery	
  Sync
github.com/couchbaselabs/Grocery-­‐Sync-­‐iOS
Plug	
  In	
  The	
  Framework
option
Run	
  &	
  Sync
Live	
  Demo
A	
  Tour	
  of	
  the	
  Code	
  
and	
  the	
  API
IniFalizaFon
DemoAppDelegate.m:64
        //  Initialize  Couchbase  Lite  and  find/create  my  database:  
        NSErr...
CBLManager
Database	
  
“otherdb”
CBLDatabase	
  
“db”
CBLDocument	
  
“doc3”
CBLDocument	
  
“doc2”
Document	
  
“doc1”
C...
Manager
• CollecFon	
  of	
  named	
  databases	
  
• Generally	
  a	
  singleton	
  
Unless	
  you	
  run	
  on	
  mulEpl...
Database
• Namespace	
  for	
  documents	
  
• Contains	
  views	
  and	
  their	
  indexes	
  
• Contains	
  validaFon	
 ...
Document
• Has	
  unique	
  ID	
  within	
  its	
  database	
  
• Contains	
  arbitrary*	
  JSON	
  object	
  
*except	
  ...
IniFalizaFon
DemoAppDelegate.m:64
        //  Initialize  Couchbase  Lite  and  find/create  my  database:  
        NSErr...
CreaFng	
  a	
  Database	
  View
RootViewController.m:101
        //  Define  a  view  with  a  map  function  that  index...
View	
  
“completed”
Views	
  &	
  Queries
CBLDatabase	
  
“db”
CBLView	
  
“byDate”
function(doc) {
emit(doc.created,
doc...
Views
• Map/Reduce	
  mechanism	
  
Popular	
  in	
  other	
  NoSQL	
  databases	
  
A	
  view	
  is	
  similar	
  to	
  i...
CreaFng	
  a	
  Database	
  View
RootViewController.m:101
        //  Define  a  view  with  a  map  function  that  index...
Driving	
  the	
  Table	
  from	
  a	
  View	
  Query
RootViewController.m:69
        //  Create  a  query  sorted  by  de...
Queries
• Basic	
  feature	
  set	
  
Key	
  ranges,	
  offset/limit,	
  reverse,	
  group	
  by	
  key…	
  
No	
  joins	
 ...
Live	
  Queries	
  &	
  Table	
  Data	
  Sources
key value docID
“2013-­‐09-­‐30” “Pencil	
  shavings”“doc62”
“2013-­‐10-­...
Driving	
  the	
  Table	
  from	
  a	
  View	
  Query
RootViewController.m:69
        //  Create  a  query  sorted  by  de...
Combining	
  CreaFng+Querying
// Returns a query for all the lists in a database.
+ (CBLQuery*) queryListsInDatabase: (CBL...
Wiring	
  Up	
  The	
  Table	
  View
RootViewController.xib
Displaying	
  Table	
  Cells
RootViewController.m:131
-­‐  (void)couchTableSource:(CBLUITableSource*)source  
            ...
Responding	
  To	
  Taps
RootViewController.m:167
-­‐  (void)tableView:(UITableView  *)tableView    
                didSe...
Adding	
  New	
  Items
RootViewController.m:248
-­‐(void)textFieldDidEndEditing:(UITextField  *)textField  {  
        // ...
DeleFng	
  Items
RootViewController.m:189
-­‐  (NSArray*)checkedDocuments  {  
        NSMutableArray*  checked  =  [NSMut...
OK,	
  But	
  Where’s	
  The	
  Sync?
CreaFng	
  ReplicaFons
RootViewController.m:293
        _pull  =  [self.database  createPullReplication:  newRemoteURL];  ...
ReplicaFon
Database	
  
“db”
ReplicaFon
Dir:	
   push	
  
Remote:	
  hlp://server/db	
  
Auth:	
   <token>
ReplicaFon
Dir:...
ReplicaFon
• Each	
  ReplicaFon	
  is	
  one-­‐direcFonal	
  (push	
  or	
  pull)	
  
• ReplicaFons	
  can	
  be	
  one-­‐...
Monitoring	
  ReplicaFons
RootViewController.m:355
//  Called  in  response  to  replication-­‐change  notifications.  Upd...
Beyond	
  Grocery	
  Sync
Models
Task
List
Task
Task
@interface Task : CBLModel
!@property NSString*title;
@property NSDate* created;
@property bool...
Models
• Kind	
  of	
  like	
  NSManagedObject,	
  but	
  simpler	
  
• Map	
  JSON	
  to	
  naFve	
  @properFes	
  
Scala...
RepresenFng	
  Document	
  Types
• There	
  are	
  no	
  tables	
  to	
  separate	
  different	
  record	
  types!	
  
Conv...
To-­‐Do	
  List	
  With	
  Models
From	
  ToDoLite	
  project
        Task*  task  =  [Task  modelForDocument:  row.docume...
Querying	
  With	
  MulFple	
  Lists
From	
  ToDoLite	
  project
        [view  setMapBlock:  MAPBLOCK({  
               ...
Querying	
  With	
  MulFple	
  Lists
From	
  ToDoLite	
  project
        CBLQuery*  query  =  [view  query];  
        que...
Whew!
hlp://developer.couchbase.com/mobile/develop/guides/couchbase-­‐lite/index.html
hap://github.com/couchbaselabs/Groce...
Q	
  &	
  A
Webinar - Developing with Couchbase Lite and iOS
Webinar - Developing with Couchbase Lite and iOS
Upcoming SlideShare
Loading in …5
×

Webinar - Developing with Couchbase Lite and iOS

1,280 views

Published on

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 iOS

Published in: Technology
0 Comments
2 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
1,280
On SlideShare
0
From Embeds
0
Number of Embeds
232
Actions
Shares
0
Downloads
17
Comments
0
Likes
2
Embeds 0
No embeds

No notes for slide

Webinar - Developing with Couchbase Lite and iOS

  1. 1. Developing  With   Couchbase  Lite  on  iOS 6/10/14 Jens  Al9e jens@couchbase.com
  2. 2. “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
  3. 3. GeNng  Up  And  Running • Download  Couchbase  Lite   • Download  Grocery  Sync  sample  code   • Copy  framework  into  sample  app  folder   • Build  &  Run
  4. 4. 1.  Download  Couchbase  Lite www.couchbase.com/download#cb-­‐mobile
  5. 5. Download  Grocery  Sync github.com/couchbaselabs/Grocery-­‐Sync-­‐iOS
  6. 6. Plug  In  The  Framework option
  7. 7. Run  &  Sync
  8. 8. Live  Demo
  9. 9. A  Tour  of  the  Code   and  the  API
  10. 10. IniFalizaFon DemoAppDelegate.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];  
  11. 11. 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
  12. 12. Manager • CollecFon  of  named  databases   • Generally  a  singleton   Unless  you  run  on  mulEple  threads   • Manages  database  storage  (local  directory)
  13. 13. Database • Namespace  for  documents   • Contains  views  and  their  indexes   • Contains  validaFon  funcFons   • Source  and  target  of  replicaFon
  14. 14. 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
  15. 15. IniFalizaFon DemoAppDelegate.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];  
  16. 16. CreaFng  a  Database  View RootViewController.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.
  17. 17. 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 }
  18. 18. 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)
  19. 19. CreaFng  a  Database  View RootViewController.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.
  20. 20. Driving  the  Table  from  a  View  Query RootViewController.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
  21. 21. 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
  22. 22. 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
  23. 23. Driving  the  Table  from  a  View  Query RootViewController.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
  24. 24. 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]; }
  25. 25. Wiring  Up  The  Table  View RootViewController.xib
  26. 26. Displaying  Table  Cells RootViewController.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   }  
  27. 27. Responding  To  Taps RootViewController.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];          }   }  
  28. 28. Adding  New  Items RootViewController.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];            
  29. 29. DeleFng  Items RootViewController.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];          }   }
  30. 30. OK,  But  Where’s  The  Sync?
  31. 31. CreaFng  ReplicaFons RootViewController.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];  
  32. 32. ReplicaFon Database   “db” ReplicaFon Dir:   push   Remote:  hlp://server/db   Auth:   <token> ReplicaFon Dir:   pull   Remote:  hlp://server/db   Auth:   <token> notifications
  33. 33. 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
  34. 34. Monitoring  ReplicaFons RootViewController.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];  
  35. 35. Beyond  Grocery  Sync
  36. 36. 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”
  37. 37. 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)
  38. 38. 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);
  39. 39. To-­‐Do  List  With  Models From  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
  40. 40. Querying  With  MulFple  Lists From  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”
  41. 41. Querying  With  MulFple  Lists From  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” {
  42. 42. 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
  43. 43. Q  &  A

×