Objective-C Class Properties

Saturday, April 2nd, 2011

In Objective-C, an instance variable is simply an object member variable whose value is stored uniquely for each instance of the object. In a similar manner, instance member functions operate on a particular instance of an object, and have access to the object's instance variables. Interestingly, there is also the notion of a class member function, which must be called without respect to a particular object instance, and cannot access instance variables.


So far these concepts are fairly familiar to C++ programmers, as they are very similar to the concepts of static member variables, member functions (or methods), and static methods, respectively.


Judging by a quick scan of the popular programming websites however, it's clear that significant confusion arises from the fact that Objective-C provides no direct support for class member variables, similar to the notion of a static member variable in C++.


Requirements


Interestingly, Objective-C provides a number of different ways of specifying or constraining access to instance variables, and one of the most prominent practices is the use of properties. In a nutshell, properties provide a customizable shorthand way of defining the accessors of an instance variable, and their use is strongly recommended. For more information on properties, see chapter 5 the Objective-C Programming Language.


For the purposes of this post, I wanted to experiment and see if it were possible to define an Objective-C class with the following characteristics:

  1. Declares a static (or class) member variable called myViewController

  2. Provides read-only access to the variable when accessed globally

  3. Provides read-write access to the variable when accessed via an instance

  4. Does not require knowledge of a particular class instance to access the variable

  5. Minimal redundant storage to support prescribed access to the variable

  6. Avoids potentially error-prone accesses or usage patterns

  7. Provides access, both internally and externally, via property syntax


Although this list may appear overly contrived, its motivation is simply to provide a class that shares a variable across all instances, yet also exposes this data in an instance agnostic manner to the application. By sticking close to the property syntax (leveraging proper encapsulation and sharing class access control), avoiding redundant consumption of memory, and minimizing externally specified variables, the hope is that this list enforces a more Apple-friendly design.


Declaration

Although perhaps imperfect, one simple way of achieving the stated requirements is the following solution:

@interface MyObject : NSObject {}

@property  (nonatomic, assign,
            getter=getMyViewController,
            setter=setMyViewController:)
            UIViewController * myViewController;

- (UIViewController *) getMyViewController;

- (void) setMyViewController: (UIViewController*) newController;

+ (UIViewController*) myViewController;

@end


Starting with the declaration, we've specified a new interface, MyObject, with no explicitly declared instance variables. Recall that instance variables may be added as necessary by the compiler to satisfy the synthesis of properties, but in our case this extra variable will not be inserted (details below).


We've declared one property, myViewController, and indicated that we wish to supply our own custom setter and getter implementations. Furthermore, we've declared our property as assign, as we will not be worrying about reference counting for the purposes of this explanation. Lastly, we have two instance method declarations, and one global method declaration.


At first glance this interface declaration may appear confusing due to the fact that we've declared both a property and a class interface with the same name, myViewController. This is perfectly legitimate however, and actually a necessary feature of the Objective-C language. The compiler will always be able to disambiguate between them, and their internal representations are distinct. For more information regarding the Objective-C Compiler's name disambiguation rules, see another post of mine.


Implementation


The corresponding implementation for our interface declaration is listed below. Notice how the custom setter and getter are used to direct attention to our static variable, m_myViewController. Note also that we do not synthesize our property, as we're using both a custom setter and getter, we do not wish for the compiler to provide automatic storage for an instance variable we'll never access.

@implementation MyObject
 
static UIViewController * m_myViewController = nil;
 
@dynamic myViewController;
 
+ (UIViewController*) myViewController
{
    return m_myViewController;
}
 
- (UIViewController *) getMyViewController
{
    return [ MyObject myViewController ];
}
 
- (void) setMyViewController: (UIViewController*) newController
{
    m_myViewController = newController;
}
 
@end


Conclusion


This solution provides one approach to meeting the stated objectives. It relies upon a single static variable for storage of our view controller pointer, rather than a more traditional instance variable. It enables users to access this static variable simply via a class method, without knowledge or regard to any particular instance of the class. Lastly, accesses to this variable (both internally to the class implementation and externally) are performed via syntax that closely resembles or identically matches the property syntax.


Thanks for reading! As always, comments questions and concerns are always appreciated, especially if you notice any errors or necessary corrections.