StackMob <--> Core Data Coding Practices
StackMob <--> Core Data Support Specifications
The goal of the iOS SDK is to provide the best experience possible for developing an application that uses StackMob as a cloud backend.
### How is the new iOS SDK different from the older version?
The biggest difference between the new and the current SDKs is our use of Core Data as a foundation for the new SDK. We believe Core Data is a powerful approach for integrating StackMob’s REST based API into an iOS application.
That being said, we understand that Core Data is not suitable for every application, which is why we still expose the complete REST based API for making create, read, update and delete calls and performing queries on your database.
### Why base the new SDK on Core Data? Our number one goal is to create a better experience. Core Data allows us to place a familiar wrapper around StackMob REST calls and Datastore API. iOS developers can leverage their existing knowledge of Core Data to quickly integrate StackMob into their applications. For those interested in sticking to the REST-based way of making requests, we provide the full Datastore API as well.
### Already know Core Data? Then you already know how to use StackMob!
All you need to do to get started with StackMob is initialize an instance of SMClient and grab the configured managed object context by following the instructions in Initialize an SMClient.
### What Core Data functionality is supported with our integration?
Check out the StackMob <--> Core Data Support Specifications.
### Reporting issues or feature requests
You can file issues through the GitHub issue tracker.
### Still have questions about the new iOS SDK?
Email us at [email protected].
If you don't already have the StackMob SDK imported into your application, get started with StackMob.
The fundamental class for StackMob is SMClient. From an instance of this class you have access to a configured managed object context and persistent store coordinator as well as a REST-based Datastore. Check out the class reference for SMClient for more information. Let's see how to initialize our SMClient
:
Wherever you plan to use StackMob, add #import "StackMob.h"
to the header file.
Create a variable of class SMClient
, most likely in your AppDelegate file where you initialize other application wide variables, and initialize it like this:
// Assuming your variable is declared SMClient *client;
client = [[SMClient alloc] initWithAPIVersion:@"YOUR_API_VERSION" publicKey:@"YOUR_PUBLIC_KEY"];
For YOUR_API_VERSION, pass @"0" for Development, @"1" or higher for the corresponding version in Production.
If you haven't found your public key yet, check out Manage App Info under the App Settings sidebar on the Dashboard page.
There are two ways to persist data to StackMob:
- Core Data
- Lower Level Datastore API
StackMob recommends using Core Data… it provides a powerful and robust object graph management system that otherwise would be a nightmare to implement. Although it may have a reputation for being pretty complex, the basics are easy to grasp and understand. If you want to learn the basics, check out Core Data References below.
The three main pieces of Core Data are instances of:
- NSManagedObjectContext - This is what you use to create, read, update and delete objects in your database.
- NSPersistentStoreCoordinator - Coordinates between the managed object context and the actual database, in this case StackMob.
- NSManagedObjectModel - References a file where you defined your object graph.
Access a StackMob-configured managed object context
You can obtain a managed object context configured from your SMClient instance like this:
// aManagedObjectModel is an initialized instance of NSManagedObjectModel
// client is your instance of SMClient
SMCoreDataStore *coreDataStore = [client coreDataStoreWithManagedObjectModel:aManagedObjectModel];
// assuming you have a variable called managedObjectContext
self.managedObjectContext = [coreDataStore contextForCurrentThread];
Use this instance of NSManagedObjectContext for the current thread you are on. You can always call contextForCurrentThread at any time to obtain an initialized managed object context if you are not sure what thread you are on.
Saving in the background
When you are ready to save your context, the NSManagedObjectContext+Concurrency class offers asynchronous callback-based methods that perform off of the main thread, as well as methods that wait for the save to complete before continuing execution. Both take advantage of the child / parent context pattern for optimized performance.
Fetching in the background
When you want to fetch objects, the NSManagedObjectContext+Concurrency class offers asynchronous callback-based methods that perform off of the main thread, as well as methods that wait for the fetch to complete before continuing execution. You also have the option of returning instances of NSManagedObject or NSManagedObjectID. Both take advantage of a pattern involving fetching object IDs from a private queue context and passing those IDs to the calling context.
Important: Make sure you adhere to the StackMob <--> Core Data Coding Practices!
If you want to make direct REST-based calls to the Datastore, check out the SMDataStore class.
Included with version 1.2.0+ of the SDK is a caching system built in to the Core Data Integration to allow for local fetching of objects which have previously been fetched from the server. See the SMCoreDataStore class reference for details on how to turn on the cache, set the cache policy, manually purge the cache, etc.
SMClient provides all the necessary methods for user authentication.
The default schema to use for authentication is user, with username and password fields.
You can set these using setters or the extended SMClient
initialization method.
For more information see The User Schema and User Authentication sections of the SMClient Class Reference.
Push Notification support comes built into the iOS SDK, which can be downloaded from the SDK Downloads Page.
If you will only be using StackMob for Push Notifications, you can download the standalone version which only includes push support.
All the details on how to set up your application for push can be found in the iOS Push Notifications Tutorial.
While the SDK has built in support for returning errors when there is no network connection, SMNetworkReachability provides an interface for developers to manually check if the device is connected to the network and can in turn reach StackMob. All the details, including how to subscribe to notifications and set blocks to be executed when the network status changes, can be found in the SMNetworkReachability class reference.
### Error Codes
The SMError
class translates numeric error codes into readable errors, so you know what went wrong. SDK specific error codes have also been defined for even more specific errors. Check out the Error Code Translations page for all the details.
### Debugging
The iOS SDK gives developers access to two global variables that will enable additional logging statements when using the Core Data integration:
- SM_CORE_DATA_DEBUG - In your AppDelegate's
application:DidFinishLaunchingWithOptions:
method, include the lineSM_CORE_DATA_DEBUG = YES;
to turn on log statements fromSMIncrementalStore
. This will provide information about the Datastore calls to StackMob happening behind the scenes during Core Data saves and fetches. The default isNO
. - SM_MAX_LOG_LENGTH - Used to control how many characters are printed when logging objects. The default is 10,000, which is plenty, so you will almost never have to set this. The only time you will see the string representation of an object truncated is when you have an Attribute of type String that maps to a field of type Binary on StackMob, because you are sending a string containing the binary of the image, etc. String representations of objects that have been truncated end with <MAX_LOG_LENGTH_REACHED>.
There are a few coding practices to adhere to as well as general things to keep in mind when using StackMob with Core Data. This allows StackMob to seamlessly translate to and from the language that Core Data speaks.
First, a table of how Core Data, StackMob and regular databases map to each other:
Core Data | StackMob | Database |
---|---|---|
Entity | Schema | Table |
Attribute | Field | Column |
Relationship | Relationship | Reference Column |
General Information:
- Entity Names: Core Data entities are encouraged to start with a capital letter and will translate to all lowercase on StackMob. Example: Superpower entity on Core Data translates to superpower schema on StackMob.
- Property Names: Core Data attribute and relationship names are encouraged to be in camelCase, but can also be in StackMob form, all lowercase with optional underscores. Acceptable formats are therefore yearBorn, year_born, or yearborn. All camelCased names will be converted to and from their equivalent form on StackMob, i.e. the property yearBorn will appear as year_born on StackMob.
- StackMob Schema Primary Keys: All StackMob schemas have a primary key field that is always schemaName_id, unless the schema is a user object, in which case it defaults to "username" but can be changed manually by setting the userPrimaryKeyField property in your
SMClient
instance.
Coding Practices for successful app development:
-
Entity Primary Keys: Following #3 above, each Core Data entity must include an attribute of type string that maps to the primary key field on StackMob. Acceptable formats are _schemaName_Id or schemaName_id. If the managed object subclass for the Entity inherits from
SMUserManagedObject
, meaning it is intended to define user objects, you may use either of the above formats or whatever lowercase string with optional underscores matches the primary key field on StackMob. For example: entity Soda should have attribute sodaId or soda_id, whereas your User entity primary key field defaults to @"username". -
Assign IDs: When inserting new objects into your managed object context, you must assign an id value to the attribute which maps to the StackMob primary key field BEFORE you make save the context. 90% of the time you can get away with assigning ids like this:
// assuming your instance is called newManagedObject [newManagedObject setValue:[newManagedObject assignObjectId] forKey:[newManagedObject primaryKeyField]]; // now you can save your context
The other 10% of the time is when you want to assign your own ids that aren't unique strings based on a UUID algorithm. A great example of this is user objects, where you would probably assign the user's name to the primary key field. In that case, your code might look more like this:
// assuming your instance is called newManagedObject [newManagedObject setValue:@"bob" forKey:[newManagedObject primaryKeyField]]; // now you can save your context
-
NSManagedObject Subclasses: Creating an NSManagedObject subclass for each of your entities is highly recommended for convenience. You can add an init method to each subclass and include the ID assignment line from above - then you don't have to remember to do it each time you create a new object!
-
SMUserManagedObject Subclasses: After creating an NSManagedObject subclass for an entity that maps to a user object on StackMob, change the inherited class to SMUserManagedObject. This class will give you a method to securely set a password for the user object, without directly setting any attributes in Core Data. It is important to make sure you initialize an SMUserManagedObject instance properly.
-
Create and Save Objects Before Relating Them: Before saving updated objects and depending on the merge policy, Core Data will grab persistent values from the server to compare against. Problems arise when a relationship is updated with an object that hasn't been saved on the server yet. To play it safe, try to create and save objects before relating them to one another.
- SMClient - Gives you access to everything you need to communicate with StackMob.
- SMCoreDataStore - Gives you access to configured NSManagedObjectContext instances to communicate with StackMob directly through Core Data. Includes the necessary methods for interacting with the cache.
- NSManagedObjectContext+Concurrency - Provides methods to save and fetch in the background.
- SMDataStore - Gives you access to make direct REST-based calls to StackMob.
- SMRequestOptions - When making direct calls to StackMob, an instance of SMRequestOptions gives you request configuration options.
- SMUserManagedObject - The managed object subclass that defines your users should inherit from SMUserManagedObject.
- SMCustomCodeRequest - Starting place for making custom code calls.
- SMBinaryDataConversion - Convert NSData to NSString for persisting to a field on StackMob with type Binary Data (s3 Integration).
- SMPushClient - Guide to sending push notifications.
- Error Code Translations - A copy of what's listed in
SMError
, this shows all the readable typedefs for specific error codes.
You can find all the iOS SDK tutorials at our Dev Center.
- Core Data Primer eBook - StackMob has put together an eBook based on one of our tutorial series which walks you through the full implementation of an app that uses Core Data.
- Getting Started With Core Data - Ray Wenderlich does a great tutorial on the basics of Core Data.
- iPhone Core Data: Your First Steps - Well organized tutorial on Core Data.
- Introduction To Core Data - Apple's Core Data Programming Guide
- Introduction To Predicates - Apple's Predicates Programming Guide