On the day the first iPad came out, I released the first version of Ghostwriter Notes — A handwritten notes taking application — and it didn’t take long for me to realize I had made some blunders. The dynamic of the AppStore isn’t like most web stores where software companies sell their product. This a land where your sales are driven by your ranking and your ranking is driven by comments users leave.
The day the software was released was also the day iPads shipped. Until then, I had only run the application on the Apple provided iPad simulator running on my desktop. Well, my desktop has a whole lot more CPU power than the iPad. I was horrified when I first ran the app and realized it was soooooo slowwwww on the device. This meant all the people who downloaded the app would essentially hate it. It immediately showed in the ratings… I didn’t want to let the users down. Really, nobody likes getting ripped off so I owed it to them to make it work faster. I worked to immediately apply fixes to improve performance but it wasn’t until I completely rewrote the app 6 months later that things got a whole lot better.
Unfortunately by then the app rating was in the toilet. Basically a bunch of 1-star ratings killing any prospect of climbing back up. Even with an app working very smoothly, good ratings weren’t coming and I was still cursed by the 1-star plague.
I did some research and found out that the battle is a bit unfair initially. The only time users are prompted to rate an app is when they delete it. Obviously if they’re deleting the app, chance are they don’t like it and here comes the dreaded 1-star. As of v3.2, I added a prompt inside the app to offset that. If the user uses the app for more than a few days, they are asked if they want to rate it. This generated an influx of 4 and 5 stars review that is slowly outweighing the bad reviews.
As an iOS developer, you want to make sure you spend some time in making sure your app gets reviews. I know you want to work on implementing cool features and all but believe me, this is what will fuel your sales.
Ever since the good ratings started coming in, the app came up from the depths of app ranking to #25 top iPad productivity apps, and still working its way up.
I work mostly from a Mac from my home office. This means that most of my meetings are online and on the phone. So I use Skype a lot. I also use Alfred as an application launcher. Last night, I decided to explore the possibilities of further improving my productivity by having Alfred dial into my conference call meetings for me. It didn’t take too long to figure out, but I’ll share it anyway so it can take you even less time…
Since Alfred does not have any hooks into Skype, the trick is to use Web search. I added two commands, one to dial any phone number and one to dial into the 800 number for conference calls.
Here is how I configured Alfred, it’s pretty simple:
The call keyword will require you to enter a phone number. The search URL {query} parameter is substituted to the phone number you enter, making Skype dial that number.
For the conference call, it’s simpler. Since the phone number is always the same, I just hard-coded it in the search URL and assigned a new keyword (conference).
And that’s it. Now I can dial into any call using a keyboard shortcut…
When software started being sold to the masses, what you bought was what you got. Once the install program had finally scanned through a the couple dozen floppy disks that came in the box, there it was: your newly purchased software running on your PC. From that moment on, your acquisition was to remain stale only to be improved by new hardware purchases such as faster graphic cards, more RAM or better CPUs. So software makers had better get it right on the first try or it would be a PR nightmare.
With the advent of the Internet came the ability to update software over the wire. Nowadays ever bit of software comes with the ability to self update. By the turn of the century, the pressure to get the software right on the first attempt had decreased substantially because mistakes could easily be corrected over the first. In the software industry, this is called the Release Early, Release Often (RERO) philosophy and it’s pretty much dominated the industry since then. The idea is of course to be first to the market, and make adjustments as you go to fix problems. Many time you get stuck in a continuous effort to fix yesterday’s problem generated by a hasty fix to the previous day’s problem.
But there is a new force applying pressure the other way: Social media. With many online stores allowing customers to rate products and offer comments directly on the product’s page, software makers have to live with the quality they produce. This is particularly true on the AppStore where a single 1-star rating with a comment can sink your sales until the next 5-star comment shows up. Last week, I released an update to my iPad app, Ghostwriter Notes. I had been working on a huge project for months where days blended and finally released it. I figured I finally had some time to publish the major upgrade I wanted to publish for the app to make customers happier. Big mistake! Minutes after the update was published, I started receiving complaints that the app was crashing in certain circumstances. Too worried about getting this update out the door to increase customer satisfaction, I had not tested enough and rushed a buggy app to the AppStore. My experience with the AppStore is that the more updates you publish, the longer Apple takes to review it and publish it to the store. So if you follow the RERO philosophy, you will get burnt because not only you will push buggy code eventually, but each time you are condemned to suffer a two or three weeks delay in Apple’s review process because you are submitting frequent updates so you’re buggy app stays out there, getting bad review after bad review.
Lesson learned… Release punctually, release rarely.
I’ve been getting a lot of emails about Pro Core Data for iOS. Most of them ask if it covers this or that. Every time I’m puzzled by the question simply because Amazon usually does a good job showing the table of contents. Come to find out, they haven’t updated it yet. So here it is:
Chapter 1: Getting Started
- What Is Core Data?
- History of Persistence in iOS
- Creating a Basic Core Data Application
- Adding Core Data to an Existing Project
- Summary
Chapter 2: Understanding Core Data
- Core Data Framework Classes
- How the Classes Interact
- Summary
Chapter 3: Storing Data: SQLite and Other Options
- Using SQLite as the Persistent Store
- Using an In-Memory Persistent Store
- Creating Your Own Custom Persistent Store
Chapter 4: Creating a Data Model
- Designing Your Database
- Using the Xcode Data Modeler
- Creating Entities
- Creating Attributes
- Creating Relationships
- Summary
Chapter 5: Working with Data Objects
- Understanding CRUD
- Generating Classes
- Modifying Generated Classes
- Using the Transformable Type
- Validating Data
- Undoing and Redoing
- Summary
Chapter 6: Refining Result Sets
- Building the Test Application
- Filtering
- Aggregating
- Sorting
- Summary
Chapter 7: Tuning Performance and Memory Usage
- Building the Application for Testing
- Faulting
- Caching
- Expiring
- Uniquing
- Improve Performance with Better Predicates
- Analyzing Performance
- Summary
Chapter 8: Versioning and Migrating Data
- Versioning
- Lightweight Migrations
- Creating a Mapping Model
- Migrating Data
- Custom Migrations
- Summary
Chapter 9: Using Core Data in Advanced Applications
- Creating an Application for Note and Password Storage and Encryption
- Managing Table Views Using NSFetchedResultsController
- Splitting Data Across Multiple Persistent Stores
- Adding Encryption
- Sending Notifications When Data Changes
- Seeding Data
- Error Handling
- Summary
Today, I was running some load scripts on code that executed an HTTP POST request to a REST service. The load test essentially ran the HTTP call over and over. When the client was done running, I ended up with a bunch of TCP connections in CLOSE_WAIT status. To see the TCP connection states, run the netstat command on Unix (I’m guessing Windows has something similar). While the system appears to be running fine, CLOSE_WAIT means that the socket is inactive but still allocated. As the system continues to run and sockets in this state accumulate, the OS will eventually run out of sockets and everything will slow down to a crawl until it ultimately implodes and everything collapses.
I’ve seen this problem before so it didn’t take long to figure out, but I figured I’d post this to help those who haven’t seen it.
First, a quick TCP refresher… When a TCP connection is about to close, its finalization is negotiated by both parties. Think of it as breaking a contract in a civilized manner. Both parties sign the paper and it’s all good. In geek talk, this is done via the FIN/ACK messages. Party A sends a FIN message to indicate it wants to close the socket. Party B sends an ACK saying it received the message and is considering the demand. Party B then cleans up and sends a FIN to Party A. Party A responds with the ACK and everyone walks away:
A --FIN-> B A <-ACK-- B A <-FIN-- B A --ACK-> B
The problem comes in when B doesn’t send its FIN. A is kinda stuck waiting for it. It has initiated its finalization sequence and is waiting for the other party to do the same.
In the case of an HTTP exchange, the same thing can happen if not managed correctly. When using Apache HttpClient, a connection isn’t closed unless the code explicitly closes it. Unfortunately it’s not completely obvious how to close the connection from the client’s perspective:
HttpResponse response = httpClient.execute(postMethod);
It is even more problematic if you are using a connection manager which will create a connection pool. Also note that it’s not enough to call releaseConnection() to close the connection. This is the most common mistake.
What works best in my opinion is to reverse the sequence and let the server initiate the finalization. This means that we want to let the server send the initial FIN. This way the client code doesn’t need to do anything specific to manage the connection. We just let the TCP implementation take care of responding. Okay, so how do we do that? Simple… The HTTP protocol defines a header parameter called “Connection” which supports the “close” option.
In your code, before calling the execute method, add:
postMethod.addHeader("Connection", "close");
This header parameter will tell the server that you’ll want it to close the connection when it has sent the response. Your client socket will receive a FIN from the server, and the OS’ TCP implementation will do its own cleanup.
CLOSE_WAIT gone… Moving on…
Every software developer is (should be) reasonably well versed in the notion of model view controller (MVC). Yet, I still stumble into code that sometimes makes me wonder if something isn’t quite clear for some…
I think at this point, everyone has the model part down pretty good. I’m being nice here because even in that category there are times where things seem a bit blurry. The real problem comes in where some are trying to figure out where the demarcation is between a view and a controller. It usually starts reasonably clean, but then it gets ugly as new UI needs arise.
I’ve been working really hard to refactor the Ghostwriter iPad application to make it work faster. The other day, I had a discussion with myself over that blurry line. The basic setup is the controller knows the pageView, and the pageView knows the page it’s rendering. I then wanted to add a button to change the paper on that page. Naturally, since the pageView knows the page, my first instinct was to add a changePaper:(Paper*) method to the view. The controller could call it and the pageView could tell the view. Really easy! Only it’s wrong. It’s wrong because the view is theoretically a materialization (sort of speak) of the page concept. So it should not be allowed to modify it, by definition. But since I was way too clever to listen to reason, I persisted with this design that seemed to work…
On top of managing the page view, the controller manages a few other views. One of them displays information about the current page, including its paper. So now, because I delegated all the work of changing paper to the pageView, I’m stuck because my infoView isn’t aware that anything has changed. Of course, if you happen to read the upcoming book Pro Core Data for iOS
, you will find out that we could wire notifications across the views. But really, this is starting to sound really complicated. One of my physics professor used to constantly repeat “If the solution looks complicated, it’s wrong”. This timeless piece of advice made me rethink what was happening here.
Now, my controller updates the paper on the page model directly, tells the two views that things have changed and everything is working flawlessly. The views stick to materializing representations of the domain, the controller sticks to orchestrating the work, and everyone is happy. Including me…
Happy New Year!
I keep getting asked the same question and each time, even though I know the basics, I stumble my way to a precarious explanation. Even my grandmother who can’t operate a toaster oven would realize that there’s something shady about my arguments. So this time, I decided to write it down and here it goes…
First, I’ll preface with what (almost) everyone knows. From a compiler standpoint, NULL, nil and Nil are interchangeable because they are all defined as zero. This is because in MacTypes.h and NSObjCRuntime.h, you’ll find:
#define nil NULL
#define Nil NULL
and in the standard C library, stddef.h:
#define NULL ((void *)0)
So ultimately, every is defined as zero therefore the compiler doesn’t care what representation of zero you use, it’s still the same value. Actually in your code, you could just use 0 instead of NULL, or even use FALSE, or NO. But that would just be ugly because you are losing the semantic meaning of the word NULL, which is used to represent ‘no value’. After all, we want to be able to read the code and understand what the programmer meant.
This is exactly why there are multiple names for a null pointer. While they all have the same value, they mean something different to the programmer who reads the code.
NULL comes from the C world. This is why it is defined in the standard C libraries. You should use NULL in your code when you want to set a C pointer to ‘no value’.
nil and Nil are used exclusively in the Objective-C world. You use nil to point an Objective-C object to ‘no value’ and Nil to point an Objective-C class to ‘no value’.
Lastly, there is NSNull. NSNull is a real object, with a non-zero value. It is not interchangeable with the others. Instead it is used to represent a null where a non-null value is required. Typically, you would use NSNull if you want to represent null entries in a collection:
[mutableArray addObject:[NSNull null]];
The main debate is usually around the use of nil vs. NULL. My take on this is that if you are pointing an Objective-C object to ‘no value’, then use nil. For everything else (which really mostly amounts to selectors and void* ), use NULL.
So if you take a look at NSAlert
- (void)beginSheetModalForWindow:(NSWindow *)window modalDelegate:(id)modalDelegate didEndSelector:(SEL)alertDidEndSelector contextInfo:(void *)contextInfo
If you wanted to call this and set all the arguments to no value, you would do:
[alert beginSheetModelForWindow:nil modalDelegate:nil
didEndSelector:NULL contextInfo:NULL];
You rarely find yourself wondering if you should use Nil, but here’s one case. The NSObject class defines the method:
- (BOOL)isKindOfClass:(Class)aClass
So you’d call:
[@"abc" isKindOfClass:Nil]
And there you have it… Even if you too can’t operate a toaster oven, you will at least know when to use the proper semantic…
I ran into an interesting performance problem today. I was working on an algorithm to process text data files. My first stab at the design went through my data file starting from the first character and on, and output a string built based on some rules applied to each character. I ended up with a O(n2) performance, which really didn’t seem that good for the kind of processing I was doing.
So I redesigned the algorithm to build strings backward and ended up with an O(n) performance, which is much better.
Happy with the design, I set out to implement it in Java (the rest of the system is in Java). In order to build my strings backwards, I used StringBuffer.insert(0, c), which inserted my character at the beginning of my output string. I ran my test on a 5Mb file and it took over 20 min. Actually I don’t really exactly know how long because I aborted it. What?!
As it turns out, StringBuffer.insert(0, c) is terribly inefficient. Instead of calling this method, I changed it to build my string reversed using StringBuffer.append(c), then reversing it using StringBuffer.reverse() right before returning. Now this same test runs in 719 milliseconds… Ridiculous difference!
Need proof? Here’s some code:
int size = 100000;
StringBuffer str1 = new StringBuffer();
long t1 = System.currentTimeMillis();
for(int i=0; i<size; i++) {
char c = (char)('a'+(i % 26));
str1.insert(0, c);
}
System.out.println("StringBuffer.insert(): "
+(System.currentTimeMillis()-t1)+" ms");
StringBuffer str2 = new StringBuffer();
long t2 = System.currentTimeMillis();
for(int i=0; i<size; i++) {
char c = (char)('a'+(i % 26));
str2.append(c);
}
str2 = str2.reverse();
System.out.println("StringBuffer.append(): "
+(System.currentTimeMillis()-t2)+" ms");
System.out.println("Equal? "+str1.toString().equals(str2.toString()));
The results speak clearly:
| insert() | append() + reverse() | |
| size=10000 | 19ms | 3ms |
| size=100000 | 1642ms | 16ms |
| size=1000000 | 162542ms | 41ms |
| size=10000000 | RIP | 85ms |
I didn’t have the heart to run the insert() method with size=10000000, that’s just cruel. But looking at the little data I collected and interpolating, it looks like it would have taken about 4 hours on my machine. Feel free to test it yourself… But the point is proven. The insert() implementation is exponential and the append()+reverse() implementation is linear. Ridiculous…
In the process of doing research on encrypting persistent stores for the upcoming Pro Core Data for iOS, I stumbled upon a neat recent feature that Apple calls “data protection”. In essence, if you have enabled data protection for your device as explained here, then you can tell iOS to use hardware-level encryption for any file, including the Core Data SQLite database.
This means that when creating your persistent store coordinator and the persistent store from the sqlite file, you can enable hardware-level encryption.
- (NSPersistentStoreCoordinator *)persistentStoreCoordinator {
if (persistentStoreCoordinator_ != nil) {
return persistentStoreCoordinator_;
}
persistentStoreCoordinator_ = [[NSPersistentStoreCoordinator alloc]
initWithManagedObjectModel:[self managedObjectModel]];
NSURL *storeURL = [NSURL fileURLWithPath:
[[self applicationDocumentsDirectory]
stringByAppendingPathComponent: @"MyStore.sqlite"]];
NSError *error = nil;
if (![persistentStoreCoordinator_ addPersistentStoreWithType:NSSQLiteStoreType
configuration:nil URL:storeURL options:nil error:&error]) {
NSLog(@"Unresolved error with store %@, %@", error, [error userInfo]);
abort();
}
NSDictionary *fileAttributes = [NSDictionary
dictionaryWithObject:NSFileProtectionComplete
forKey:NSFileProtectionKey];
if(![[NSFileManager defaultManager] setAttributes:fileAttributes
ofItemAtPath:[storeURL path] error: &error]) {
NSLog(@"Unresolved error with store encryption %@, %@",
error, [error userInfo]);
abort();
}
return persistentStoreCoordinator_;
}
The trick is to set the file attribute using NSFileProtectionKey and set its value to NSFileProtectionComplete. By default it is set to NSFileProtectionNone.
Now take a minute to reflect on this and make sure you fully understand what is happening before you start jumping up and down because you got encryption for free. The data will be automatically encrypted, at the hardware level, on your device (obviously not the iOS simulator) when the device is locked. When the device is unlocked, it is automatically decrypted. So your persistent store is at best as secure as your device, but not more. If someone figures a way to crack your 4 digits lock code, you’re out of luck. And by the way, somebody has figured it out…
I just made it back from Cocoa Camp 2010 where Rob (@hoop33) and I gave a talk on creating custom stores using Core Data. It was a good opportunity to mention our upcoming book since we have a few pages dedicated to custom stores. Our presentation was done in a room where the only light was the projector’s. That light was a deep blue until we plugged in our laptop. And let me tell you, the light was blue for a long 10 minutes as we slowly realized that we did not bring the right adapter for the projector. “Ouch we need a mini-DVI adapter!”, we exclaimed. I had to scramble and run out into the hallways and other rooms approaching anyone with a MacBook Pro (and in a Cocoa conference, that’s a lot of people) asking if they had a mini-dvi adapter. I eventually found someone. Ran back into the room. Pfew! Saved! Oh no! The new MacBook Pro does not have a mini-DVI adapter, it’s a mini display adapter we need… Back out running around in the hallways. 10 minutes have passed and I finally come back with the right adapter. Finally we can get rid of the deep blue light and get on with it! We came close to complete embarrassment! We’d have had to cancel because I couldn’t really see ourselves trying to describe diagrams with gestures and talking to a bunch of blue people. May be we could have used Chinese shadows play using the projector’s light on the wall.
Once we got passed our technical difficulty, everything went perfectly well. Got some good questions, good interest and good feedback. Met some smart people. Met some marketing folks as well, this was an interesting angle too.
We both attended Rod Strougo’s (@rodstrougo) presentation on Cocos2d (http://www.cocos2dbook.com) which is a very compelling framework for building 2D games on the iDevices, including physics engines and stuff. I’ll definitely have to play around with this. Check out Rod’s upcoming book as well. I’m definitely getting it.
Overall an excellent experience. I don’t regret the trip to Atlanta but I’m glad to be back because we still have most of chapter 7′s first draft due on Monday.




