Skip to content

Image Retweever® App, “… a Lava Lamp for tweets,” is out the door.

Our new app, Image Retweever® App, is now available in the iTunes App Store. Our marketing site is Image.Retweever.com

Dal Child

This fun app is built on top of the library engine we built for #Chat. Stay tuned for more technical details soon. I must do some marketing first.

An iTunes App Store App Review Success Story

My new app Startup Crawl, http://bit.ly/StartupCrawlApp, was just approved by the Apple App Review team. This is unremarkable and expected for a simple app. What is remarkable was how well and simple getting this app approved using the expedited review request proved to be.

Startup Crawl is a simple event directory app supporting the Startup Crawl tour during Austin’s Startup Week, October 8-12, http://atxstartupweek.com. The Crawl itself takes place on Thursday evening, October 11th, from 5 to 10 PM. The event promises to be a lot of fun and, I hope, results in new partners to work on my new startup idea with me.

The app was started by myself and Grayson Lawrence on September 15th. It was submitted to Apple on October 3rd, approved on October 9th. These dates are important. I submitted my prior app, Punch It Out™, http://bit.ly/PunchItOut, to the App Store on September 17th and it was approved on the 25th — 8 days. I had hoped to get Startup Crawl submitted earlier, the code was done on Monday, October 1st, but wrangling icons out of startups can sometimes be quite hard. Basically, by submitting the app on Wednesday, I was not giving Apple the same amount of time that they had used just two weeks previously.

I was concerned. If Apple was still swamped by the iPhone 5 and iOS 6 app approval flood, then Startup Crawl might not be available during the Crawl itself.

I’ve had my apps rejected by Apple before. Always this seems to be a straightforward but time consuming event. If your app is rejected, it can take Apple another 7 or more days to get back to your app. In other words, the penalty for shipping something lame is go to the back of the line. Because of this, Apple has implemented an expedited review process — an appeal, if you will. As I had been a good doobie and submitted the app just over 7 days before I needed it to be available, I felt I was a good candidate for an expedited review.

Apple granted that review and the app is now available to Startup Week participants.

What did I tell Apple to get this indulgence?

First, I’ve met the App Review staff at WWDC. They are nice people who get almost no respect. They are always “in the way” — between a developer and her market. But they are, nonetheless, people with feelings who make judgements that affect my future. Second, they “fight for the user” but they want you to succeed too. They want to approve your app. Third, approving my jumping in line means some other deserving developer’s app is not approved today. I have to show these folks why my need to access the market is more important than the other developer’s need, she works just as hard on her app as I do on mine.

Hence, I crafted my pitch in an email to AppReview@Apple.com as follows:

Gentle Apple App Reviewers,

I have written an app, Startup Crawl, id = xxxxxxxx8, that needs to be approved by close of business on Wednesday, October 10th, 2012.

Why? This app is providing a guide for the Austin, TX Startup Week Startup Crawl. The Crawl is on Thursday, October 11th, from 5 – 10 PM. Approving the app after the 10th or, at the latest, midday the 11th will be moot. No one needs an app that documents an event that has already occurred.

What have I done to help you, Apple App Reviewers, help the Austin Startup Community? We submitted the app on Wednesday, October 3rd. I believe this allows you your requested expected review time of seven (7) days. In other words, I am trying to keep Apple off of my critical path. The variance of app review times is unknown; due to the release of iPhone 5 and iOS 6, I expect it is longer than normal. I am alerting you to the firm deadline to my app’s utility. If we’re late …

Why would Apple want to help me? First, this app helps Apple iOS developers. It is sponsored by the local developer group, Cocoa Coders. (By sponsored, I mean I’ve donated my time developing this app to help the Cocoa Coder and Austin Startup community.) Second, due in part to the app, these developers and other Austin startups will have added visibility to the Austin angel investor, business partner and co-founder community. More developer and investor commitment to your platform only helps Apple. By approving this app, you help improve the developer opportunity in the Apple ecosystem.

Finally, I am trying to be proactive in alerting Apple to my situation. This is much better, I hope you agree, than being reactive after the fact and needing emergency attention.

I hope you can help me by slotting my app into your Wednesday or earlier approval queue.

Thank you.

And it worked. Almost. It got returned and I was told to resubmit it through the appropriate form: http://developer.apple.com/appstore/contact/appreviewteam/index.html. That worked.

Lesson Learned:

First, don’t cry wolf for every app submission. I brought their attention to how I was working within their constraints and they honored that by approving this app.

Second, be nice. I’ve sat across the desk from these people trying to resolve a problem. Being nice helped.

Third, it isn’t all about you or Apple. It is about your joint customer. In my case, investors and partners using their phones to navigate downtown Austin in search of business opportunity.

A Pattern to Declare an Objective-C Mix-in

The missing piece for creating a full fledged mix-in, or multiple inheritance, language out of Objective-C was the addition of associated references. My earlier post on creating a category that uses associated references is an example of the basic framework to do so. All it was missing was a formal way for the compiler to enforce the types of the mix-in. A protocol provides this mechanism. This post will show how to create and use this convention.

Use Cases

There are, at least, two use cases for a mix-in. First, it is an organizational mechanism for building libraries that can be added to any proprietary class. This has been a common use for categories since they were invented and implemented in Obective-C. Unfortunately, it was always restricted to only adding methods and not ivars to a class. Obviously, using associated references addresses this limitation. Second, it can be used to add functionality to existing classes in a precompiled framework, as in my DDGActivity example adding an indicator to a UIView.

Modifications to DDGActivityViewController

The changes are quite simple. You convert your category into an @protocol. I will show two examples. First, I’ll add a mix-in to support TestFlight’s SDK. TestFlight is an excellent service to support a wide area Ad Hoc app testing program. You can learn about their SDK at http://TestFlightApp.com. There are other companies/open source software projects that provide similar services, such as QuicyKit, http://QuincyKit.net, and HockeyKit, http://HockeyKit.net.

The example’s goal is to use TestFlight during Ad Hoc testing and to compile the code out of the app for deployment. There is some question whether Apple allows apps into the App Store with the crash reporting functionality provided by TestFlight. Hence, I wanted a mechanism that made it trivial to remove TestFlight without placing conditional compilation statements throughout my application. I also added an ivar, lastCheckpoint, to contain the last string saved by the -passCheckpoint: method. This ivar is a proper @property. Hence, you can observe the ivar and do things like collect a history of the checkpoints. I’ve implemented simple logging in the view controller this way.

All of the type information is contained in two files. The first file contains a traditional declaration of a protocol. In this case, it is DDGTestFlight.h. It is name spaced because I wrote it. It more appropriately belongs in the TestFlight.h file in the TestFlight SDK. The second file is a simple modification of the category file in the previous version of this project. It is a very simple change. You import the header and then apply the protocol to the category. As in:

@interface DDGActivityViewController (DDGTestFlight) <DDGTestFlight>

As with any protocol, this allows you to precisely control both the type and which methods are required to be implemented. While the category and the protocol do not need to have the exact same name, that seems like it is a good convention to adopt.

Modifications to DDGView

The category on UIView is similarly simple augmented. A protocol file, DDGView.h, is written and it is included and applied to the category. As in:

@interface UIView (DDGView) <DDGView>

I implement the same naming convention as in DDGTestFlight.

Code Encapsulation Improvements Appear in ModalViewController

A very nice side effect of using protocols instead of categories is the information encapsulation now possible. In ModalViewController, we are able to just test for the protocol and not the class of the mixed-in instance. Your code is now more loosely coupled as a result. Traditionally, this means it is more robust against changes in other parts of your program. This is a good thing.

Summary

Moving to a protocol driven technique of adding both associative references and methods improves the encapsulation of your classes while also partitioning type information in a useful fashion. As it is a pretty simple addition to what you need to do to add associative references anyway, I recommend that you do it. As before, you can get the source code up at GitHub, http://bit.ly/DDGActivityGH.

Postscript to our Friends at TestFlight

As you can see from the above, it is pretty straightforward to add an effective form of conditional compilation to your system. I would raise two issues. First, the team token for DDGActivity in my account is hard compiled into the code. I’m OK with this if you are. Second, more importantly, I want to encourage you to embrace this method of adding a TestFlight mix-in. In your case, I recommend that you create and maintain the TestFlight protocol. Furthermore, as Apple is standardizing on the class name AppDelegate in their Xcode 4 templates, it is almost trivial to change my category implementation to apply to AppDelegate instead of DDGActivityViewController. Unlike the rest of your library, I want to encourage you to keep the source code for this category visible to your licensees.

Steve Jobs RIP

Steve Jobs changed my life.

Outside of my immediate family, I think I can only say that about him.

I wanted to contribute to his vision.

I left graduate school to write Mac software — D2 Software’s MacSpin — to contribute to Jobs’ vision.

I followed the siren call of multiprocessor performance and lead a team to create the TokaMac family of Mac accelerators. People could do more on their Macs with my products.

In the height of irony, I joined IBM to lead IBM’s Mac OS licensing technical team. We were successful. Jobs disapproved.

I spent 11 years in IBM Software Group tracking everything Apple did. Apple once suggested that IBM embrace a Cocoa UI in Java. I countered with a vision of a browser based UI. We now call it AJAX. It was the original programming model for the iPhone.

In 2009, I asked to be laid off from IBM. The goodbye severance launched a new embrace of Jobs’ vision; I returned to programming with the iPhone.

I am beyond being a fanboy. People who call me that don’t understand the vision.

I am a contributor.

Thank you Steve for making a place to play and contribute.

DDGActivity: An Example of Using Associated References

Object oriented languages have always allowed a programmer to add both methods and ivars to any class. Apple recommends you should not over-ride some Cocoa/Cocoa Touch classes. Hence, you cannot use inheritance to add ivars and methods to those classes. Of course, Objective-C has always offered the category mechanism as a way to add arbitrary methods to any class. But historically, categories cannot add ivars. Apple has addressed this in the modern Objective-C runtime with a mechanism called associated references. I have tested this code on iOS v4+.

The example app shows you how use an associated reference to add a UIActivityIndicatorView to every UIView, just as if it was any other ivar.

UIView (DDG) category

This category adds an @property and a method, -centerIndicator to a UIView. Here is the header:

#import <UIKit/UIKit.h>

extern NSString *const kActivityIndicatorKey;

@interface UIView (DDG)

@property (nonatomic, retain) UIActivityIndicatorView *activityIndicator;

- (void) centerIndicator;

@end

As we are using an @property, I also add a constant string key to support key-value coding. (I do this to allow the Xcode’s function completion to suggest the right key. This, of course, ensures that you don’t inadvertently add a typo to your key.)

How Do You Use It?

Here I create an activityIndicator and add it to a UIViewController‘s UIView.

self.view.activityIndicator = [[[UIActivityIndicatorView alloc] 
                                initWithActivityIndicatorStyle: UIActivityIndicatorViewStyleGray] 
                               autorelease];
[self.view addSubview: self.view.activityIndicator];
[self.view centerIndicator];

[self.view.activityIndicator startAnimating];

Here I release the activity indicator:

[self.view.activityIndicator removeFromSuperview];
self.view.activityIndicator = nil;

That is straightforward and is used no differently from any other ivar that contains a UIActivityIndicatorView.

A Pleasant Surprise.

One downside of the category mechanism is that it cannot over-ride any arbitrary method. This is a problem. To preclude a memory leak, all instances need to be released. But you cannot override -dealloc with a category. How do we solve this problem? We don’t have to; the Objective-C runtime handles this for us. This is another example of Objective-C evolving into a modern object oriented language that manages its own memory.

The example application allows you to create a modal view. When you dismiss the modal view, the activityIndicator is automatically released by the runtime and not by a -dealloc method. Please run the example app under Instruments’ memory leak tool. You will see this to be true.

How Does It Work?

The activityIndicator is an @dynamic @property. Hence, we need to implement both the setter and getter. All of this code is in UIView+DDG.h/.m files.

Here is the getter:

- (UIActivityIndicatorView *) activityIndicator {

    return objc_getAssociatedObject(self, kActivityIndicatorARKey);

} // -activityIndicator

Here is the setter:

- (void) setActivityIndicator: (UIActivityIndicatorView *) activityIndicator {

    objc_setAssociatedObject(self, 
                             kActivityIndicatorARKey, activityIndicator, 
                             OBJC_ASSOCIATION_RETAIN_NONATOMIC);

} // -setActivityIndicator:

As you can see, the runtime provides a simple C-function to implement both accessors. The runtime identifies the associated reference by this C-string key:

static const char *kActivityIndicatorARKey =  "ddgActivityIndicatorARKey";

This string could be anything. I chose to namespace it with a DDG prefix and role suffix, "ARKey". Both of these together insure that this symbol will not collide with an Apple name. (As I prefer readability in my code, I chose NOT to namespace the ivar activityIndicator itself. This namespace collision is a risk I’m willing to take.) As these accessors apply to the instance, self is the appropriate object to pass to the function. Finally, the memory management policy is defined by a family of self descriptive constants: OBJC_ASSOCIATION_ASSIGN, OBJC_ASSOCIATION_RETAIN_NONATOMIC, OBJC_ASSOCIATION_COPY_NONATOMIC, OBJC_ASSOCIATION_RETAIN, OBJC_ASSOCIATION_COPY. In the example, I’ve chosen OBJC_ASSOCIATION_RETAIN_NONATOMIC to match the @property (nonatomic, retain) declaration.

DDGActivity Example Application.

The example application is based upon Apple’s single view application template. For clarity and simplicity, most of the template code has been removed. The root view controller, DDGActivityViewController, has just 3 button action methods: -turnOnAction:, -turnOffAction: and -modalViewAction:. The first two toggle the state of the activity indicator and the third, somewhat obviously, shows the modal view.

The modal view exists to show you automatic memory reaping of associated references by the runtime. It does this by not actively releasing the activityIndicator when the modal view is dismissed. All of the memory is automatically reclaimed. No leaks are created. Please verify this by running the app under Instruments’ memory leak tool. The ModalViewController just has two methods: -viewDidLoad and -dismissAction:. They are simple. -viewDidLoad‘s body was copied from -turnOnAction:. -dismissAction: just dismisses itself.

Licensing

Even though there is little likelihood that you will copy and past this code directly into your app, it is covered by an attribution required BSD license. If you use this technique, please consider giving me credit in your licenses or credits view. I write these posts to help grow my development consulting business and would appreciate your help.

Where to get it?

This code lives up on GitHub at: http://bit.ly/DDGActivityGH. The announcement post to my blog is at: http://bit.ly/DDGActivity.

DDGPreferences: A Class for all Settings

Almost every iOS application has individual user preferences. Some apps also use Apple’s Settings app, some don’t. If you develop many different applications, as I do in my development consulting practice, it is tedious to code up a custom preferences class for each app. My class, DDGPreferences, is an attempt to minimize the tedium by providing a very simple API to the NSUserDefaults class for both settings and custom preferences. In addition to DDGPreferences, I have included a set of standard logging macros, DDGMacros, and an example single view iOS app tying all of the pieces together.

The API

I like simple APIs. They are easy to use and easy to share. I wanted this API to be no more than a list of properties. As in:

@interface Preferences : DDGPreferences

@property (nonatomic, copy)   NSString *nameSetting;
@property (nonatomic, assign, getter=isEnabledSetting) BOOL enabledSetting;
@property (nonatomic, assign) CGFloat sliderSetting;

@property (nonatomic, copy)   NSString *namePref;
@property (nonatomic, assign, getter=isEnabledPref) BOOL enabledPref;
@property (nonatomic, assign) CGFloat sliderPref;
@property (nonatomic, retain) NSData *rectPrefData;

@end

Furthermore, the only difference between whether a property was visible in Apple’s settings app should be if a key matching its exact name was present in the Root.plist in the Settings.bundle. In other words, each setting has an identifier/key which is identical to a property name. This post is not a tutorial on how to build an app that uses Apple’s Settings application. That said the example app has only made minor changes to the fields created when you add a Settings.bundle to your app. (In particular, I changed the Key/Identifier from using under bars, _, as word separators to using standard Cocoa camel case.) In other words, I believe a beginner should be able to follow the logic of using this class without too much difficulty.

How do you use DDGPreferences?

Using DDGPreferences is simple. Make your Preferences class a subclass of DDGPreferences and then instantiate it. Really, that is all you have to do. Your preferences are limited to those supported by Apple’s .plist files. This is not as restrictive as it might seem. Later, I’ll show you how to convert an arbitrary NSCoding compliant class to a preference.

If you have default preference values which are different from the state of a freshly initialized object, then you must implement the DDGPreferences protocol’s single method, -setDefaultPreferences. The example application has this method.

What about synchronizing changes between Apple’s Settings app and yours while the app is in the background? When your app returns to the foreground, I recommend you read/write the Settings managed values in response to the UIApplicationDidBecomeActiveNotification, UIApplicationWillResignActiveNotification notification pair. The example app shows one way to do this. All other coordination with the Settings app is handled by DDGPreferences.

The DDGPreferences app:

I’ve included an app showing how to use DDGPreferences. It is a single view iPhone app with an array of identical controls for both Apple’s Settings app and the DDGPreferences app. You can change the preferences for the settings in both apps and they transfer bi-directionally. A simple CGRect is also initialized and stored. It is then displayed in a UILabel. How to store a complex structure, such as a CGRect, is described below. Traditionally, your preferences are stored with your application singleton. In this example, for pedagogical simplicity, I store them in the root view controller.

Saving complex classes:

This is an advanced technique and, if you can, I recommend that you avoid using it. Any NSCoding compliant class can be stored, with care, in DDGPreferences. As DDGPreferences uses the properties to determine what needs to be persisted, you cannot just define a @property for your class that is not one of those supported by Apple’s .plist format; you need to define an NSData typed instance variable to hold an archived instance of your class/structure. In the example, rectPrefData is that property. To access this data as your preferred type, you need to define “old school” Objective-C v1 style accessors. In the example, these are -rectPref/-setRectPref:. Somewhat obviously, these accessors will use rectPrefData to store the value. A example implementation of these methods is:

- (CGRect) rectPref {

    return [[NSKeyedUnarchiver unarchiveObjectWithData:
             self.rectPrefData] CGRectValue];

} // -rectPref

- (void) setRectPref: (CGRect) rect {

    self.rectPrefData = [NSKeyedArchiver archivedDataWithRootObject:
                         [NSValue valueWithCGRect: rect]];
} // -setRectPref:

They work by taking your NSCoding compliant class and archiving it using the NSKeyedArchiver/NSKeyedUnarchiver classes. The above methods, for pedagogical purposes, are not key-value coding compliant.

Licensing:

DDGPreferences is covered under a public attribution required version of the new BSD license. Why do I require that you acknowledge me publicly in your app? Similarly to many other developers, I make my code available under an open source license as an advertisement for my development consulting services. Hence, I need to be able to easily point to applications that use my code. While it is not necessary, I would appreciate it if you also sent me an email saying in which apps you use DDGPreferences.

From my experience making other code available under an open source license, some folks will write asking to be relieved of my public recognition requirement. Unless the requestor is willing to compensate me to change the licensing terms, I will always decline to change my agreement. I have put some time and care into crafting this class, app and this blog post. That time deserves compensation. I have chosen to be compensated by using this class as a marketing mechanism. I apologize if this does not align with your open source values. I have a family to feed and a mortgage to service. I sell coding services and code to provide for all of us. I hope you understand.

Where to get the code:

This code is available from GitHub at this URL: <https://github.com/adonoho/DDGPreferences>. I will be tracking comments at both GitHub and this post on my personal blog, <http://blog.DDG.com/?p=53>. I, of course, encourage you to send in bug fixes and make suggestions to improve DDGPreferences for all of us.

I hope you find DDGPreferences useful.

In a future post for advanced programmers, I will describe how DDGPreferences functions.

Acknowledgements:

I would like to thank Scott Gustafson and Mason Weems for their suggestions and support. Also, Austin’s local Mac OS X/iOS developer group, Cocoa Coders, organized by Jim Hillhouse and Rajat Datta, has been extremely helpful in my return to software engineering.

Core Data Lessons Learned.

The lessons I’ve learned about using CD are pretty simple.

1) Retain the minimum CD items as necessary to run your app. The CD row cache and fetch requests appear to be quite performant. Rebuilding fetches allows the system to dump memory as needed.

2) -save: is your friend. -save: early and often. Sometimes this will hit your UI’s responsiveness. It’s OK. In particular, you should -save: before starting background operations. Frequent -save:‘s mean that each one is a fast operation.

3) The fetched results controller is “new” code. It has surprising performance “gotchas” and section update bugs. In particular, you should dump it at the first sign of memory pressure. You can recreate it simply. Block oriented fetches are quick.

4) It really helps to go though your program early in a memory warning and dump CD items. Your root view controllers appear to get first crack at dumping memory. If at all possible, do it there. It isn’t clear whether CD gets a chance to dump it’s caches before your -applicationDidReceiveMemoryWarning: gets called. When it did, I then frequently saw a UI-locking loop into the fetched results controller. Also, call -save: in each memory warning routine. If you are observing NSManagedObjectContextDidSaveNotification, it creates a potential dirty loop; KVO observers get fired as the save progresses.

5) The predicate documentation is wholly inadequate. Yes, it is a complete reference. Yet, it is useless as a learning document. The “CD Programming Guide” is much better. The predicate guide needs as thorough a treatment. (Apple is not alone in this lack, one well known book addresses predicates in 3/4 of one page. I feel like such a sucker buying a DB book that doesn’t cover the query language.) For example, I spent a great deal of time banging my head against the fetching limitations of the fetch request. (Of course, if you use a fetched results controller, you have no choice. There is a great need for a block/handler controller.) There are no good examples of the idioms involved with using this predicate language. In particular, when I need to start using text searching, there is little discussion of how the regex engine interacts with the object graph and the row cache.

6) There are surprising interactions between your foreground and background contexts. They can be handled with careful model design and instantiation order. While I don’t think Apple should necessarily document these kinds of problems, some discussion of CD model design guidelines would be helpful. CD is a different way to think about a data model. Apple needs, IMO, to help folks get their heads around the differences.

While you might think that all of my suffering with CD would cause me to walk away from the technology, I’m leaning the other way. As I’ve now crossed a competence threshold, I am seeing good benefits from using an object graph instead of a SQL model. For example, I have a recursive algorithm. Recursive SQL appears to be it’s own special hell. The object graph makes it easy and handles cycles well. While I doubt there is a performance issue, I can pre-fill the row caches with a single fetch request. In addition, my algorithms are well served by object graphs.

The above said, I wish that learning this technology was as straightforward as learning the rest of Cocoa/Cocoa Touch. Apple could do better here.

DNS-SD Configuration “Gotcha”

weLost™ uses DNS-SD, DNS Service Discovery, to bootstrap the location of its social network servers. While this was a good idea, it had a very subtle “gotcha” in its configuration. The basic configuration instructions are described here in: Static Server Setup. If you do not intend to support browsing for your resources, then things are even simpler but there is still that pesky “gotcha”. To support direct access you only need to implement the third set of DNS records. The one’s labeled: “SRV & TXT records describing each service entity named above”.

If my experience with the iPhone is a guide, the TXT record is not optional. Every service you query MUST have a TXT record. In my case, I neglected to set the TXT record for my narrow web HTTP server. This caused every NSNetService query to timeout. Solving this problem was simple, I entered “txtvers=1” as the body (minus the quote marks) for the TXT record. This is a default version of the format of all DNS-SD TXT records. There are other values you could use, particularly for HTTP, but this one is both innocuous and sufficient.

Enjoy and Anon,
Andrew

Network Reachability

If you write an iPhone application that uses the network, then you must check if the network is both operating and that your server is reachable. Apple has and will continue to reject applications that do not test reachability. To this end, Apple provides iPhone developers a sample application and class, Reachability, that can easily be used to perform these tests. While the 2.0 version of this code is much better than v1.5, it is still quite raw. (For example, there is a bare [super init]; in a class method [line 175 in Reachability.m]. It does nothing. It also has two routines with misspellings in their names: -startNotifer/-stopNotifer should be -startNotifier/-stopNotifier) To me, these are signs of raw code. To remedy this, I have significantly reengineered this class.

I had three goals when starting this process. First, I wanted to understand how to use this code. It isn’t at all apparent how these routines should be used. What order should they be called in and what do the various tests and values mean? Second, my scan of the code convinced me that it was written by a low level network engineer. They had made implementation decisions that were not terribly friendly to using it in a Cocoa Touch program. I wanted a class that fit in with my coding style. Third, because the core network testing routine -networkStatusForFlags: was not, in my opinion, clear, I did not feel comfortable shipping it in my app, weLost™. I wanted to have confidence in this code.

This class has two important features: network status transition notifications and easy reachability testing for each server your app touches. Because radios lose connections all of the time, these dynamic notifications help your user understand why they cannot use the networking features of your app.

When I start my app, the first Reachability method I use creates a Reachability instance for the network itself, +(Reachability *) reachabilityForInternetConnection;. This tests the hardware and can immediately provide you with the current network status. Because this reachability test doesn’t leave the phone, there is no network latency. Because hostname reachability instances must resolve your host’s name into an IP address, they are asynchronous. The immediately returned status is that your host is not reachable. (Bear in mind that the subsystem underlying Reachability, SCNetworkReachability, does not actually try to send a packet to your host. It only really knows the state of the radios and whether IP addresses have been allocated for the phone and that your host’s name has resolved into an IP address.)

These Reachability instances do not start notifying you of network transitions upon instantiation. You must turn this on. Before turning on the notifications, I like to register for them. The notification name in the default notification center is: kReachabilityChangedNotification. When your registered method is called, the notification’s object will be the Reachability instance with the changed status. For example, you might register this method:

-(void) networkReachabilityEvent: (NSNotification *) notification;

with the notification center. When it is called for a status change, the Reachability instance is recovered with this line of code:

Reachability *r = [notification object];

A Reachability instance’s notifications are initiated, unsurprisingly, with the -startNotifier method.

Now that you can track gross network transitions, you need to create Reachability instances for each host. In weLost’s case, I track 4 different servers. I use:

+(Reachability *) reachabilityWithHostName: (NSString*) hostName;

to create these instances. These host names must be resolved into addresses before the instance is reachable. (A notification, if you’ve turned them on for this instance, is issued when the resolution is finished.)

This class can be used both synchronously and asynchronously. Typically, you will make synchronous queries of the Reachability instance passed to you after a network status transition. You may also want to do a synchronous test before opening a new view which connects to your host. (One advantage of creating all of your Reachability instances at startup, i.e. before you need them, is that their name resolution does not delay your later network accesses.) My version of Reachability has more methods for synchronously testing network status than Apple’s. Their version also has mixed some tests, such as whether user intervention is required, into the network status method which I think should not be there. I have cracked them out into separate methods. Here are the kinds of network tests you can perform:

  • Test whether this Reachability instance is of interest.
  • If so, then test what kind of network transition it is:
    • Is the host reachable? -(BOOL) isReachable;
      • Is the connection up? -(BOOL) isConnectionRequired;
        • Will it come up automatically? -(BOOL) isConnectionOnDemand;
        • Will the user have to enter a password? -(BOOL) isInterventionRequired;
      • Is the connection slow? -(BOOL) isReachableViaWWAN;
      • Is the connection fast? -(BOOL) isReachableViaWiFi;

How do you determine if a Reachability instance is of interest? You check its key — a hostname or a dotted quad IP address or one of two constants: kInternetConnection or kLocalWiFiConnection. This is a big change from Apple’s code. I keep a key, an NSString, along with the SCNetworkReachabilityRef. Apple just keeps a boolean and the SCNetworkReachabilityRef. In other words, I make it easy to use Reachability instances in complex Cocoa data structures. I’m sure Apple’s engineer would argue that pointer comparisons are sufficient to determine one’s interest in a notification. That doesn’t mean it is a particularly useful mechanism in a Cocoa program. Also, Apple’s boolean is used just to differentiate one instance type, kLocalWiFiConnection, from all of the other types. While this is useful to the internal functioning of Apple’s code, it isn’t particularly useful to a client of the class. I provide a convenience method, -isEqual:, to compare Reachability instances. To a Cocoa Touch programmer, a key is just more flexible.

Your decision tree to interpret network status transitions is, of course, idiosyncratic to your application. However, there are issues to consider based upon your connection. After you have determined whether your host is reachable, is the network active and connected? For example, if you are connected via the EDGE/3G wireless wide area network (WWAN), your network is always reachable but it may not be active. You start the radios by trying to connect to your host. I have seen this process take tens of seconds. Does your user need to know this? If you are connected via WiFi and if a user must enter a password, you may choose not to connect to the network. If you’ve transitioned from WiFi to WWAN, does the user need to know that things are much slower or they may have lower resolution media? And the converse? Do you enable more features when the network transitions to WiFi from WWAN? And what, exactly, do you do when there is a repeated network flap between WiFi and WWAN? What do you do when your app is brought out of sleep in a new venue? What do you tell your user? You will get a notification for each of these situations.

There are two Reachability instances I have neglected — -reachabilityWithAddress: and -reachabilityForLocalWiFi. -reachabilityWithAddress: takes an internet IP/socket address and can be queried immediately for its status. Its key is a dotted quad IP address, such as @"127.0.0.1". The -reachabilityForLocalWiFi instance is a bit more subtle. It tests for a WiFi connection using an automatic private IP address, 169.254.0.0. If this network is reachable, then your network is active but not routable. Some services, such as Bonjour, will still function fine in this case but not much else. I have not found any use for this instance type. Yet I have preserved Apple’s test criteria for this instance in my code. Perhaps it is of use to you.

Before using my extensions you should probably ask: how compatible is this stack with Apple’s? My answer is: very. My code is a superset of Apple’s API. Other than Apple’s misspelled method names, my code will be a drop in replacement for Apple’s class. It has, as far as I’ve been able to test, identical behavior. My network status test is different. It is supported by empirical observations of the status flags. Because it does not conflate a test for whether a user’s intervention is required with the basic reachability, my network status test is simpler. Nonetheless, if you do not wish to use my extensions, I provide a #define DDG_EXTENSIONS to enable easy comparisons between the two network status policies in your application. Both classes employ NSAssert and NSCAssert. This is aligned with the Cocoa policy to throw exceptions during development to catch programmer errors. These exceptions can be turned off by defining NS_BLOCK_ASSERTIONS during your release builds. Finally, I support a conditionally compiled logging system. To turn it on you need to #define CLASS_DEBUG in the class header and #define DEBUG for the debug builds of your app. Then both the -description method and synchronous logging are turned on. My log entries also list the method name and line number of the source code. Class logging is turned on by default.

This class is packaged in a .zip file here: Reachability 2.0.4ddg.zip. It has two directories: Reachability itself and my version of Apple’s Reachability project. These extensions to Apple’s class are covered by the new BSD license. Hence, if you use my version, I require a public acknowledgement of my contributions in your application.

I hope you find this version of Reachability useful. May your code compile without errors and run like the wind.

NOTE: Allen Brunson found a memory leak in Reachability. This has been corrected and a new version generated, 2.0.2ddg, and placed at the link above.

NOTE: Ling Wang suggested an additional test for a WiFi+VPN condition. This has been added and a new version generated, 2.0.3ddg, and placed at the link above.

NOTE: After complaints about my added NSAssert in the -networkStatusForFlags: method, I have now surrounded the assert with a conditional compile macro. This change has been added and a new version generated, 2.0.4ddg, and placed at the link above.

SQLite Persistent Objects

I use Jeff LaMarche’s and his contributor’s SQLite Persistent Objects library in my upcoming iPhone application. This library was created before version 3 of the iPhone OS was released. Because iPhone OS v3 contained Core Data, Jeff and his contributors ceased further development. Yet, I was dependent on it and, hence, I continued private development.

My changes were primarily performance enhancements and some reorganization of the main header files to support better life cycle management of the databases. In particular, I added a static variable to hold a static NSDateFormatter. (An NSDateFormatter is surprisingly expensive to create on each SQLite transaction involving a time stamp.) I also defined a new mechanisms to hold the propertiesWithEncodedTypes as a class static. These properties are static with respect to each class. Hence, caching the dictionary, which is used on almost every call to the class, is an excellent performance enhancement.

To use this new feature to optimize your classes, you need to override +propertiesWithEncodedTypes. Here is the code your need to place in your class:

+ (NSDictionary *) propertiesWithEncodedTypes {
	
	static NSDictionary *classProperties = nil;
	
	if (classProperties == nil) {
		
		// Because it is stored in a static, we must retain it.
		classProperties = [[self propertiesWithEncodedTypes_] retain];
		
	}
	
	return classProperties;
	
} // propertiesWithEncodedTypes

Due to these enhancements this library is not thread safe. Because there are other static variables sprinkled throughout the code, which also preclude thread safety, this is not a change in the library’s lack of thread safety.

The license agreement used by this project was legally dubious. With Mr. LaMarche’s formal agreement via email, as the voice of the project, I have edited each project file to be covered by the OSI approved New BSD license. This license, while supporting the values expressed by Jeff during the creation of the project, adds liability protection to each contributor and formally defines the criteria to use the code. Let me be clear, each contributor was facing an unspecified legal liability under the old license. They are now protected. I contribute my changes to this code under the below license.

I hope you find my changes useful and the license agreement a legal improvement. Here is a link to a zip of the archive, 091023 SQLite Persistent Objects.zip. And a link to Jeff’s extremely useful presentation at the 360 iDev Conference.

Enjoy and Anon,
Andrew


SQLite Persistent Objects for Cocoa and Cocoa Touch.

Copyright (c) 2008 – 2009,
Jeff LaMarche,
All rights reserved.

Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:

* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.

* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.

* Neither the name of Jeff LaMarche nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.