Posts Tagged ‘coding’

Objective-C: @property gotcha #1

October 26th, 2011

Sometimes “best” practices can bite you.

In Apple iOS documentation, they strongly recommend the use of declared properties to automatically generate access methods to class variables.  In header files, you would have something like this:

@interface MyClass
{
    IBOutlet UIView* view;
}

@property (nonatomic, retain) IBOutlet UIView* view;

@end

 

Technically, this generates access methods named ‘view’ and ‘setView’, but in practice one generally accesses the class variable with the dot notation (i.e., ‘self.view’) .  The implementation of this class (minus any explicit methods) would be:

@implementation MyClass

@synthesize view;

@end

 

Accessing the variable with dot notation calls the access methods (as does calling them explicitly, obviously), but simply using ‘view’ (without the ‘self’ reference) accesses the variable directly, omitting any other functionality associated with the accessors, such as (in the above example) retaining the new view.  This is generally a poor practice except in initialization and deallocation routines, where it is preferred.

So, in order to assure that one does not accidentally skip the accessors, the recommended best practice is to use the ability of @synthesize to generate accessors that access a slightly different variable name.  In other words, instead of ‘view’ and ‘setView’ referencing the ‘view’ variable, they can be instead made to access ‘view_’:

@synthesize view = view_;

 

This is, in theory, a good idea because one can only access the variable directly with the explicit addition of an underscore (in this case), and simply referencing ‘view’ instead of ‘self.view’ should produce a compiler error.  (Note that we use a trailing underscore because leading underscores already have a specific meaning in our coding guidelines.)

Problem: If you modify the class implementation as noted above to put this into practice, you introduce a bigger problem into your code.  It turns out that @synthesize actually creates a class variable if none of the specified name exists, but it does not generate a warning or error if the one of the ostensible name does exist.  In other words, the above line would create a new ‘view_’ class variable, and create accessor methods, despite the fact that ‘view’ already exists.  The ‘view’ and ‘setView’ methods modify ‘view_’, so ‘self.view’ does the same, but failing to ‘self’ reference, rather than generating the intended error, actually modifies the orphaned ‘view’ variable.  Instead of having an extra compiler check, you instead have two very similar variables in the same class and any error becomes even harder to diagnose.

If the @property/@synthesize combination essentially replaces normal variable declarations, it obviates the whole issue of these declarations.  This seems rather silly/weird, since declaring [class] variables is a staple of C[++], and the method of doing this in Objective-C is one of the first lessons taught.  Nevertheless…

Solution: To make this idea an actual best practice, at least for simple classes, omit the entire parenthesized section of the class declaration and just declare all variables via @property/@synthesize statements.  You would end up with something like the following:

@interface MyClass
@property (nonatomic, retain) IBOutlet UIView* view;
@end
@implementation MyClass
@synthesize view = view_;

- (id)init
{
    self = [super init];
    if ( self )
    {
        view_ = nil;
    }
    return self;
}

- (void)dealloc
{
    [view_ release];
    [super dealloc];
}

@end

 

All (or most) other references to the class variable would be via dot notation, ‘self.view’, which would (of course) modify the ‘view_’ variable via accessors, as desired.

Happy coding!

API Design Dilemma

February 25th, 2010

I need to decide how to define certain parameter types.

The general situation is this:  I am refactoring a piece of C++ code to be part of a separate library, so I am in the process of defining and documenting an API for using the included classes and methods.  A fundamental design consideration is that the library may be called by third parties, without access to the source code, so I need to make the code as close to bulletproof as possible.  (For internal development, at least I know the methods used, how the API will be utilized, and that it will not be abused terribly.)

During this process, I encountered a theoretical dilemma about how to handle certain parameters.  Specifically, I was working on method definitions that included sizes and counts that should never be negative (but, of course, I need to prepare for abuse).  As an example, say I am reviewing a method that is declared like this:

    bool FillBuffer ( byte* pBuffer, int nSize );

Here, pBuffer is a pointer to the buffer to be filled, and nSize is the size of that buffer.  Of course, it is not possible for a buffer to be a negative size, so my initial reaction was to redefine it as:

    bool FillBuffer ( byte* pBuffer, unsigned uSize );

This makes perfect sense from a theoretical standpoint, but then a practical consideration occurred to me.  I always verify parameters with an assertion and, for a public method (as here), abort the routine if verification fails, with an exception or error return as appropriate.  In this case, my original method would assert nSize to be greater than zero (and return false), which would catch any negatives.  The new method would only catch the case where uSize was zero, but if a careless programmer cast a signed integer (or, worse, let the compiler do it), the current validation check would not identify a problem.

So, there were a few obvious solutions that I considered:

  • I could leave the original definition alone, which would catch obvious parameter errors, but would be theoretically incorrect, and if a programmer wanted to pass the size of a static buffer, using sizeof(), there would be a signed/unsigned mismatch.
  • I could use the new method definition, which would be correct in theory, and just trust programmers not to abuse the method with invalid parameters (and let them suffer if they do).
  • I could use the new method definition and add a sanity check so an extremely large buffer size (i.e., likely a negative value cast improperly) would be rejected, but the drawback there is that any such check would be somewhat arbitrary, and it would limit the functionality for any programmer who truly wanted to use an enormous buffer.

Each of these solutions has advantages and drawbacks.  I dislike having a parameter take a type that is not accurate (though not so much as to not have written this code in the first place), but I dislike arbitrary limits even more.  However, I know that defensive design is important here, since a careless programmer is, in my experience, the most likely to complain that the library or API is at fault.  (I was once threatened with physical violence when I produced a critical review of code written by a nominal “programmer”.)

At this point, I am leaning toward a hybrid solution by overloading the method with both (or multiple) definitions, the original checking for negative sizes as usual before doing an explicit cast of the size value and passing processing to the new/correct method.  The advantage is that passing an actual negative number (or signed type) will result in that extra checking, and a programmer could pass a buffer size up to the limit of the unsigned type.  The disadvantages are the additional work needed to create the extra stub(s), loss of type checking during static analysis, and the fact that our careless friend could still cast a value to create problems (but then it should be quite obvious, at least).

This post is an exercise in the process of working through a problem by simply writing down the issues, which often results in a solution (or decision) by the time one is finished with the description.  (It did here.)  I would, however, welcome any comments on my proposed solution, or other suggestions.

Finally, yes, I know that int and unsigned are not ideal parameter types for this in the first place, but I used them for the purpose of illustration.  (The principle also applies to object counts and other similar parameter types.)

Three Steps to Apple Help, Part 3

November 25th, 2009

Accessing Apple Help from C++ Code (Carbon)

The third/final step in implementing Apple Help is programmatically displaying the main contents or individual topics within your help pages.  This, of course, assumes that you have already created a set of HTML help pages for Apple Help and then indexed and integrated these files into your Xcode project.

Accessing Apple Help from C++ using Carbon is fundamentally simple.  The Apple Help Reference contains only 4 functions (plus one constant enumeration that is no longer used).  There is a little bit of necessary mucking about with bundle references and whatnot that may be unfamiliar to programmers who have not worked with Mac development before, but it is all fairly straightforward.

In order to access Apple Help from the application, you first register your help files using the AHRegisterHelpBook() function.  This only needs to be done once, ideally during program initialization, and we do it something like this:

bool RegisterHelp ( void )
{

    CFBundleRef const bundle = CFBundleGetMainBundle ( );
    if ( !bundle )
        return false;

    CFURLRef const location = CFBundleCopyBundleURL ( bundle );
    if ( !location )
        return false;

    FSRef file;
    if ( !CFURLGetFSRef ( location, &file ) )
    {
        CFRelease ( location );
        return false;
    }

    _Error = AHRegisterHelpBook ( &file );

    CFRelease ( location );

    if ( _Error )
        return false;

    return true;

}

(Additional validity checking and error reporting has been stripped from this sample code for clarity.)

In the above example, most of the code is just to obtain the FSRef (file system reference) of the application bundle from which the help is to be displayed, and it assumes that you want help for the current application.  (Obviously, you could instead pass a reference to any other bundle and access a different help system, but that would be unusual.)

Once the help files are registered, you can display the main help page using the AHGotoPage() function (with default parameters), which we accomplish with a function similar to this:

void ShowHelpContents ( void )
{

    CFBundleRef const bundle = CFBundleGetMainBundle ( );
    if ( !bundle )
        return;

    CFStringRef const key = CFSTR( "CFBundleHelpBookName" );
    CFTypeRef const book =
        CFBundleGetValueForInfoDictionaryKey ( bundle, key );
    if ( !book )
        return;

    CFStringRef const help = (CFStringRef)book;

    _Error = AHGotoPage ( help, NULL, NULL );

}

(Additional validity checking and error reporting has been stripped from this sample code for clarity.)

You can also display a specific help topic by using the AHLookupAnchor() function, for which we use something like this:

void ShowHelpTopic ( CFStringRef topic )
{

    if ( !topic )
        return;

    CFBundleRef const bundle = CFBundleGetMainBundle ( );
    if ( !bundle )
        return;

    CFStringRef const key = CFSTR( "CFBundleHelpBookName" );
    CFTypeRef const book =
        CFBundleGetValueForInfoDictionaryKey ( bundle, key );
    if ( !book )
        return;

    CFStringRef const help = (CFStringRef)book;

    _Error = AHLookupAnchor ( help, topic );

}

(Additional validity checking and error reporting has been stripped from this sample code for clarity.)

In both of these last two examples, the function reads the CFBundleHelpBookName string from the main application bundle and uses that string for the name of the help system, passed as the first parameter to the appropriate Apple Help function.  (You could, of course, hard code this string, but if you were thinking that this is a good idea, shame on you.)

Accessing Apple Help from Objective-C (Cocoa)

If you are using Objective-C and Cocoa, much of the help system handling is done behind the scenes (which is, in part, why some programmers find Objective-C to be objectionable).  If you follow the steps in the previous two posts (Part 1 and Part 2) to insert your Apple Help into a Cocoa project, your main help system will work automatically.

The main help page in a Cocoa application is accessible by the user through the ‘Help->[ApplicationName] Help’ menu option by default.  If you wish to bring up the main page from your Objective-C code, you may need to reference an anchor on that page (see below) or use the Carbon method described above.

To access a specific help topic (anchor) from Objective-C and Cocoa, this is done through the shared NSHelpManager object using the openHelpAnchor:inBook: method.  For example, to open the ‘rules’ topic, you would use the following code:

    NSString *book = [[NSBundle mainBundle]
        objectForInfoDictionaryKey:@"CFBundleHelpBookName"];
    [[NSHelpManager sharedHelpManager]
        openHelpAnchor:@"rules" inBook:book];

The documentation for NSHelpManager is quite clear that all of its functionality is simply a number of wrappers around the functions described in the first section of this post, so you could always use those functions directly, if desired.

There you have it.  At this point, you should know enough to properly implement Apple Help in your Carbon or Cocoa application for Mac OS X.  The process is a little convoluted to suss out from the documentation, so I hope this provides a decent jump start.