2011年10月24日星期一

The Complete List of Objective-C 2.0 @ Compiler Directives


I haven’t been able to find a list of all Objective-C @ compiler directives in one place. We all know the keywords like @interface and @implementation but others like @dynamic and @encode are lesser known, and possibly even much less understood.
Although I know most of them already, I couldn’t shake the feeling that I may be missing a hidden gem. So I made an effort to document all the Objective-C @ compiler directives in one place.

@class
Used for class forward declarations. Declares class as known without having to import the class’ header file.
@class ClassName;
Note, unlike with @protocol and @selector you can not write the following to get the Class object by name:
// ERROR: this doesn't work!
Class c = @class(ClassName);
Instead use:
Class c = [ClassName class];

@protocol @required @optional @end
Marks the start of a protocol declaration. A @protocol can optionally declare that it must conform to other protocols.
@protocol ProtocolName <aProtocol, anotherProtocol>
@required
  // method declarations
@optional
  // method declarations
@end
Like with @selector you can use @protocol to get a protocol object by name:
-(void) aMethod
{
    Protocol *aProtocol = @protocol(ProtocolName);
}
Dependent Directives:
  • @required (default) – Declares the methods following the @required directive as required (default).
  • @optional – Declares the methods following the @optional directive as optional. Classes implementing this protocol can decide whether to implement an optional method or not. Classes making use of the protocol must test optional protocol methods for existence. For example:
    [object respondsToSelector:@selector(optionalProtocolMethod)];
  • @end – Marks the end of the protocol declaration.

@interface @public @package @protected @private @property @end
Marks the start of a class or category declaration.
Class declaration:
While SuperClassName is optional, Objective-C classes should derive from NSObject either directly or indirectly. The @interface for a class declaration can optionally declare that it conforms to other protocols.
@interface ClassName : SuperClassName <aProtocol, anotherProtocol>
{
@public
  // instance variables
@package
  // instance variables
@protected
  // instance variables
@private
  // instance variables
}

// property declarations
@property (atomic, readwrite, assign) id aProperty;

// public instance and/or class method declarations
@end
Category declaration:
The @interface of a Objective-C category can not add instance variables. But it can optionally declare to conform to (additional) protocols. CategoryName can be omitted (leaving only the empty brackets) if the category is added to the implementation file of the class that it extends, in order to declare methods as “private”.
@interface ClassName (CategoryName) <aProtocol, anotherProtocol>

// property declarations
@property (atomic, readwrite, assign) id aProperty;

// method declarations
@end
Dependent Directives:
  • @public – Declares the instance variables following the @public directive as publicly accessible. Public instance variables can be read and modified with pointer notation:
    someObject->aPublicVariable = 10;
  • @package – Declares the instance variables following the @package directive as public inside the framework that defined the class, but private outside the framework. This applies only to 64-bit systems, on 32-bit systems @package has the same meaning as @public.
  • @protected (default) – Declares the instance variables following the @protected directive as accessible only to the class and its derived classes.
  • @private – Declares the instance variables following the @private directive as private to the class. Not even derived classes can access private instance variables.
  • @property – Declares a property which can be accessed with dot notation. The @property can be followed by optional brackets within which special keywords (property modifiers) specify the exact behavior of the property. The property modifiers are:
    • readwrite (default), readonly – Generate both setter & getter methods (readwrite), or only the getter method (readonly).
    • assign (default), retain, copy – Only applicable for properties that can be safely cast to id. Assign simply assigns the passed value – retain sends release to the existing instance variable, sends retain to the new object, assigns the retained object to the instance variable – copy sends release to the existing instance variable, sends copy to the new object, assigns the copied object to the instance variable. In the latter two cases you are still responsible for sending release (or assigning nil) to the property on dealloc.
    • atomic (default), nonatomic – Atomic properties are thread-safe, nonatomic properties are prone to synchronization issues if accessed from multiple threads. Nonatomic property access is faster than atomic and often used in single-threaded apps, or in cases where you’re absolutely sure the property will only be accessed from one thread.
    • weak (default), strong – Available if automatic reference counting (ARC) is enabled. The keyword strong is synonymous to retain, while weak is synonymous to assign, except that a weak property is automatically set to nil should the instance be deallocated. Note thatweak is only available in iOS 5 or newer and Mac OS X 10.7 (Lion) or newer.
  • @end – Marks the end of the interface declaration.

@implementation @synthesize @dynamic @end
Marks the start of a class’ or category implementation.
Class implementation:
@implementation ClassName
@synthesize aProperty, bProperty;
@synthesize cProperty=instanceVariableName;
@dynamic anotherProperty;

// method implementations
@end
Category implementation:
@implementation ClassName (CategoryName)
@synthesize aProperty, bProperty;
@synthesize cProperty=instanceVariableName;
@dynamic anotherProperty, bnotherProperty;

// method implementations
@end
Dependent Directives:
  • @synthesize – Instruct compiler to automatically generate property setter and getter methods for the given (comma seperated list of) properties. The setter and getter methods are generated according to the property modifiers. If the instance variable is not named exactly like the@property, you can specify the instance variable name following the equals sign.
  • @dynamic – Tells the compiler that the necessary setter and getter methods for the given (comma seperated list of) properties will be implemented manually, or dynamically at runtime. Accessing a dynamic property will not generate a compiler warning, even if the getter/setter is not (yet) implemented. You will want to use @dynamic in cases where property getter and setter methods need to perform custom code.
  • @end – Marks the end of the implementation of the class.

@throw @try @catch @finally
Throwing and Handling exceptions:
@try
{
    // code that might throw an exception … like this one:
    NSException *exception = 
        [NSException exceptionWithName:@"ExampleException"
                                reason:@"In your face!"
                              userInfo:nil];
    @throw exception;
}
@catch (CustomException *ce)
{
    // CustomException-specific handling ...
}
@catch (NSException *ne) 
{
    // generic NSException handling ...

    // to simply re-throw the caught exception in a catch block:
    @throw;
}
@finally 
{
    // code that runs whether an exception occurred or not ...
}

@synchronized
Encapsulates code in a mutex lock. It ensures that the block of code and the locked object can only be accessed by one thread at a time. See mutual exclusion.
-(void) aMethodWithObject:(id)object
{
   @synchronized(object)
   {
      // code that works with locked object 
   }
}

@autoreleasepool
In an app that has ARC (automatic reference counting) enabled, you must use @autoreleasepool as a replacement for the NSAutoreleasePool class. The @autoreleasepool is about six times faster than using NSAutoreleasePool, therefore Apple recommends its use even for non-ARC projects.
You should not declare a variable inside the @autoreleasepool block and continue to use the variable after the @autoreleasepool block. Such code should be avoided or refactored.
-(void) aMethod
{
    @autoreleasepool
    {
        // code that creates a large number of temporary objects
    }
}

@selector
Returns the selector type SEL of the given Objective-C method. Generates compiler warning if the method isn’t declared or doesn’t exist.
-(void) aMethod
{
    SEL aMethodSelector = @selector(aMethod);
    [self performSelector:aMethodSelector];
}

@encode
Returns the character string encoding of a type.
-(void) aMethod
{
    char *enc1 = @encode(int);                 // enc1 = "i"
    char *enc2 = @encode(id);                  // enc2 = "@"
    char *enc3 = @encode(@selector(aMethod));  // enc3 = ":"

    // practical example:
    CGRect rect = CGRectMake(0, 0, 100, 100);
    NSValue *v = [NSValue value:&rect withObjCType:@encode(CGRect)];
}

@compatibility_alias
Allows you to define an alias name for an existing class. The first parameter is the alias for a class name, a class with this name must not exist. The second parameter is the name of an existing class that the alias refers to.
@compatibility_alias AliasClassName ExistingClassName
From then on you can use AliasClassName in place of ExistingClassName. This can be useful after refactoring a class’ name without modifying its behavior, you can use @compatibility_alias to allow existing code using the refactored class to continue to work without refactoring.
@”string”
Declares a constant NSString object. Such strings do not need to be retained or released.
-(void) aMethod
{
    NSString* str = @"This is a constant string.";
    NSUInteger strLength = [@"This is legal!" length];
}

Summary

I hope you enjoyed this list and hopefully learned something from it. If you know there’s a directive missing from the list, please add a comment and I will update the post!
If you liked this list please tweet, like or plus-one it, thank you!

没有评论:

发表评论