Working with Parse.com
This is now obsolete that Parse has(or will be by 2017) shutdown
I started working with Parse.com service because I needed a way to send push notifications to my iOS app that I’m building for Kids Yoga Speak, my wife’s project. I needed free and I needed simple. I didn’t want to have to learn how to setup a complete backend server to support Apple’s Push Notification Service requirements.
Implementing the push notifications turned out to be very easy thanks to the tutorials at Parse.
One registers with Parse via the SDK, and waits for a push. Couldn’t be easier!
dispatch_block_t parseRegistrationBlock = ^{
[self registerWithParse:launchOptions];
// Clear any badges on the app icon
// First check to see if any pushes have come while the app was in the background or not running
NSDictionary *pushNotification = [launchOptions valueForKey:UIApplicationLaunchOptionsRemoteNotificationKey];
[self handleBadge:pushNotification application:application];
// Register for push notifications
[application registerForRemoteNotificationTypes:UIRemoteNotificationTypeBadge |
UIRemoteNotificationTypeAlert |
UIRemoteNotificationTypeSound];
};
// Register for notifications and with Parse in background
dispatch_async([[kysDataModelManager sharedInstance] getAsyncQ], parseRegistrationBlock);
- I used a block and ran the registration on a background thread so that it wouldn’t slow the application launch. I don’t know if that is strictly needed and it is not shown this way in the tutorials.
- The important bit for push notification is line 10
Then, add this code to save the Apple token with the Parse backend.
- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)newDeviceToken
{
// Store the deviceToken in the current installation and save it to Parse.
PFInstallation *currentInstallation = [PFInstallation currentInstallation];
[currentInstallation setDeviceTokenFromData:newDeviceToken];
[currentInstallation saveInBackground];
}
What to do when push notifications come in is up to you, and you should read Apple’s documentation on the subject so you cover all the bases.
On the Parse web site, it’s super simple to send push notifications. Follow the instructions to register your app, and go from there. It really is easy.
Once I started using the Parse web interface for push notifications, I started thinking how I could use the Data Browser within the Parse ecosystem. Data Browser is a database with a very simple, friendly web frontend. Click and edit, buttons to remove and add rows, etc. It’s also schemaless, which means that I do not need to define my objects stored in the database before I start creating those objects. Rather, I just create on the fly.
What was a good use for the database in my app?
I decided that I could track which parts of my application were used by generating an object and shooting it up to Parse. Tracking metrics on how an app is used can help direct where new features should be focused. Even with a simple app it can be useful. I created a singleton to handle the calls to Parse, I won't include that here because that isn't interesting. However, when you want to log/create a metric datapoint, do the following...metric_1 = [PFObject objectWithClassName:@"metrics_A"];
[self.metric_1 incrementKey:@"count"];
[self.metric_1 incrementKey:@"someSpecialEventInYourApp"];
[self.metric_1 saveInBackground];
- Create a PFObject with your custom class name. This can be anything, but stay consistent with the name otherwise you will have a zillion tables in your database. What I did was use the same class name for events of a specific type.
- incrementKey:@“someKey” is used to increment the value of a column called @“someKey”
- saveInBackground tells the Parse SDK to save this object to Parse, but do it asynchronously.
After this is done, drive your app around and then visit Parse to take a look at the data objects you’ve created. Making sense of the metrics is another ball of string…
Dump PHP and MySQL!
Previous to Parse, I had written code, PHP and Objective C, to interface to a MySQL database containing promo codes for the app. The database had a list of valid codes, number of remaining uses, and what devices has already consumed a promo code. See this awesome [tutorial](http://www.raywenderlich.com/2941/how-to-write-a-simple-phpmysql-web-service-for-an-ios-app) for a step by step recipe for setting it up. While this configuration worked for me, it was cumbersome to have to edit PHP on the server and tinker with the MySQL database via the phpAdmin console with my webhost. Then I put it together with Parse.Parse has a feature called Cloud Code, javascript that runs on Parse servers and interacts with the Data Browser database object, and is remotely invoked via the Parse SDK. I knew nothing about how to do this when I started on this project at 3pm on a Saturday. Long story short, by 6pm I had the functionality of the PHP/MySQL juggernaut reproduced with a few lines of Parse JavaScript.
- In the web interface to Parse’s Data Browser, I added a new object called promoCode which contains columns for the name of the promo code and the number of uses for that code.
- In my iOS app, I added
``
[PFCloud callFunctionInBackground:@"promoCode" withParameters:[NSDictionary dictionaryWithObjectsAndKeys:code, @"name", uniqueIdentifier, @"device_id", nil]
block:^(id response, NSError *error){
[MBProgressHUD hideHUDForView:self.view animated:YES];
if ([response isKindOfClass:[NSDictionary class]])
{
NSDictionary *results = (NSDictionary *)response;
NSString *unlockCode = [results objectForKey:@"unlock_code"];
if ([unlockCode rangeOfString:@"com.kidsyogaspeak.unlock.premium"].location != NSNotFound)
{
self.textView.text = @"Premium Unlocked!";
[[kysInAppHelper sharedInstance] authorizePremium];
[self.purchaseTable reload];
}
else
{
self.textView.text = [NSString stringWithFormat:@"Unlock code: %@", unlockCode];
}
}
else
{
self.textView.text = response;
}
}];
-
this is the remote method call syntax. The name of my method is promoCode (line 1) and I pass in the name of the promo code the user entered and a unique identifier for this device (in my case, I use the MAC address).
-
The code block processes the response to the Cloud Code method call. ``
Parse.Cloud.define(“promoCode”, function (request, response) { var PromoCode = Parse.Object.extend(“promoCode”); var pc = new Parse.Query(PromoCode); pc.equalTo(“name”, request.params.name);
pc.first({ success: function(promo) { if (promo == null) { response.success("Unknown Promo Code"); } else { var count = promo.get("count"); if (count <= 0) { response.success("Code Expired"); } else { // Check if already used by this device var PromoCodeUsers = Parse.Object.extend("promoCodeUsers"); var codeUser = new Parse.Query(PromoCodeUsers); var did = request.params.device_id; var name = request.params.name; codeUser.equalTo("device_id", did); codeUser.equalTo("name", name); codeUser.first({ success: function(user) { if (user != null) { response.success("Code already used"); } else { // code valid, record it count -= 1; promo.set("count", count); promo.save (); var saveMe = new PromoCodeUsers(); saveMe.set("device_id", request.params.device_id); saveMe.set("name", request.params.name); saveMe.save(); response.success({ "unlock_code" : "com.appName.unlock.premium"}); } }, error: function (user) { response.error("Error 2"); } }); } } }, error: function(error) { response.error("Error 1"); } });
});
This code mines the database for the given promo code, checks to see if it is valid and still has uses left, then it checks to see if the user has already consumed this promo code. If all is well, the response is sent back to the calling app.
I’m thrilled that I discovered Parse and their services for indie developers like me. Their service has helped me add some valuable features to my app in a very short amount of time. If you need simple services like I did, you might as well check them out.