Skip to content

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.

RHView and Delegate Drawing…

The delegate drawing pattern implemented by a RHView is not a decorator pattern. It is a simple delegate pattern. I intend you, though, to use it somewhat differently than a traditional delegate. A traditional delegate would be responsible for drawing directly in the RHView. And, of course, you can use it that way. I use it differently though.

I create all of my drawing commands as methods of the RHView. This allows complex graphics commands to be encapsulated in the view. The delegate becomes a drawing coordinator and does not a directly draw in the view.

Here is a simple example — a subclass of RHView to draw a graph:

#import "RHView.h"
@class Curve;
@interface GraphView : RHView {
@private Curve *curve; }
@property (retain, nonatomic) Curve *curve;
- (void) drawBorder: (CGRect) rect inContext: (CGContextRef) context; - (void) drawCurve: (CGRect) rect inContext: (CGContextRef) context;
@end

It has a single instance variable — a curve. And it has two drawing methods — -drawBorder:inContext: and -drawCurve:inContext:. The delegate object only needs to implement the RHViewDelegate protocol.

Here is a sample delegate implementation:

- (void) drawView: (GraphView *) view inRect: (CGRect) rect inContext: (CGContextRef) context {
[view drawCurve: rect inContext: context]; [view drawBorder: rect inContext: context];
}

All drawing commands are encapsulated in the subclass of RHView. Your view controller is, in my opinion, the natural delegate of the RHView. You then just create new view controllers to coordinate the new behavior. It is totally congruent with the MVC pattern.

This pattern really cleaned up my code. I hope it cleans yours up too.

An aside: the RHViewDelegate is the key mechanism needed to initiate a decorator drawing pattern.

Coordinate Systems and the iPhone…

Interesting iPhone apps draw custom views/widgets. Every platform though makes assumptions that will be good for some applications and bad for others. As the Mac OS X evolved into iPhone OS, one of the graphics assumptions changed — the handedness of the drawing coordinate system. In Mac OS X’s case, the right handed coordinate system was a natural match to traditional graphing which we all learned in high school algebra. iPhone OS uses a left handed coordinate system. The left handed system is very good for drawing text. The big difference is in the direction of the y-axis. In a right handed system, the y-axis points up; a left handed y-axis points down. If you want to draw scatter plots, then a right handed system is just easier to use.

The graphics system is called Quartz 2D. It supports general purpose transformations of every graphics action. This is how the handedness can switch between the Mac and the iPhone — Quartz 2D made it easy. Hence, to return to a right handed system, we need to use this transformation system to flip the coordinate system. We will also need to move the origin of the view from the top-left to the bottom-left corner. Two tasks: flip the coordinate system and translate the origin.

Each view in Cocoa Touch draws in exactly one method: -drawRect:. Our code needs to intercept this method and transform the coordinate system. Also, because there is a common design pattern in Cocoa Touch, delegation, we should support that too. Finally, because of the ways views are implemented in Cocoa Touch, as CALayers, our class needs to provide some methods to make it easy for layers to be rendered in our new coordinate system.

Two tasks:

  • Flip the coordinate system.
  • Translate the origin.

Three requirements:

  • Intercept -drawRect:
  • Implement a delegate pattern.
  • Provide a utility method for layer drawing.

The Right Hand View Header:

@interface RHView : UIView {
@private
	id <RHViewDelegate> delegate;
}
@property (assign, nonatomic) id <RHViewDelegate> delegate;
// Abstract methods. This must be overridden. - (void) drawRect: (CGRect) rect inContext: (CGContextRef) context;
// Concrete methods. - (CGContextRef) flipContext: (CGContextRef) context; @end

Starting at the top:

This class inherits from UIView, the standard parent class to all views in Cocoa Touch. It’s only instance variable is a pointer to a delegate that implements the RHViewDelegate protocol. As with almost all other delegate instance variables in Cocoa Touch, the delegate is assigned and not retained. It is up to the delegate to keep from being reaped.

This class has two public methods. The first method, -drawRect:inContext:, is an abstract method. It must be overridden by your subclass to draw anything. Or you must use the delegate. You cannot use both at the same time.

The second method, -flipContext:, is a utility method to transform a graphics context between coordinate systems. You should not override this method.

The alternate way to draw is with a delegate that implements the RHViewDelegate protocol.

@protocol RHViewDelegate
@required
// Draw contents into the given view, using the given bounds and context. - (void) drawView: (RHView *) view inRect: (CGRect) rect inContext: (CGContextRef) context;
@end

Because a delegate is unrelated to the view, you need to pass the view to the delegate along with the rectangle that needs to be filled in and the flipped context: -drawView:inRect:inContext:.

How does RHView work?:

I’ll start with simpler of the 2 methods: -flipContext:.

- (CGContextRef) flipContext: (CGContextRef) context {

    // Get the current transformation matrix.
    CGAffineTransform ctm = CGContextGetCTM(context);

    // Toggle the origin's position between the bottom-left and top-left.
    CGAffineTransformTranslate(ctm, 0.0, self.bounds.size.height);

    // Flip the handedness of the coordinate system.
    CGAffineTransformScale(ctm, 1.0, -1.0);

    // Apply the new coordinate system to the CGContext.
    CGContextConcatCTM(context, ctm);

    return context;

} // flipContext:

This method is rather straightforward. It implements our two tasks: flipping and translation. The key thing to recognize is that the new origin is always at the “top” of the current view. In a left handed system, the top-left point is the same as the bottom-left of a right handed system. And this is true, vice versa. The second transform, the CGAffineTransformScale, changes the sign of the y-axis. It changes the handedness of the system. That really is all that is required.

The RHView -drawRect: method has to do both the transformation and delegate dispatch. Unlike a normal UIView, you do not override -drawRect:. Because it is responsible for managing the coordinate system, it has to get the first crack at drawing the view. Hence, you need to override the -drawRect:inContext: method. The only difference between the two methods is that you will use the provided context instead of the default context. Other than that, everything about the new method is treated identically to the classical -drawRect: method. (A note: -drawRect:inContext: is using the same naming pattern as CALayer‘s delegate method -drawLayer:inContext:.)

- (void) drawRect: (CGRect) rect {

    // Convert the coordinate system to be what Quartz 2D expects.
    CGContextRef context = UIGraphicsGetCurrentContext();
    CGAffineTransform ctm = CGContextGetCTM(context);

    // Translate the origin to the bottom left.
    CGAffineTransformTranslate(ctm, 0.0, self.bounds.size.height);

    // Flip the handedness of the coordinate system back to right handed.
    CGAffineTransformScale(ctm, 1.0, -1.0);

    // Convert the update rectangle to the new coordiante system.
    CGRect xformRect = CGRectApplyAffineTransform(rect, ctm);

    // Apply the new coordinate system to the CGContext.
    CGContextConcatCTM(context, ctm);

    if (delegate != nil) {
        // The delegate gets the first crack at rendering the view.
        [delegate drawView: self inRect: xformRect inContext: context];
    } else {
        [self drawRect: xformRect inContext: context];
    }
} // drawRect:

-drawRect: has to do four tasks: 1) get the current graphics context; 2) translate and flip the coordinate system; 3) transform the drawing rectangle; 4) dispatch to either the delegate or subclass.

Getting the Code:

I’ve released this code into the public domain.
It is available here: RHView.zip.

Enjoy!

The iRush: Programming the iPhone…

’09ers versus the ’49ers: the only differences are the lack of dirt and hookers.

The iRush has been underway for 18 or so months now. The facts are clear. This is a great market to experiment with product design and business models. It is also where many small, “long tail” businesses are being formed — including ours.

Yet, this wonder of social computing, the iPhone, has been woefully underexploited. The 50K+ apps are mostly uninspired but polished attempts to bring desktop activities to the phone. The phone is a bridge device between the social realm and the intimate realm. Therein lies opportunity.

About the DDG blog…

This blog is a place for me, Andrew Donoho, to write about technical strategy, design and programming/development issues. I’ll be publishing code, primarily for the iPhone. I’ll discuss the strategic implications of technology developments. And I’ll be discussing design in both the user interface and the code.

I hope you enjoy it.