Webinar - Developing with Couchbase Lite iOS


Published on

Learn how to develop with Couchbase Lite for iOS in this technical lecture led by Jens Alfke, lead Couchbase Lite iOS developer. Walkthrough developing your first iOS application using Native APIs, and hear about what is to come for Couchbase Lite iOS.

In this webinar you will see:

An overview of the Couchbase Lite iOS API
A step-by-step demonstration on how to develop a iOS application with Couchbase Lite
A quick demo of a iOS app
An explanation of the future plans for Couchbase Lite iOS

Published in: Technology
1 Like
  • Be the first to comment

No Downloads
Total Views
On Slideshare
From Embeds
Number of Embeds
Embeds 0
No embeds

No notes for slide

Webinar - Developing with Couchbase Lite iOS

  1. 1. Developing  With   Couchbase  Lite  on  iOS Jens  Al9e jens@couchbase.com 10/29/13
  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/communi:es/couchbase-­‐lite
  5. 5. Download  Grocery  Sync github.com/couchbaselabs/Grocery-­‐Sync-­‐iOS
  6. 6. Plug  In  The  Framework option
  7. 7. Live  Demo
  8. 8. A  Tour  of  the  Code   and  the  API
  9. 9. Ini;aliza;on DemoAppDelegate.m:64        //  Initialize  Couchbase  Lite  and  find/create  my  database:          NSError*  error;          self.database  =  [[CBLManager  sharedInstance]  createDatabaseNamed:  kDatabaseName                                                                                                                                error:  &error];          if  (!self.database)                  [self  showAlert:  @"Couldn't  open  database"  error:  error  fatal:  YES];  
  10. 10. Manager,  Databases,  Documents CBLManager ! CBLDatabase  Database   CBLDocument  “doc1”   “db” “otherdb” { } “text”: “Vacuum”, “created”: “2013-10-08”, “check”: false Document   “doc1” CBLDocument   “doc2” CBLDocument   “doc3” thumb.jpg
  11. 11. Manager • Collec;on  of  named  databases   • Generally  a  singleton   Unless  you  run  on  mul:ple  threads   • Manages  database  storage  (local  directory)
  12. 12. Database • Namespace  for  documents   • Contains  views  and  their  indexes   • Contains  valida;on  func;ons   • Source  and  target  of  replica;on
  13. 13. Document • Has  unique  ID  within  its  database   • Contains  arbitrary*  JSON  object   *except  keys  that  start  with  “_”  are  reserved   There  is  no  explicit,  enforced  schema   Denormaliza:on  is  OK  —  use  arrays  or  dic:onaries   • May  contain  binary  aVachments   Data  blobs,  can  be  large,  tagged  with  MIME  type   • Versioned   Mul:-­‐Version  Concurrency  Control  (MVCC)   Every  update  creates  a  revision  ID  (based  on  digest  of  contents)   Revision  ID  history  is  stored
  14. 14. Ini;aliza;on DemoAppDelegate.m:64        //  Initialize  Couchbase  Lite  and  find/create  my  database:          NSError*  error;          self.database  =  [[CBLManager  sharedInstance]  createDatabaseNamed:  kDatabaseName                                                                                                                                error:  &error];          if  (!self.database)                  [self  showAlert:  @"Couldn't  open  database"  error:  error  fatal:  YES];  
  15. 15. Crea;ng  a  Database  View RootViewController.m:101 Not a U IView — a datab ase “view ” is like a n index.        //  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"];  
  16. 16. Views  &  Queries CBLDatabase   “db” function(doc) { emit(doc.created, doc.title); } map fu nction CBLView   View   “completed” “byDate” 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
  17. 17. Views • Map/Reduce  mechanism   Popular  in  other  NoSQL  databases   A  view  is  similar  to  index  in  rela:onal  database.   • App-­‐defined  map  func;on   Called  on  every  document   Can  emit  arbitrary  key/value  pairs  into  the  index   • Op;onal  reduce  func;on   Data  aggrega:on  /  grouping   • Func;ons  are  registered  as  na;ve  blocks/callbacks   Not  stored  as  JavaScript  in  “design  document”  (as  in  CouchDB)
  18. 18. Crea;ng  a  Database  View RootViewController.m:101 Not a U IView — a datab ase “view ” is like a n index.        //  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"];  
  19. 19. Driving  the  Table  from  a  View  Query RootViewController.m:101        //  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"; RootViewController.h:41 @property(nonatomic,  strong)  IBOutlet  UITableView  *tableView;   @property(nonatomic,  strong)  IBOutlet  CBLUITableSource*  dataSource;  
  20. 20. Queries • Basic  feature  set   Key  ranges,  offset/limit,  reverse,  group  by  key…   No  joins  or  fancy  sor:ng   but  compound  keys  (and  clever  emits)  allow  for  some  tricks   • LiveQuery  subclass   Monitors  database,  pushes  no:fica:ons   Uses  KVO  on  iOS,  can  drive  a  UITableView   • Upcoming  goodies!   Full-­‐text  indexing   Geo  (bounding-­‐box)  queries
  21. 21. Live  Queries  &  Table  Data  Sources key value “2013-­‐09-­‐30” “Pencil  shavings” “doc62” “2013-­‐10-­‐17” “Mangos” “doc82” “2013-­‐10-­‐17” “second” “doc83” view index docID } CBLQuery CBLLiveQuery CBLUI-­‐ TableSource data source
  22. 22. Driving  the  Table  from  a  View  Query RootViewController.m:101        //  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"; RootViewController.h:41 @property(nonatomic,  strong)  IBOutlet  UITableView  *tableView;   @property(nonatomic,  strong)  IBOutlet  CBLUITableSource*  dataSource;  
  23. 23. Wiring  Up  The  Table  View RootViewController.xib
  24. 24. Displaying  Table  Cells DemoAppDelegate.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   }  
  25. 25. Responding  To  Taps DemoAppDelegate.m:131 -­‐  (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];          }   }  
  26. 26. Adding  New  Items DemoAppDelegate.m:247 -­‐(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  untitledDocument];          NSError*  error;          if  (![doc  putProperties:  inDocument  error:  &error])  {                  [self  showErrorAlert:  @"Couldn't  save  new  item"  forError:  error];            
  27. 27. Dele;ng  Items DemoAppDelegate.m:191 -­‐  (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];          }   }
  28. 28. OK,  But  Where’s  The  Sync?
  29. 29. Crea;ng  Replica;ons DemoAppDelegate.m:291        //  Tell  the  database  to  use  this  URL  for  bidirectional  sync.          //  This  call  returns  an  array  of  the  pull  and  push  replication  objects:          NSArray*  repls  =  [self.database  replicateWithURL:  newRemoteURL  exclusively:  YES];          if  (repls)  {                  _pull  =  repls[0];                  _push  =  repls[1];                  _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];          }  
  30. 30. Replica;on Database   “db” Dir:   push   Remote:  hkp://server/db   Auth:   <token> Replica;on Replica;on Dir:   pull   Remote:  hkp://server/db   Auth:   <token> ns tio ica tif no
  31. 31. Replica;on • Each  Replica;on  is  one-­‐direc;onal  (push  or  pull)   • Replica;ons  can  be  one-­‐shot,  con;nuous  or  persistent   One-­‐shot:  Stops  when  complete.   Con:nuous:  Keeps  monitoring  changes  :ll  app  quits   Persistent:  Automa:cally  starts  again  on  next  relaunch   • Replicator  runs  in  a  background  thread   It  detects  online/offline,  handles  connec:on  errors,  retries…   You  just  see  document-­‐changed  or  query-­‐changed  no:fica:ons.   • Progress  is  observable  through  KVO  or  NSNo;fica;on
  32. 32. Monitoring  Replica;ons DemoAppDelegate.m:353 //  Called  in  response  to  replication-­‐change  notifications.  Updates  the  progress  UI.   -­‐  (void)  replicationProgress:  (NSNotificationCenter*)n  {          if  (_pull.mode==  kCBLReplicationActive  ||  _push.mode==  kCBLReplicationActive)  {                  //  Sync  is  active  -­‐-­‐  aggregate  progress  of  both  replications:                  unsigned  completed  =  _pull.completed  +  _push.completed;                  unsigned  total  =  _pull.total  +  _push.total;                  [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.error  ?  _pull.error  :  _push.error;          if  (error  !=  _syncError)  {                  _syncError  =  error;                  if  (error)                          [self  showErrorAlert:  @"Error  syncing"  forError:  error];  
  33. 33. Beyond  Grocery  Sync
  34. 34. Models List @interface Task : CBLModel ! @property NSString*title; @property NSDate* @property bool @property List* ! @end @interface List : CBLModel ! @property NSString* title; @property NSArray* members; ! @end Task created; checked; list; Task Task Document   “doc3” Document   “doc23” Document   “doc82” Document   “doc99”
  35. 35. Models • Kind  of  like  NSManagedObject,  but  simpler   • Map  JSON  to  na;ve  @proper;es   Scalar  types  (int,  bool…),  String,  Date,  Data  (blob)   References  to  other  doc  models   Arrays  of  the  above   • Proper;es  are  KV-­‐observable   • Models  provide  mutable  state   -­‐save:  writes  to  underlying  document   • No  query-­‐based  rela;on  support  (yet)
  36. 36. Represen;ng  Document  Types • There  are  no  tables  to  separate  different  record  types!   Conven:on  is  to  use  a  “type”  property   • Map  func;ons  can  pick  out  docs  with  the  right  type   if  (doc.type  ==  “item”)  emit(doc.created,  doc.text);
  37. 37. 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* @property bool @property List* ! @end created; checked; list;
  38. 38. Querying  With  Mul;ple  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”
  39. 39. Querying  With  Mul;ple  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”
  40. 40. Whew! hkp://docs.couchbase.com/couchbase-­‐lite/cbl-­‐ios/ hkp://couchbase.github.io/couchbase-­‐lite-­‐ios/docs/html/annotated.html hkps://github.com/couchbaselabs/Grocery-­‐Sync-­‐iOS
  41. 41. Coming  Up  Next! Tuesday,  November  5,  10:00AM  PST   “Developing  With  Android”
  1. A particular slide catching your eye?

    Clipping is a handy way to collect important slides you want to go back to later.