Debugging Core Data

This blog post is just a short overview of the tools that I am using when working with Core Data.

Launch Arguments

To enable launch arguments for your app select your target from the Xcode toolbar and select Edit Scheme. You’ll see this menu: Any argument passed on launch will override the current value in NSUserDefaults for the duration of execution.1 Here are some options if you’re using SQLite as your persistent store:

-com.apple.CoreData.SQLDebug [1,2,3]

This option allows you too see actual SQL statements sent to the persistent store used by Core Data. Verbosity of the output can be controlled by setting the value from 1 to 3. Higher the number more SQL output you’ll see.

-com.apple.CoreData.SyntaxColoredLogging 1

With this option you can turn on the syntax coloring.

-com.apple.CoreData.SQLiteDebugSynchronous [0,1,2]

Control the way in which data in a SQLite-based store is written to disk. With 0 disk switching is switched off. 1 means normal and 2 is the default.

-com.apple.CoreData.SQLiteIntegrityCheck 1

With this option SQLite store does extra integrity checking if set to 1.

-com.apple.CoreData.ThreadingDebug [1,2,3]

This option enables assertions to enforce Core Data’s multi-threading policy. Higher value enables more debugging.

SQLite

There are many tools available for viewing actual SQLite that is stored in application’s Documents directory. In the simulator .sqlite is located at: ~/Library/Application Support/iPhone Simulator/X/Applications/XXXX-XXXX-XXXX-XXXX/Documents where X is your deployment target.

To simplify the process you can download app called SimPholders. It is a small utility for fast access to your iPhone Simulator apps. Or you can use awesome debugging toolkit called PonyDebugger.

Generate Your Podfile

On March, 29th I attended a CocoaPods Bug Bash event. The main idea was to clean up any issues and remove duplicates in the CocoaPods repository.

Creativity, curiosity, execution.

After the Hackathon finished I said to myself, wouldn’t it be great if you could generate a Podfile with all your favourite third party libraries when you’re starting a new project. It would be similar to services like Ninite for bulk downloading multiple applications.

Because there is the CocoaPods search API and it was about time to say hello again to Ruby I started working on it.

I asked CocoaPods contributors what they thought about the idea, which served as a brief validation for me.

From mockup to actual product

I wanted a pretty simple workflow: search for libraries that you need to start working on your project. A dropdown with suggested libraries will appear. Select library. Repeat. The tags will appear bellow the search bar so that you know which libraries have been selected. Final step is one click away. It will generate and download a Podfile with your pods so you just need to pod install them!

Because I like nice and simple products, I asked a friend of mine if he could help me with design and logo.

He did the magic.

Cocoa Brewer

Before you go…

Check CocoaBrewer.org out! There’s a ton of things that can be improved. Feel free to contribute.

debugDescription

When I was preparing my talk about remote debugging toolset PonyDebugger at NSLondon I had a pre-presentation in front of my lovely co-workers. I was talking a lot about debugging and how to be efficient when doing this. After finished the talk I was asked many questions but this stood out…

Luka, why don’t you write code without bugs?

Good question, but that’s just how it is. We are all humans after all and we make mistakes sometimes. Or maybe the third party libraries we use are not polished enough and specific methods do not function properly so you need to debug.

Just a random model

So with an abundance of models in your project imagine that you have a model for Person

1
2
3
4
5
6
7
8
9
10
@interface LBPerson : NSObject

@property NSString *name;
@property NSString *surname;
@property NSUInteger age;
@property NSString *city;

- (id)initWithName:(NSString *)name Surname:(NSString *)surname Age:(NSUInteger)age City:(NSString *)city;

@end

You are fiddling around, debugging and inspecting the values that are held inside a newly created object.

1
LBPerson *luka = [[LBPerson alloc] initWithName:@"Luka" Surname:@"Bratos" Age:25 City:@"London"];

Let’s debug, yay!

Let’s do things like this and waste our time:

1
NSLog(@"%@", luka);

Output: 2014-03-25 21:53:28.488 Debug[6752:60b] <LBPerson: 0x8c6a110>

1
NSLog(@"%@", luka.name);

Output: 2014-03-25 21:55:06.740 Debug[6794:60b] Luka

This is not very useful. And it takes too much time to write these annoying NSLog’s.

The right way

If you take a look and dive into NSObject header file you will see these two methods:

1
2
3
- (NSString *)description;
@optional
- (NSString *)debugDescription;

In the iOS Developer Library, more specifically in Mac OS X Debugging Magic you can see the definition for description is:

All Cocoa objects (everything derived from NSObject) support a description method that returns an NSString describing the object.

But in most cases the default description is not enough. You can still get some information out but it can be done better.

debugDescription

You can take advantage of GBD or lldb debugger and use print-object or po. By default po will basically call the debugDescription method which by default invokes description method of the specified object.

You can decouple these by implementing debugDescription on your own.

1
2
3
4
- (NSString *)debugDescription
{
  return [NSString stringWithFormat:@"Name: %@\nSurname: %@\nAge: %d\nCity: %@\n", self.name, self.surname, self.age, self.city];
}

End result:

Share Code Snippets With Ease

Update – Snippet was rewritten in Python! See this.

GitHub Gist is a nice way to share a snippet of code or a block of text with other people. Gists are under Git revision control so it is very easy to view and follow changes, other users can fork them and they are under SSL encryption for private sharing.

Overview

Snippet is a Mac OS X Service made with Automator and powered by a small Ruby script for uploading code snippets to GitHub Gist with the ease of a simple right-click.

Implementation

Implementation was pretty straightforward. Gists can be created for anonymous users without a token. Code bellow will create private Gist named file1.txt with content Hello World!. We can optionally add a description and set visibility of Gist to public or private. The default is private.

1
2
3
curl -X POST \
--data-binary '{"files": {"text.txt": {"content": "Hello World!"}}}' \
https://api.github.com/gists

I used Automator workflow with Shell Script and Ruby to achieve my goal with the help of a simple Ruby script that will take selected text, create an API call and parse the URL value returned by the GitHub API and copy it to the clipboard.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
require 'json'
require 'net/http'

uri = URI("https://api.github.com/gists")
data = { 'files' => { 'snippet' => { 'content' => ARGV[0] }}}

request = Net::HTTP::Post.new(uri.path)
request.body = data.to_json

response = Net::HTTP.start(uri.hostname, uri.port, :use_ssl => true) do |http|
  http.request(request)
end

my_hash = JSON.parse(response.body)
IO.popen('pbcopy', 'w') { |f| f << my_hash["html_url"] }

Installation

Double-click on Snippet.workflow and click on the Install button. This will install Snippet into ~/Library/Services folder.

Install

You can uninstall by deleting it from the same folder.

If you want to assign a keyboard shortcut to Snippet service you can do this easily by assigning a key in System Preferences -> Keyboard -> Shortcuts -> Services.

Usage

Select code and right-click. Snippet is located under Services menu. When you use it, it will automatically upload selected text to GitHub Gist and it will copy generated URL to your clipboard so you can share instantly.

Snippet

Requirenments

Ruby 1.9.2+ or gem install json.

You can download the project here. Follow me on twitter.

A/B Testing iOS Apps Like a Pro

A/B testing is commonly used in several forms of advertising predominantly in online marketing and web development. It is often called split-testing because sample of users is usually split in two halves or variants A and B.

Variants A (baseline) and B are compared which differ one from another in small aspect that might impact user’s behaviour. Point of A/B testing is finding the predominant version that will result in higher conversion rates.

Say hello to Bestly

Bestly offers an easy way to add A/B testing and staged rollouts to native mobile applications.

The easiest way to add Bestly into your iOS project is using CocoaPods. Simply create new Podfile or add to existing one pod 'Bestly' and run pod install in your terminal.

Then you need to add the following import to your .pch or AppDelegate.m

1
#import <Bestly/Bestly.h>

Sign into Bestly and create a new app. Paste the following line to your application:didFinishLaunchingWithOptions: and replace APP_KEY with key that was generated on the website.

1
[Bestly setupWithKey:@"APP_KEY"];

Creating your first controlled experiment

You can run experiment with two A, B or three A, B, C variants.

In this example I will show you the basic usage with two variants.

1
2
3
4
5
6
7
8
9
10
11
12
13
/**
 * Call this whenever you'd like to run an experiment.
 * @param experimentID The experiment ID corresposding to the
 * experiment that you'd like to run.
 * @param a Experiment variation A. This is the baseline
 * variation. Please note that in any sort of failure
 * (e.g. lack of internet connectivity),
 * this will be the variation that is run.
 * @param b Experiment variation B.
 */
+ (void)runExperimentWithID:(NSString *)experimentID
                          A:(void(^)(void))a
                          B:(void(^)(void))b;

Let’s say that we want to A/B test a button with different title. We’ve got two variants:

  • A: Hi!
  • B: Hello!

Paste this code and replace EXPERIMENT_ID with Experiment ID that you can find on the website.

1
2
3
4
5
6
[Bestly runExperimentWithID:@"EXPERIMENT_ID" A:^{
    // Insert your testing logic here...
    [self.testButton setTitle:@"Hi!" forState:UIControlStateNormal];
} B:^{
    [self.testButton setTitle:@"Hello!" forState:UIControlStateNormal];
}];

Place the following code to the UIButton action method so you can see if variation’s goal was reached.

1
2
3
- (IBAction)testButtonTapped:(id)sender {
    [Bestly goalReachedForExperimentID:@"EXPERIMENT_ID"];
}

After playing around a little bit on the iPhone simulator we can see that the conversion rate is higher for the button with the title Hello. However to get accurate results, the number of users needs to be bigger than 100 per variation.

Conversion rate and change over baseline

For each variation conversion rate is calculated as:

Where x is number of conversions and n is number of people that have viewed variation.

Formula for calculating change over baseline is basically substraction of conversion B and A divided by conversion value of A.

Update

The response for this blog post was immense. I was lucky enough to get on the the front page of Hacker News resulting in almost 3000+ visitors from 70+ countries in one day—not too bad.

I also received a very special email. It was from James, the founder of Bestly. He thanked me for writing the post and informed me that a new version of Bestly is coming out.

What changed?

  1. There’s a new version of Bestly SDK on GitHub
  2. You don’t need to use [Bestly goalReachedForExperimentID:@""]; anymore1.
  3. Design changes on the dashboard
  4. Other things such as aliases

You can download the project here. Follow me on twitter.


  1. You can send any event you want to track and it wil be tracked for every experiment.