[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Objective-C class definitions are always divided into two parts: an
interface and an implementation. This division mirrors the common C
library division into a header file with function declarations, which is
distributed to all users of a library, and a source file with the
implementations, which is only used to compile the library and is generally
not distributed to users. A class interface declares instance variables,
methods and the superclass name, while the implementation file holds the
operational code that implements those methods. Typically the interface and
implementation are held in separate files, using the .h
and .m
extensions, respectively. They may, however, be merged into one file, and a
single file may implement many classes.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
The interface is included in the source using #include
:
#include "SomeClass.h" |
To ensure that a Header file is included only once, it is usual to protect it with pre-compiler defines:
#ifndef _MY_CLASS_H_INCLUDED #define _MY_CLASS_H_INCLUDED /* HEADER FILE */ #endif |
This is the standard C technique to protect header files from being included
more than once. A cleaner alternative, introduced in Objective-C, is to use
the #import
directive instead of #include
. The compiler will
automatically include #import
ed files no more than once, even if
multiple import
statements are encountered. Thus, you can do away
with the messy preprocessor conditionals in the header file.
You should be careful, however, to only use #import
for Objective-C
interface headers, and continue using #include
for standard C files.
It is possible, though not likely, that regular C headers may rely on being
included multiple times in some cases. Also, you may need to include the
compiler directive -Wno-import
to gcc to avoid a didactic warning to
this effect.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
The interface file declares new classes that can be used by source code, holding all the information necessary to use the classes from other Objective-C code. Firstly, the file reveals to the programmer the position of the class in the class hierarchy by defining exactly which is the superclass. Secondly, it informs programmers of what variables are inherited when they create subclasses. Finally, the interface file may inform other software entities of the messages that can be sent to the class object and to the instances of the class.
Interface files use the .h
extension as for ordinary C header files.
(If you use emacs, put a line “// -*-ObjC-*-
” at the top of your file
to use the correct mode.)
Here is an example of a class interface declaration:
#import <Foundation/NSObject.h> @interface Point : NSObject { @private // instance variables only accessible to instances of this class ... @protected // instance variables accessible to instances of this class or subclasses float x; float y; @public // instance variables accessible by all code ... } // class methods + (id) new; + (id) newWithX: (float)x0 Y: (float)y0; + (Point*) point; + (Point*) pointWithX: (float)x0 Y: (float)y0; // instance methods - (id) init; - (id) initWithX: (float)x0 Y: (float)y0; - (float) x; // (field accessor) - (float) y; - (void) setX: (float)newX; - (void) setY: (float)newY; @end |
@interface
and @end
.
@interface Point : Object
names the class
and links it to the superclass. If no superclass is named, and the
directive is without a colon, the compiler assumes that a root class
is being created. You more than likely don’t want to do this.
private
, protected
, or
public
. An instance’s private variables may only be accessed by
instances of this class. An instance’s protected variables may be
accessed by instances of this class or instances of subclasses of this class.
Public variables may be accessed by any code. This is analogous to the
usage in C++ and Java. If you do not mark your instance variable declaration
explicitly, it is made protected
by default.
- (float) x; |
which is a method returning a float.
- (void) setX: (float)newX; |
which is a method that returns nothing, and takes a single float as its argument.
Note. The default type for methods and messages (id
) is assumed
when a return or argument type is not explicitly declared.
For example, ’-name
’ implicitly means a method returning id
(i.e. an object). It is usually better to avoid this and use
explicit typing as in
- (NSString*) name; |
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Source code (including Objective-C implementation and interface files) may
integrate interfaces using #import
(or #include
). Thereafter
the source module may utilize the classes in those interfaces so as to:
With the exception of the root class, all working interfaces integrate a
superclass using either #import
or #include
– as was seen in
the previous simplified interface file example. As a result the vast majority
of class files begin with a standard form that includes their superclasses,
and thus places them in the class hierarchy:
#import "SomeSuperclass.h" @interface SomeClass : SomeSuperclass { // instance variables ... } // method declarations ... @end |
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
It is possible for a source module to refer to classes without including their interface files. This is useful when you just need to tell the compiler that a certain word is a class name, but you want to avoid the overhead of including the whole interface file for that class.
For example, to inform the compiler that Border
and Square
are
classes without including their full interface file, the following syntax is
used:
@class Border, Square;
Class names may also appear in interface files at times when instance variables, return values and arguments are statically typed:
#import "Foundation/NSObject.h" @class Point @interface Square : NSObject { @protected Point *lowerLeft; float sideLength; } + (id) newWithLowerLeft: (Point *)lowerLeft sideLength: (float)sideLength; - (id) initWithLowerLeft: (Point *)lowerLeft sideLength: (float)sideLength; - (Point *) lowerLeft; - (float) sideLength; - (void) setLowerLeft: (Point *)newLowerLeft; - (void) setSideLength: (float)newSideLength; @end |
Here, we see the Point
class we declared earlier being used as a
component in Square
’s definition. Because this class is only referred
to here to declare variables and method signatures, it suffices to reference
it only using the @class
directive. On the other hand, the
implementation file may need to send messages to Point
instances and
would be better of importing the interface in this case.
The compiler will produce a warning if you don’t include it, and no type checking can be performed (to see if class instances respond to the messages you send to them), but compilation will succeed. It is best to take advantage of type-checking when you can, however, and include interfaces that messages are to be sent to.
There is one situation where you must include the interface however. If
you are implementing a new class, you always need to include the interface of
the superclass; @class
cannot be used in this case because the
compiler needs to know the details of the superclass and its instance
variables etc., so as to create a fully working new class. If you try using
@class
in this situation, compilation will abort.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
An interface file declares a class, while an implementation file implements it. The separation between the interface and implementation file yields a black box concept where the programmer using the class need only be concerned with the interface and its declared methods, superclasses, and instance variables. The implementation of classes is transparent to the programmer who may use them without detailed knowledge of their structures.
Implementation files use the .m
extension, to distinguish them from
ordinary C files.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
An implementation file contents are encapsulated between
@implementation
and @end
directives:
#import "Point.h" @implementation Point // method implementations + (id)new { // statements ... } + (id)newWithX: (float)x Y: (float)y { // statements ... } // ... - (void)setY: (float)newY { // statements ... } @end |
The implementation file uses #import
to include a named interface file
holding all declarations. Then it places method implementations for the class
between @implementation
and @end
directives. Each method
declared in the interface must be implemented. Instance variables may be
referred to in instance methods (the ones with a “-” in front of them) but
not class methods (the ones with a “+”).
- (float) x { return x; } - (void) setX: (float)newX { x = newX; } |
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
To assist in writing instance methods, Objective-C provides the two reserved
words self
and super
. Self
is used to refer to
the current instance, and is useful for, among other things, invoking other
methods on the instance:
- (Foo *) foo { if (![self fooIsInitialized]) [self initializeFoo]; return foo; } |
Super
is used to refer to method implementations in the superclass of
the instance. It is useful when overriding methods and when writing
initializers, as discussed in the next section.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Instance initialization is one of the trickier aspects of getting started in
Objective-C. Recall that instances of a class are created by use of the class
alloc
method (inherited from NSObject
) but are initialized by
instance methods. This works a little differently than in C++ and Java, where
constructors are special methods that are neither class nor instance methods.
In particular, since initializer methods are inherited instance methods, they
may still be called even if you have not implemented them in your class. For
example, it is always valid to invoke
SomeComplexClass *c = [[SomeComplexClass alloc] init]; |
Even if you have not implemented init
in SomeComplexClass
, the
superclass’s implementation will be invoked, or, ultimately,
NSObject
’s if no other ancestors implement it. Obviously, this could
result in some of SomeComplexClass
’s internal state being left
uninitialized. For this reason, you should always either provide an
init
implementation, or document whether it should be used. We will
return to this concern below.
Typically, a class will also provide one or more initWith...
methods
for initialization with arguments, and it may optionally also provide
+new
methods and convenience class methods that act like constructors.
The general approach
to implementing these is illustrated here for the Point
class.
+ new { Point *point; // note "self" refers to the "Point" _class_ object! point = [[self allocWithZone: NSDefaultMallocZone()] init]; return point; } + newWithX: (float)x0 Y: (float)y0 { Point *point; point = [[self allocWithZone: NSDefaultMallocZone()] initWithX: x Y: y]; return point; } + point { Point *point; // note "self" refers to the "Point" _class_ object! point = [self new]; return AUTORELEASE(point); } + pointWithX: (float)x0 Y: (float)y0 { Point *point; point = [self newWithX: x Y: y]; return AUTORELEASE(point); } - init { return [self initWithX: 0.0 Y: 0.0]; } // this is the "designated" initializer - initWithX: (float)x0 Y: (float)y0 { self = [super init]; if (self != nil) { x = x0; y = y0; } return self; } |
Notice that, first, the convenience constructors (new
and
newWithX:Y:
) execute [self allocWithZone:]
to begin with. The
“self
” here refers to the class object, since it is used inside a
class method. Thus the effect is the same as if “[Point alloc]
”
had been executed in external code. Second, notice that the other
convenience constructors (point
and pointWithX:Y:
)
autorelease the new instance before returning it.
This is to follow the rules of memory
management discussed in Memory Management. Third,
note that the new..
methods each call a corresponding init...
method. It is not necessary to maintain such a one to one correspondence but
it is a common convention to have the convenience implementations rely on
instance init
methods as shown. Fourth, note that the use of
[self allocWithZone: NSDefaultMallocZone()]
rather than
[self alloc]
is generally unnecessary, but provides a slight
efficiency gain since +alloc
is implemented by calling
+allocWithZone:
on the default zone.
Designated Initializer
Finally, notice that the initWithX:Y:
method is marked as the
“designated” initializer. This concept is important to ensure proper
initialization for classes within a hierarchy. The designated initializer
should be the one with the most control over the nature of the new instance,
and should be the one that all other initializers “ground out” in. In
other words, all other initializers should be chained so that they either
call the designated initializer, or they call another initializer that
(eventually) calls it.
The importance of having a designated initializer is this: when a subclass is created, it need only override the designated initializer to ensure that all of its instances are properly initialized. If this is not done, external code could invoke an initializer that initializes only the superclass’s instance variables, and not the subclass’s. To avoid this, each class designates a “ground out” initializer to which other initializers ultimately delegate. Then the subclass overrides this initializer, and in its own designated initializer, makes a call to it, to ensure that the superclass is initialized properly. Thus:
@implementation SuperClass - initWithA: (int)a { return [self initWithA:a B:0]; // 0 is default value } // designated init for SuperClass - initWithA: (int)a B: (int)b { self = [super init]; myA = a; myB = b; return self; } @end @implementation SubClass // overrides SuperClass's designated init - initWithA: (int)a B: (int)b { return [self initWithA: (int)a B: (int)b C: (int)c]; } // designated init for SubClass - initWithA: (int)a B: (int)b C: (int)c { self = [super initWithA: a B: b]; myC = c; return self; } @end |
Note, as shown above, unlike in some other object-oriented languages,
’self
’ is a variable that can be redefined. For example, we could have
written the new
constructor above like this:
{ self = [[self alloc] init]; // note "self" now refers to the new instance! [self setX: 1.0]; return self; } |
Another point to note is that Objective-C does not enforce calling superclass
initializers before carrying out subclass initialization. Although above the
first call in the designated initializer was always [super ...]
, this
was not required, and if you need to set something up before super
acts, you are free to do so.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
As mentioned before, it is possible for an initialization process to, if
desired, return not a new object but an existing object. This may be done in
one of two ways. If you are doing it from a convenience class method like
new
, then use something like the following:
+ new { if (singleton == nil) singleton = [[self alloc] init]; return singleton; } |
Note this example presupposes the existence of a class variable,
’singleton
’. Class variables as such don’t exist in Objective-C but
can be simulated, as discussed below.
If you want to possibly return an existing instance from an init instance
method like init
, the procedure is slightly more complicated:
- init { if (singleton != nil) { RELEASE(self); self = RETAIN(singleton); } else { singleton = self; } return self; } |
Here, we explicitly deallocate the current instance and replace it with
the desired existing instance. Because this might happen, you should always
be careful to use the returned value from an init
method:
id anObject = [SomeClass alloc]; // this is bad: [anObject init]; // anObject might have been deallocated! // do this instead: anObject = [anObject init]; |
One scenario where this actually occurs in the GNUstep libraries is with the
class NSConnection
. It only permits one connection to exist
between any two ports, so if you call initWithReceivePort:sendPort:
when a connection for the ports exists, the method will deallocate
the newly allocated instance, and return the current conflicting object,
rather than the receiver.
In general, it is better to catch this type of requirement in a “new
”
class method rather than an instance “init
” method so as to avoid
the unnecessary allocation of instances that will not be used, however this
is not always possible given other design constraints.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
As described in Memory Management,
objects should be deallocated when they are no longer needed. When garbage
collection is not being used, this is done through explicit calls to the
dealloc
method. When GC is being used, dealloc
is still
called implicitly, and should be implemented. However the tasks of the
dealloc
method are fewer in this case.
When garbage collection is not active, the dealloc
method must
release all other objects that this instance has retained. Usually these are
those instance variables that are objects rather than primitive types. In
certain cases such as container classes, other objects must be released as
well. In addition, if the instance has acquired any external resources, such
as a network connection or open file descriptor, these should be relinquished
as well. Likewise, any memory that has been directly allocated through use
of malloc
or other functions should be released.
When garbage collection is active, the dealloc
method is still
responsible to relinquish external resources, but other GNUstep objects need
not be released, since they will be garbage collected once this instance has
been.
If you cannot be sure whether your class will be running in a garbage-collecting environment, it never hurts to execute all of the releases of other objects. This will not harm the operation of the garbage collector, though it will result in pointless calls to the retain/release methods that are stubbed out under garbage collection. If this could cause a performance hit in your application, you should use the RETAIN/RELEASE macros instead of the function calls.
Here is an example of a dealloc
implementation:
- dealloc { RELEASE(anInstanceVariableObject); NSZoneFree(NULL, myMemory); [super dealloc]; } |
Here, we use the RELEASE
macro to release an instance variable, and the
NSZoneFree
function to free memory that was earlier allocated with
NSZoneMalloc
or a related function. (See Base Library for
discussion of GNUstep’s raw memory allocation functions.) The NULL
used indicates that the memory was from the default zone, and is equivalent
to saying ’NSDefaultMallocZone()
’ instead.
Finally, notice we end with a call to [super dealloc]
. This should
always be done in dealloc
implementations, and you should never
concern yourself with deallocating structures that are associated with a
superclass, since it will take care of this itself.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Protocols in Objective-C provide a level of flexibility beyond class structure in determining what messages objects respond to. They are similar to interfaces in Java but more flexible.
There are two types of protocol in Objective-C: informal protocols, where we document methods to which objects will respond, and specify how they should behave, and formal protocols, where we provide a list of methods that an object will support in a format where the compiler can check things, and the runtime can also check that an object conforms to the protocol. Informal protocols are merely convention, but are useful where we want to say that some system will work as long as it (or its delegate) implements some subset of a group of methods. Formal protocols are of more use when we want the compiler or runtime to check that an object implements all of a group of methods itself. Formal protocols form an inheritance hierarchy like classes, and a given class may conform to more than one protocol. Thus, formal protocols are identical in many respects to Java interfaces.
As in Java, a particularly important use of protocols is in defining the methods that an object in a remote process can respond to … by setting the protocol used by a local proxy object, you can avoid having to send messages to the remote process to check what methods are available - you can simply check the local protocol object. This will be covered later in Distributed Objects.
Informal protocols are closely associated with Categories, another Objective-C language facility, and will be discussed in the next section.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
A formal protocol is declared as a series of method declarations, just like a
class interface. The difference is that a protocol declaration begins with
@protocol
rather than @interface
, and has an optional
super protocol specified in angle brackets.
@protocol List - (void) add: (id) item; - (void) remove: (id) item; - getAtIndex: (int)idx; - (void) clear; @end @protocol LinkedList <List> - (void) addFirst: (id)item; - (void) addLast: (id)item; - getFirst; - getLast; @end |
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
If you want your class to conform to a protocol, you declare it in your interface, and implement the methods in your declaration:
@interface BiQueue <LinkedList> { // instance variables ... } // method declarations ... // [don't need to redeclare those for the LinkedList protocol] - takeFirst - takeLast @end ... @implementation BiQueue // must implement both List's and LinkedList's methods ... - add: (id) item { // ... } - addFirst: (id)item { // ... } @end |
To declare conformance to multiple protocols, do something like this:
@interface ContainerWindow < List, Window > ... @end |
The implementation must include all methods in both protocols.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
To use a formal protocol, simply send objects the messages in the protocol. If you want type-checking, you must either use the type of a class implementing the protocol, or use a special syntax:
... BiQueue queue = [[BiQueue alloc] init]; // send a LinkedList message [queue addFirst: anObject]; // alternatively, we may stipulate only that an object conforms to the // protocol in the following way: id<LinkedList> todoList = [system getTodoList]; task = [todoList getFirst]; ... |
In the last part of this example, we declare that todoList
is an
object that conforms to the LinkedList
protocol, but do not specify
what class it may be an instance of.
If you are not sure the returned object does indeed conform to the protocol you are interested in, you can check it:
if ([anObject conformsToProtocol: aProtocol] == YES) { // We can go ahead and use the object. } else { NSLog(@"Object of class %@ ignored ... does not conform to protocol", NSStringFromClass([anObject class])); } |
Finally, you can specify an object conforming to multiple protocols in the same way you declare it in an interface:
id <LinkedList, Window> windowContainerOfUnknownClass; |
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Categories provide a way in Objective-C to add new methods to an existing class, without declaring a subclass. Once the category is declared and implemented, all instances of the existing class that are created will include the capability to respond to the new methods. Furthermore, subclasses of the class will inherit these methods. However, it is not possible to add instance variables to a class using a category. Categories do not have an obvious parallel in other major object-oriented languages (with the exception of Ruby), but it is well worth taking the trouble to understand them and the benefits they can provide.
A category is declared in connection with the class it is going to modify. (You can think of it as a new “category” of instances of this class.)
#import "Point.h" @interface Point (Transformable) - translateByX: (float)tx Y: (float)ty; - rotateByAngle: (float)radians; - scaleByAmountX: (float)xscale Y: (float)yscale; @end |
You then provide an implementation file more or less analogously to that for a class, where you implement just the new methods:
#import "PointTransformable.h" @implementation Point (Transformable) - (void) translateByX: (float)tx Y: (float)ty { x += tx; y += ty; return self; } - (void) rotateByAngle: (float)radians { // ... } - (void) scaleByAmountX: (float)xscale Y: (float)yscale { // ... } @end |
Notice that you have access to instance variables of the class you are creating a category of; this includes private and protected variables.
One of the primary uses of categories is illustrated by this example. Suppose
you are working with a third party drawing package that uses some geometrical
classes such as Point
and Line
. You are developing an animation
program based on the package and need the ability to move things around.
Rather than employing a complex subclassing or aggregation scheme to add these
capabilities, you simply define the Transformable
category for each of
the geometrical entities. At runtime, all instances of these entities,
whether created by you or the package itself, have the additional methods.
The presence of these methods does not affect the existing operation of this
or any third party package, but allows you to conveniently implement the
enhanced functionality you need.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
You can also use categories to override methods that a class already has. If
you do so, you cannot access an existing implementation in the class itself,
however you can still call [super someMethod]
to access an
implementation inherited from a superclass. You obviously need to be careful
not to break existing functionality.
You can add multiple categories to a class by declaring them and implementing them separately. Instances of the class will then implement all of the categories declared. The order in which the category implementations are searched for methods is not defined, therefore you cannot override a method implemented in one category with an implementation in another.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Categories are not just useful for extending an existing class. Another major use for categories is to separate the implementation of a new class into a number of source files. (Each file implements one category of the new class, and at runtime instances of the class respond to the methods in all the categories.) The benefits of this program development strategy include: grouping subject-oriented methods; incremental compilation for large classes; helping to logically divide the class when being created by a number of developers; and, permitting configuration-specific classes targeting particular applications.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
As described in the previous section, in addition to the formal protocol
facility described, Objective-C provides for informal protocols. An
informal protocol is essentially a category declaration without an
implementation. Usually, the informal protocol is declared as a category for
a high-level object, such as NSObject
, then each class that actually
wishes to implement something in the protocol lists the methods it chooses to
implement in its interface and provides implementations in its
implementation.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Unlike most object-oriented languages Objective-C does not provide for method scoping. Instead, all methods are effectively public. Often, however, it is useful to have internal “utility” methods that help a class do its job but are hidden from external use. Rather than cluttering up the class’s API with a bunch of methods marked “do not use”, one wants to make these methods visible only to subclasses, or only to the class itself. Categories can help in this regard.
Using Categories
One common approach is to define a category within a class’s implementation file:
#import "Point.h" @interface Point (Private) -(BOOL) isPositiveQuadrant; @end @implementation Point // public method implementations ... @end @implementation Point (Private) -(BOOL) isPositiveQuadrant { return (x > 0) && (y > 0) ? YES : NO; } @end |
All of this code would appear in the file Point.m
. What this does is
add a category to Point defining the private methods. Since external code
only “knows about” Point
through its interface file, these additional
methods are effectively invisible. However, you should be aware that external
code is not prevented from actually calling the private methods, if it happens
to know about them. However the compiler will produce a warning if you try
to do this with a typed variable:
Point *p = [[Point alloc] init]; // works, but produces a compile warning BOOL b = [p isPositiveQuadrant]; |
The bright side of this is it allows you to simulate protected methods as
well. For this, the writer of a subclass must be informed in some way about
the protected methods, and they will need to put up with the compiler
warnings. Alternatively, you could declare the Protected category in a
separate interface file (e.g., “PointProtected.h
”), and provide this
interface file with the understanding that it should only be imported and used
by a subclass’s interface file.
Using Convention
Another approach to providing protected methods that the class or subclass can use is to prefix these methods with an underscore (’_’). These methods will still be visible publicly, but programmers will know, by convention, not to use them externally, and the GNUstep documentation system will automatically mark these in API documentation as off-limits.
An alternative approach to providing private methods is to simply declare them as functions within the implementation file itself. The catch to this is that these functions will not have access to the class’s instance variables. You will need to pass these in manually whenever you invoke them from an ordinary method.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
While Objective-C does not provide for variables that are associated with the
class as a whole rather than an instance, these are often useful. It is
possible to simulate them to a limited extent by declaring static variables in
the implementation file for the class (inside the @implementation
block). The variables will not be available to subclasses, unless they
explicitly declare them “extern
” and are compiled at the same time.
...
[ << ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
This document was generated by Adam Fedor on December 24, 2013 using texi2html 1.82.