RSS

Learning Core Data for iOS

As you progress through the chapters of Learning Core Data for iOS, you’ll build a fully functional Core Data App from scratch. Each key piece of information will be explained in succinct detail so you can apply what you’ve learned straight away. The sample application built throughout this book has been especially designed to demonstrate as many aspects of Core Data as possible. At the same time it is a completely real-world application available on the App Store today. This should make it easier to absorb concepts as you relate them to real-life scenarios.

The arrival of iOS 7 has seen major improvements in the speed, reliability, and simplicity of Core Data integration with iCloud. I encourage anyone who has previously given up on this technology to give it another go, because you will be pleasantly surprised.

Scroll to the bottom of this page for the complete source code!

Chapter Outline

  • Chapter 1, “Your First Core Data Application”—The groundwork is laid as the fundamental concepts of Core Data are introduced. You’ll be shown what Core Data is, and just as importantly what it isn’t. The first helper class CoreDataHelper is created as Core Data integration with an existing application is demonstrated with Grocery Dude.
  • Chapter 2, “Managed Object Model Basics”—Data models are introduced as parallels are drawn between traditional database schema design and Core Data. You’ll be shown how to configure a basic managed object model as entities and attributes are discussed, along with accompanying advice on choosing the right data types. Inserting, fetching, filtering, sorting and deleting managed objects is also covered and followed up with an introduction to fetch request templates.
  • Chapter 3, “Managed Object Model Migration”—Experience lightweight migration, default migration, and using a migration manager to display migration progress. Learn how to make an informed decision when deciding between migration options for your own applications and become comfortable with the model versioning capabilities of Core Data.
  • Chapter 4, “Managed Object Model Expansion”—The true power of a relational data model is unlocked as different types of relationships are explained and added to Grocery Dude. Other model features such as abstract and parent entities are also covered, along with techniques for dealing with data validation errors.
  • Chapter 5, “Table Views”—The application really comes to life as Core Data is used to drive memory efficient and highly performing table-views using a fetched results controller. Of course, most of the generic legwork is put into a reusable table-view controller subclass called CoreDataTVC. By dropping this class into your own applications, you can easily deploy Core Data driven table-views yourself.
  • Chapter 6, “Views”—Working with managed objects takes a front seat as you’re shown how to pass them around the application. Objects selected on a table-view are passed to a second view ready for editing. The editing interface is added to Grocery Dude demonstrating how to work with objects and then save them back to the persistent store.
  • Chapter 7, “Picker Views”—As a nice touch, Core Data driven picker-views are added to the editing views. Picker-views allow the user to quickly assign existing items to a unit of measurement, home location or shop location. A special reusable text-field subclass called CoreDataPickerTF is introduced, which replaces the keyboard with a Core Data picker-view whenever an associated text-field is tapped.
  • Chapter 8, “Pre-loading Data”—Techniques for generating a persistent store full of default data from XML are explained and demonstrated in this chapter as the generic CoreDataImporter helper class is introduced. Once you have a persistent store to include with a shipping application, you’ll then be shown how to determine whether a default data import is required or even desired by the user.
  • Chapter 9, “Deep Copy”—A highly flexible and fine-grained alternative to migratePersistentStore, deep copy, allows you to copy objects and relationships from selected entities between persistent stores. In this chapter, the CoreDataImporter helper class is enhanced with the deep copy capability.
  • Chapter 10, “Performance”—Gain experience with Instruments as you identify and eliminate performance issues caused by the common pitfalls of a Core Data application. The camera functionality is introduced to highlight these issues and demonstrates just how important good model design is to a well performing application.
  • Chapter 11, “Background Processing”—Top-notch performance requires intensive tasks be offloaded to a background thread. Learn just how easy it is to run processes in the background as the example of photo thumbnail generation is added with the new generic helper class called Thumbnailer. Also learn how to keep memory usage low with another helper class, called Faulter.
  • Chapter 12, “Search”—Learn how to handle twin fetched results controllers in the one table-view as you implement efficient search in CoreDataTVC.
  • Chapter 13, “Backup and Restore”—Create backups and synchronize them to Dropbox using their Sync API. Restore data to any device using the same Dropbox account at the touch of a button.
  • Chapter 14, “iCloud”—Enjoy the easiest, most reliable Core Data integration with iCloud yet. Handle multiple accounts and varying preferences on using iCloud without missing a beat.
  • Chapter 15, “Taming iCloud”—Take iCloud integration to the next level with entity level seeding and unique object de-duplication. Accurately emulate first time iCloud use by resetting ubiquitous content globally, the right way.
  • Chapter 16, “Web Service Integration”—Enable collaboration as cross-platform data sharing between multiple users is introduced with StackMob. StackMob have one of the best free Backend-as-a-Service (BaaS) offerings available, and their iOS API is native to Core Data.

All Source Code

LearningCoreDataForiOS_AllSourceCode.zip

Source Code By Chapter

Chapter Source Code
Appendix A – Preparing Grocery Dude for Chapter 1 GroceryDude-AfterAppendixA.zip
Chapter 1 – Your First Core Data Application GroceryDude-AfterChapter01.zip
Chapter 2 – Managed Object Model Basics GroceryDude-AfterChapter02.zip
Chapter 3 – Managed Object Model Migration GroceryDude-AfterChapter03.zip
Chapter 4 – Managed Object Model Expansion GroceryDude-AfterChapter04.zip
Chapter 5 – Table Views GroceryDude-AfterChapter05.zip
Chapter 6 – Views GroceryDude-AfterChapter06.zip
Chapter 7 – Picker Views GroceryDude-AfterChapter07.zip
Chapter 8 – Pre-loading Data GroceryDude-AfterChapter08.zip
Chapter 9 – Deep Copy GroceryDude-AfterChapter09.zip
Chapter 10 – Performance GroceryDude-AfterChapter10.zip
Chapter 11 – Background Processing GroceryDude-AfterChapter11.zip
Chapter 12 – Search GroceryDude-AfterChapter12.zip
Chapter 13 – Backup and Restore GroceryDude-AfterChapter13.zip
Chapter 14 – iCloud GroceryDude-AfterChapter14.zip
Chapter 15 – Taming iCloud GroceryDude-AfterChapter15.zip
Chapter 15 – Easy iCloud EasyiCloud.zip
Chapter 15 – Generic Core Data Classes Generic Core Data Classes.zip … Please read CoreDataHelper.h for usage instructions
Appendix B – Preparing Grocery Cloud for Chapter 16 GroceryCloud-AfterAppendixB.zip
Chapter 16 – Web Service Integration GroceryCloud-AfterChapter16.zip
Be Sociable, Share!
     

    187 Responses to Learning Core Data for iOS

    1. Arlene

      October 8, 2014 at 9:20 am

      Hello Tim, I’m totally new at this but having bought your book somehow makes me think that I can actually do this! I would like to import a .csv (in email attachment) into an app, where users can then work with the list. Database structure is already defined. I just wish to import the data from a .csv. Is this covered anywhere in your book? I can’t seem to find this topic. Not even in Pre-Loading. Thank you SO SO MUCH.
      -Arlene

       
      • Tim Roadley

        October 8, 2014 at 9:33 am

        Hi Arlene, thanks for buying my book!

        You’re right, I don’t cover import from .csv, only from XML and a persistent store. The concept will be pretty much the same though, you’ll just need to find a way to read in the csv and map stuff you find to the managed objects. There are a bunch of examples available on the internet from the quick search I’ve just performed.

         
        • Arlene

          October 8, 2014 at 10:04 am

          Which chapter in the book to find the “XML/persistent store” info? I want to be sure I’m getting this right :-) Thanks, I will search the net diligently. Last question, would you recommend Python to read in the .csv, and convert to XML? (Have you authored a book on Python?)

           
      • Tim Roadley

        October 8, 2014 at 10:09 am

        Check out the “Importing from XML” section of Chapter 8 (Page 193).

        It depends on what you’re trying to do I guess. What is the purpose of the csv file? I mean, is it a backup file, are you just trying to load default data or something else?

         
        • Arlene

          October 8, 2014 at 10:15 am

          Thank you.

          Upon installation, each app user initially will need to load their spreadsheet of names, id#, rank, phone number, date of initiation. The goal is really just a small searchable list, which can remain on their phones. It does not need to be shared with any other user anywhere. So, it’s not Default Data, or a Backup file. It’s the user’s own data. Does this make it easier to code?

           
        • Tim Roadley

          October 8, 2014 at 12:21 pm

          So basically you need to give users an easy way to import their own data. Assuming you can get the csv file on to the device somehow I’d look in to something like this: https://github.com/davedelong/CHCSVParser

          I haven’t used that myself though, it’s just where I’d start.

           
        • Arlene

          October 9, 2014 at 5:17 am

          Got it. Thank you very much. :-)))

           
    2. Terrence R.

      October 10, 2014 at 1:04 am

      HI Tim. I’ve used your tutorials and would like to purchase your book. However, the apps I’ve made with your tutorials are not working with IOS 8 and the latest Xcode. I downloaded the source code for some of the chapter in the book and they too are not working with the iPhone 6 and 6 plus simulators I get multiple errors and (Though they do work with iPhone 5 and earlier). Is there an update that I am missing? I Thank you!

       
    3. Zachary Fisher

      October 25, 2014 at 10:55 pm

      Great book! It has helped tremendously. Having an issue that I think is iOS 8 related. I have a large xml file that users can import part of as they see fit. When I import small groups, it writes to the core data store just fine. When I import larger groups, it starts throwing this error on random items: [PFUbiquityFilePresenter processPendingURLs]_block_invoke(439): CoreData: Ubiquity: Librarian returned a serious error for starting downloads Error Domain=BRCloudDocsErrorDomain Code=5 “The operation couldn’t be completed. (BRCloudDocsErrorDomain error 5 – No document at URL)” – – My googling has led me to believe it has something to do with the new randomized directories that iOS 8 uses for the app directories. It’s during the parser operation, which logs: START PARSE OF /Users/zacharyfisher/Library/Developer/CoreSimulator/Devices/4B70FCFC-4704-4C83-B848-0D52D833E28A/data/Containers/Bundle/Application/6901B469-58F3-485F-8D73-D548ADC6F8EB/Toy Collector 2 iCloud Reset.app/DefaultData.xml – then it successfully “adds” some items and randomly throws the error on others. the log error is pretty log… I’d be happy to share the whole text if that might help – any thoughts on how to fix? It appears to be blocking the iCloud/Core data syncing.

      Thanks,
      Zack

       
      • Zachary Fisher

        October 28, 2014 at 12:40 am

        It seems to be iOS 8 specific. Perhaps something needs to be updated with the coredatahelper or coredataimporter classes to work in iOS 8? Thanks

         
    4. Koen van der Drift

      November 2, 2014 at 11:19 pm

      Does anyone have a recommendation for a StackMob alternative – it is no longer available.

       
    5. Rick Michaud

      November 5, 2014 at 2:07 pm

      Hi Tim,

      I’m having a bit of a snag on chapter 13 when I test the “unlink from dropbox” selection on the action sheet. After selecting this item I get the following output in the console:

      2014-11-04 22:34:05.604 Grocery Dude[4413:3481093] Presenting view controllers on detached view controllers is discouraged .
      2014-11-04 22:34:05.605 Grocery Dude[4413:3481093] Running DropboxTableViewController ‘viewWillAppear:’
      2014-11-04 22:34:07.265 Grocery Dude[4413:3481093] Running DropboxTableViewController ‘viewWillDisappear:’
      2014-11-04 22:34:08.465 Grocery Dude[4413:3481093] Running DropboxTableViewController ‘viewWillAppear:’
      2014-11-04 22:34:14.759 Grocery Dude[4413:3481093] Linking to Dropbox…
      2014-11-04 22:34:15.352 Grocery Dude[4413:3481093] Running DropboxTableViewController ‘viewWillDisappear:’
      2014-11-04 22:34:52.076 Grocery Dude[4413:3481093] Linked to Dropbox!
      2014-11-04 22:34:52.077 Grocery Dude[4413:3481093] Running DropboxTableViewController ‘viewWillAppear:’
      2014-11-04 22:46:03.889 Grocery Dude[4413:3553648] [ERROR] err: client.cpp:40: shutdown: client has been shutdown
      2014-11-04 22:46:03.890 Grocery Dude[4413:3553648] [ERROR] err: client.cpp:40: shutdown: client has been shutdown
      2014-11-04 22:46:03.891 Grocery Dude[4413:3553648] *** Terminating app due to uncaught exception ‘DBException’, reason: ‘DBException: SHUTDOWN: client.cpp:40: client has been shutdown {-[DBFilesystem listFolder:error:]}’
      *** First throw call stack:
      (
      0 CoreFoundation 0x02b01946 __exceptionPreprocess + 182
      1 libobjc.A.dylib 0x0278aa97 objc_exception_throw + 44
      2 Grocery Dude 0x000e187c _Z13dbx_translatePKcRKN7dropbox11checked_errEPU15__autoreleasingP7DBError + 0
      3 Grocery Dude 0x000eb354 -[DBFilesystem listFolder:error:] + 361
      4 Grocery Dude 0x0008b6cf __36-[DropboxTableViewController reload]_block_invoke + 191
      5 libdispatch.dylib 0x0354730a _dispatch_call_block_and_release + 15
      6 libdispatch.dylib 0x03567e2f _dispatch_client_callout + 14
      7 libdispatch.dylib 0x0355010f _dispatch_root_queue_drain + 634
      8 libdispatch.dylib 0x0355184a _dispatch_worker_thread3 + 115
      9 libsystem_pthread.dylib 0x038c3296 _pthread_wqthread + 724
      10 libsystem_pthread.dylib 0x038c0eea start_wqthread + 30
      )
      libc++abi.dylib: terminating with uncaught exception of type DBException

      My suspicion is that when the [self reload] is called, the reload method attempts to list the items in dropbox which fails because its now unlinked. While the reload tries to ignore any errors the underlying framework raises this exception.

      Not sure if you’ve seen this happen but I’ll try to code up a workaround.

       
    6. Michele Damato

      November 8, 2014 at 2:26 am

      I found this little trick to prevent the app crashes : I’m going to simply check if the account is valid or not.

      DBAccount *account = [[DBAccountManager sharedManager] linkedAccount];
      if (account.linked) {
      dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^() {
      NSArray *actualContents = [[DBFilesystem sharedFilesystem] listFolder:[DBPath root] error:nil];
      NSMutableArray *updatedContents = [NSMutableArray arrayWithArray:actualContents];

      // Don’t list folders
      NSMutableArray *folders = [NSMutableArray new];
      for (DBFileInfo *info in updatedContents) {
      if (info.isFolder) {[folders addObject:info];}
      }
      [updatedContents removeObjectsInArray:folders];

      // Don’t list files that don’t end with ‘Stores.zip’
      NSMutableArray *notValid = [NSMutableArray new];
      for (DBFileInfo *info in updatedContents) {
      if (![[[info path] stringValue] hasSuffix:@”Stores.zip”]) {
      NSLog(@”Not listing invalid file: %@”, [[info path] stringValue]);
      [notValid addObject:info];
      }
      }
      [updatedContents removeObjectsInArray:notValid];

      [updatedContents sortUsingFunction:sort context:NULL];
      dispatch_async(dispatch_get_main_queue(), ^() {
      self.contents = updatedContents;
      _loading = NO;
      [self.tabella_righe reloadData];
      [self refreshStatus];
      });
      });
      }

       
    7. Rick Michaud

      November 9, 2014 at 11:52 am

      Thanks Michele, your trick helped. I tweaked it some more to also clear out the tableView when the unlink action was called. Here is my updated reload method:

      – (void)reload {
      [self refreshStatus];
      if (_loading) return;

      DBAccount *account = [[DBAccountManager sharedManager] linkedAccount];
      if (account.linked) {
      _loading = YES;
      dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^() {
      NSArray *actualContents =[[DBFilesystem sharedFilesystem] listFolder:[DBPath root] error:nil];

      NSMutableArray *updatedContents = [NSMutableArray arrayWithArray:actualContents];

      // Don’t list folders
      NSMutableArray *folders = [NSMutableArray new];
      for (DBFileInfo *info in updatedContents) {
      if (info.isFolder) {[folders addObject:info];}
      }
      [updatedContents removeObjectsInArray:folders];

      // Don’t list files that don’t end with ‘Stores.zip’
      NSMutableArray *notValid= [NSMutableArray new];
      for (DBFileInfo *info in updatedContents) {
      if (![[[info path] stringValue] hasSuffix:@”Stores.zip”]) {
      NSLog(@”Not listing invalid file: %@”, [[info path] stringValue]);
      [notValid addObject:info];
      }
      }
      [updatedContents removeObjectsInArray:notValid];

      [updatedContents sortUsingFunction:sort context:NULL];
      dispatch_async(dispatch_get_main_queue(), ^() {
      self.contents = updatedContents;
      _loading = NO;
      [self.tableView reloadData];
      [self refreshStatus];
      });
      });
      } else {

      NSMutableArray *emptyContents = nil;
      self.contents = emptyContents;
      [self.tableView reloadData];
      _loading = false;
      }
      }

       
      • Sean Bergin

        December 2, 2014 at 3:00 am

        Thanks Michelle and Rick – hopefully Tim will read this and update the source code.

         
    8. Podster

      December 5, 2014 at 4:46 pm

      How would you convert the below cdh to Swift?

      – (CoreDataHelperExtension*)cdh {
      //NSLog(@”Running %@ ‘%@'”, self.class, NSStringFromSelector(_cmd));
      //NSLog(@”_coreDataHelperExtension %@”, _coreDataHelperExtension);
      if (!_coreDataHelperExtension) {
      // static dispatch_once_t predicate;
      // dispatch_once(&predicate, ^{
      _coreDataHelperExtension = [CoreDataHelperExtension new];
      // });
      [_coreDataHelperExtension setupCoreData];
      }

      return _coreDataHelperExtension;
      }

      Thank you.

       
    9. David

      December 16, 2014 at 1:19 pm

      Tim, I have a question about moving from tableview to the object view in chapter 6. Why do we pass the NSManagedObjectID to the view and then retrieve the object from the ID, rather than just passing the object itself? Especially when editing details of a new object that has been just created, since it seems that the objectID can change until the context is saved?

       

    Leave a Reply