added several new texi files that I forgot to commit before with new manual update: AdvancedMessaging, BaseLibrary, Compliance, ExceptionHandling, GSDoc; removed outdated files that I forgot to remove: AdvancedTopics

git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@19679 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
Adrian Robert 2004-07-04 14:24:17 +00:00
parent 49d11595cd
commit 948b5dfb97
8 changed files with 2441 additions and 130 deletions

View file

@ -0,0 +1,392 @@
@paragraphindent 0
@node Advanced Messaging
@chapter Advanced Messaging
@cindex advanced messaging
@cindex messaging, advanced techniques
Objective-C provides some additional possibilities for message routing besides
the capabilities described so far (inheritance and categories). One of the
most important is that it is possible for an object, upon receiving a message
it has not been set up to respond to, to @i{forward} that message to another
object. A second important capability, which forwarding relies on, is the
ability to represent method implementations directly in code. This supports
various reflective operations as well as optimization where messages are sent
many times.
@section How Messaging Works
Sending an Objective-C message requires three types of information:
@itemize @bullet
@item
The message @b{receiver} - the object which is to perform the request.
@item
The message @b{selector} - this identifies the message, and is used to
locate the excecutable code of the corresponding @b{method} by searching the
structure of the class, and if necessary its superclasses, for an
implementation.
@item
The message @b{arguments} - once the implementation has been found, these are
simply passed to the method on the stack as in an ordinary function call.
@end itemize
In the message '@code{[taskArray insertObject: anObj atIndex: i]}', the
receiver is ``@code{taskArray}'', the selector is
``@code{insertObject:atIndex:}'', and the arguments are ``@code{anObj}'' and
``@code{i}''. Notice that the selector includes the argument titles and both
colons, but not the argument names. In other words, this method might have
been declared as '@code{- (void) insertObject: (id)anObject atIndex:
(unsigned)index;}', but the ``@code{anObject}'' and ``@code{index}'' are just
used for tracking the arguments within the method implementation code and not
for looking up the method itself.
The following sequence of events would occur on sending this message at
runtime:
@enumerate
@item
The internal @code{isa} pointer of the @b{receiver} (@code{taskArray}) is used
to look up its class.
@item
The class representation is searched for a method implementation matching the
@b{selector} (@code{insertObject:atIndex:}). If it is not found, the class's
superclass is searched, and recursively its superclass, until an
implementation is found.
@item
The implementation is called, as if it were a C function, using the
@b{arguments} given (@code{anObj} and @code{i}), and the result is returned to
the code sending the message.
@end enumerate
In fact, when the method implementation is actually called, it additionally
receives two @i{implicit} arguments: the @b{receiver} and the @b{selector}.
These additional hidden arguments may be referred to in the source code by the
names @code{self} and @code{_cmd}.
The process of looking up the method implementation in the receiver at runtime
is known as dynamic binding. This is part of what makes the language powerful
and flexible, but it is inevitably (despite clever caching strategies used in
the runtime library) a little slower than a simple function call in C. There
are, however, ways of short-circuiting the process in cases where performance
is at a premium. Before discussing this, we must first cover the concepts of
selectors and implementations in greater detail.
@section Selectors
So far we have been using the following syntax to send messages to objects:
@example
[myArray removeObjectIdenticalTo: anObject];
@end example
The example sends the message named @code{removeObjectIdenticalTo:} to
@code{myArray} with the argument @code{anObject}.
An alternative method of writing this is the following:
@example
SEL removalSelector = @@selector(removeObjectIdenticalTo:);
[myArray performSelector: removalSelector withObject: anObject];
@end example
Here, the first line obtains the desired method selector in the form of a
compiled representation (not the full ASCII name), and the second line sends
the message as before, but now in an explicit form. Since the message that is
sent is now effectively a variable set at runtime, this makes it possible to
support more flexible runtime functioning.
@subsection The Target-Action Paradigm
One conventional way of using selectors is called the @i{target-action}
paradigm, and provides a means for, among other things, binding elements of a
graphical user interface together at runtime.
The idea is that a given object may serve as a flexible signal sender if it
is given a receiver (the @i{target}) and a selector (the @i{action}) at
runtime. When the object is told to send the signal, it sends the selector
to the receiver. In some variations, the object passes itself as an
argument.
The code to implement this paradigm is simple -
@example
- (id) performAction
@{
if (target == nil || action == 0)
@{
return nil; // Target or action not set ... do nothing
@}
if ([target respondsToSelector: action] == NO)
@{
return nil; // Target cannot deal with action ... do nothing
@}
return [target performSelector: action withObject: self];
@}
@end example
As an example, consider a graphical button widget that you wish to execute
some method in your application when pressed.
@example
[button setTarget: bigMachine]
[button setAction: @@selector(startUp:)];
@end example
Here, @code{button} stores the given target and action in instance variables,
then when it is pressed, it internally calls a method like
@code{performAction} shown above, and sends the message ``@code{[bigMachine
startUp: button]}''.
If you are used to programming with events and listeners in Java, the
target-action paradigm provides a lighter-weight alternative for the most
common case where only one object needs to be informed when an event occurs.
Rather than writing or extending a special-purpose adaptor class, you just
register the method you want called directly with the actuating element. If
you need to send the event to multiple objects, however, you would need to
write a special method to multiplex the event out. This would be
approximately comparable effort to what is always required in Java, and is
only needed in the minority of cases.
@subsection Obtaining Selectors
In addition to using the compile-time @code{@@selector} operator, there are a
couple of other ways of obtaining selectors.
@itemize @bullet
@item
In a method implementation, you can always obtain the current selector from
the variable @code{_cmd}:
@example
- (void) removeObjectIdenticalTo: (id)anObject
@{
SEL mySelector = _cmd;
// ...
@}
@end example
@item
At any point, you can use the @code{NSSelectorFromString()} function -
@example
SEL mySelector = NSSelectorFromString(@@"removeObjectIdenticalTo:");
@end example
In reality, you would never use @code{NSSelectorFromString} for a constant
string as shown; @code{@@selector} would do and is more efficient, since is a
compile-time operator. Its chief utility lies in the case where the selector
name is in a variable value (for whatever reason).
@end itemize
If you ever need to test the contents of a @code{SEL} variable for equality
with another, you should use the function @code{sel_eq()} provided as part of
the GNU Objective-C runtime library. This is necessary because, while the
compiler tries to ensure that compile-time generated references to selectors
for a particular message point to the same structure, selectors produced at
runtime, or in different compilation units, will be different and a simple
pointer equality test will not do.
@subsection Avoiding Messaging Errors when an Implementation is Not Found
Using @b{typed} objects as shown below, the compiler would forewarn
you if the @code{anObject} was unable to respond to the @code{alert:}
message, as it knows what type of object @code{anObject} is:
@example
SomeClass *anObject; // an instance of the 'SomeClass' class
anObject = [[SomeClass alloc] init]; // build and initialize the object
[anObject alert: additionalObject]; // compiler warns if 'alert:' not
// defined in SomeClass or a superclass
@end example
However at times the compiler will not forewarn you that a message will
attempt to invoke a method that is not in the @b{receiver's} repertoire. For
instance, consider the code below where @code{anObject} is not known to
implement the @code{alert:} message:
@example
id anObject; // arbitrary object;
anObject = [[SomeClass alloc] init]; // build and initialize object
[anObject alert: additionalObject]; // compiler cannot check whether
// 'alert' is defined
@end example
In this case, the compiler will not issue a warning, because it only knows
that @code{anObject} is of type @code{id} @dots{} so it doesn't know what
methods the object implements.
At runtime, if the Objective-C runtime library fails to find a @b{method
implementation} for the @code{alert:} message in the @code{SomeClass} class
or one of its superclasses, an exception is generated. This can be avoided
in one of two ways.
The first way is to check in advance whether the method is implemented:
@example
if ([anObject respondsToSelector: @@selector(alert:)] == YES)
@{
[anObject alert: additionalObject]; // send it a message.
@}
else
@{
// Do something else if the object can't be alerted
@}
@end example
The second way is for the object the message was sent to to @i{forward} it
somewhere else.
@section Forwarding
@cindex forwarding
What actually happens when the GNU Objective-C runtime is unable to find a
method implementation associated with an object for a given selector is that
the runtime instead sends a special @code{forwardInvocation:} message to the
object. (Other Objective-C runtimes do the same, but with a slightly
different message name and structure.) The object is then able to use the
information provided to handle the message in some way, a common mechanism
being to forward the message to another object known as a @b{delegate}, so
that the other object can deal with it.
@example
- (void) forwardInvocation: (NSInvocation*)invocation
@{
if ([forwardee respondsToSelector: [invocation selector]])
return [invocation invokeWithTarget: forwardee];
else
return [self doesNotRecognizeSelector: [invocation selector]];
@}
@end example
@itemize @bullet
@item
@b{@code{invocation}} is an instance of the special @code{NSInvocation} class
containing all the information about the original message sent, including its
@b{selector} and its arguments.
@item
@b{@code{forwardee}} is an instance variable containing the @code{id} of an
object which has been determined to be likely to implement methods that this
object does not.
@item
The @b{@code{NSInvocation}} class has a convenience method that will pass the
message on to a target object given as argument.
@item
The @b{@code{doesNotRecognizeSelector}} method is a fallback which is
implemented in @code{NSObject}. Unless it has been overidden, its behavior
is to raise a runtime exception (a @code{NSInvalidArgumentException} to be
exact), which generates an error message and aborts.
@end itemize
Forwarding is a powerful method for creating software patterns. One of these
is that forwarding can be used to in effect provide a form of multiple
inheritance. Note, however that, unlike inheritance, a forwarded method will
not show up in tests like @code{respondsToSelector} and
@code{isKindOfClass:}. This is because these methods search the inheritance
path, but ignore the forwarding path. (It is possible to override them
though.)
Another pattern you may come across is @i{surrogate object}: surrogates
forward messages to other objects that can be assumed to be more complex. The
@code{forwardInvocation:} method of the surrogate object receives a message
that is to be forwarded; it determines whether or not the receiver exists, and
if it does not, then it will attempt to create it. A @b{proxy} object is a
common example of a surrogate object. A proxy object is useful in a remote
invocation context, as well as certain scenarios where you want one object to
fulfill functions of another.
@ignore
Need to talk about NSMethodSignature and methodSignatureForSelector?
@end ignore
@section Implementations
Recall that when a message is sent, the runtime system searches for a method
implementation associated with the recipient object for the specified
selector. (Behind the scenes this is carried out by a function
``@code{objc_msgSend()}''.) This may necessitate searches across multiple
superclass objects traversing upwards in the inheritance hierarchy, and takes
time. Once the runtime finds an implementation for a class, it will cache the
information, saving time on future calls. However, even just checking and
accessing the cache has a cost associated with it. In performance-critical
situations, you can avoid this by holding on to an implementation yourself.
In essence, implementations are function pointers, and the compiler provides a
datatype for storing them when found at runtime:
@example
SEL getObjSelector = @@selector(getObjectAtIndex:);
// get the 'getObjectAtIndex' implementation for NSArray 'taskArray'
IMP getObjImp = [taskArray methodForSelector: getObjSelector];
// call the implementation as a function
id obj = (getObjImp)( taskArray, getObjSelector, i );
@end example
Here, we ask the runtime system to find the '@code{taskArray}' object's
implementation of '@code{getObjectAtIndex}'. The runtime system will use the
same algorithm as if you were performing a method call to look up this code,
and then returns a function pointer to it. In the next line, this pointer is
used to call the function in the usual C fashion. Notice that the signature
includes both the object and the selector -- recall that these are the two
implicit arguments, @code{self} and @code{_cmd}, that every method
implementation receives. The actual type definition for @code{IMP} allows
for a variable number of additional arguments, which are the explicit
arguments to the method call:
@example
typedef id (*IMP)(id, SEL, ...);
@end example
The return type of @code{IMP} is @code{id}. However, not all methods return
@code{id}; for these others you can still get the implementation, but you
cannot use an @code{IMP} variable and instead must cast it yourself. For
example, here is such a cast for a method taking a double and returning
'@code{double}':
@example
double (*squareFunc)( id, SEL, double );
double result;
squareFunc = (double (*)( id, SEL, double ))
[mathObj methodForSelector: @@selector(squareOf:)];
result = squareFunc(mathObj, @@selector(squareOf:), 4);
@end example
You need to declare such a function pointer type for any method that returns
something besides @code{id} or @code{int}. It is not necessary to declare the
argument list (@code{double}) as we did above; the first line could have been
``@code{double (*squareFunc)( id, SEL, @b{...} )}'' instead.
An excellent exposition of the amount of time saved in using
@code{methodForSelector} and other details of the innards of Objective-C and
the Foundation may be found here:
@url{http://www.mulle-kybernetik.com/artikel/Optimization/opti-3.html}.
You should realize that it is only worth it to acquire the @code{IMP} if you
are going to call it a large number of times, and if the code in the method
implementation itself is not large compared with the message send overhead.
In addition, you need to be careful not to call it when it might be the wrong
function. Even when you are sure of the class of the object you are calling
it on, Objective-C is sufficiently dynamic that the correct function could
change as a program runs. For example, a new category for a class could be
loaded, so that the implementation of a method changes. Similarly, a class
could be loaded that poses as another, or one that was posing stops doing so.
In general, @code{IMPs} should be acquired just before they are to be used,
then dropped afterwards.
@comment Making Forwarding Transparent
@page

View file

@ -1,130 +0,0 @@
@paragraphindent 0
@node Advanced Topics
@chapter Advanced Topics
@cindex advanced topics
@section Forwarding
@cindex forwarding
When an object is unable to respond to a message, the Objective-C
runtime sends a @code{forwardInvocation:} message to the object, and
the object is then able to use the information provided to handle the
message in some way, a common mechanism being to forward the message
to another object known as a @b{delegate}, so that the other object
can deal with it.
@example
- (void) forwardInvocation: (NSInvocation*)objectInvoke
@{
if ([forwardObject respondsToSelector: [objectInvoke selector]])
return [objectInvoke invokeWithTarget: forwardObject];
else
return [self doesNotRecognizeSelector: [objectInvoke selector]];
@}
@end example
@itemize @bullet
@item
@code{objectInvoke} is another object (of the @code{NSInvocation} class)
which has all the information about the original message sent, including
its @b{selector} and its arguments.
@item
@code{self} refers to the object or receiver.
@end itemize
@b{Note. this is a powerful method for creating software patterns for
multiple inheritance, journaling, and dispatching messages to
dynamically loaded code.}
@subsection Forwarding and Multiple Inheritance
Forwarding is a form of multiple inheritance. The diagram below shows a simple scenario where an instance of the @code{Chat} class passes the @b{negotiate} message to an instance of the @code{ChatTwo} class. The forwarding object therefore inherits methods from its own inheritance path and from that of the receiving object.
@subsection Surrogate Objects
Surrogate objects forward messages to objects that can be assumed to be more complex. The @code{forwardInvocation:} method of the surrogate object receives a message that is to be forwarded; it determines whether or not the receiver exists, and if it does not, then it will attempt to create it. A @b{proxy object} is a common example of a surrogate object. A proxy object performs obvious functions that we have already discussed:
@itemize @bullet
@item
provides a local address for a remote object
@item
queues messages
@item
forwards messages to typically remote receivers
@item
copies and retrieves arguments over the connection.
@end itemize
@subsection Forwarding vs Inheritance
The main difference between @b{Forwarding} and @b{Inheritance} surfaces in the application of methods like @code{respondsToSelector} and @code{isKindOfClass:}. This is because these methods search the inheritance path, but ignore the forwarding path.
(See Section 1.6.6 @code{respondsToSelector.})
@b{Note. @code{respondsToSelector} does not trace the forwarding chain, and can therefore erroneously report that an object does not respond to a particular message, when it does.}
@comment Making Forwarding Transparent
@section Exception Handling
@section Copying, Comparing, Hashing Objects
@itemize @bullet
@item
deep copy vs swallow copy
@item
simple copy vs mutable copy
@item
isEqual:, hash
@end itemize
@section Dictionaries, Arrays, Containers
@section Coding
@itemize @bullet
@item
Possibilities offered by Coding
@item
Type Encoding
@end itemize
@section Property Lists
@itemize @bullet
@item
What are property lists
@end itemize
@section Bundles
@section UserDefaults
@section Threading
General discussion about threading with gnustep base, what is
thread-safe, what is not, how to start new threads, NSThread briefly
introduced with examples.
[Nicola: important: talk about NSConnection enableMultipleThreads]].

View file

@ -0,0 +1,983 @@
@paragraphindent 0
@node Base Library
@chapter Base Library
@cindex base library
The GNUstep Base library is an implementation of the OpenStep @i{Foundation},
a nongraphical API supporting for data management, network and file
interaction, date and time handling, and more. Much of the API consists of
classes with defined methods, but unlike many ``class libraries'' it also
includes functions and macros when these are more appropriate to the
functionality.
Note that many other APIs developed subsequently to OpenStep are also called
``Foundation'' -- the Java standard classes and the Microsoft Windows C++
class library are two prominent examples. In OpenStep, however, the term only
applies to a non-graphical library; the graphical component is referred to as
the @i{Application Kit}, or ``AppKit'' for short.
Although the OpenStep API underwent several refactorings subsequent to its
first release as part of NeXTstep, deprecated and superseded classes and
functions have not been retained. Therefore the library still boasts a
minimal footprint for its functionality.
In some cases, GNUstep has supplemented the OpenStep API, not to provide
alternative means of achieving the same goals, but to add new functionality,
usually relating to technology that did not exist when the OpenStep
specification was finalized, but has not, for whatever reason, been added by
Apple to the Cocoa APIs. These additions are called, appropriately enough,
the @i{Base Additions} library, and include classes, functions, and macros.
XML parsing facilities, for example, are provided as part of this library.
In addition, methods are sometimes added to Foundation classes. These are
specially marked in the documentation and can even be excluded at compile time
(a warning will be generated if you try to use them) if you are writing code
intended to be ported to OpenStep or Cocoa compliant systems. In addition,
Cocoa has made additions to OpenStep and these are marked as ``MacOS-X''. For
information on how to set compile flags, see @ref{Compliance to Standards}.
In deciding whether to use a given API, you need to weigh the likelihood you
will need to port the application to a platform where it will not be
available, and in that case, how much effort would be required to do without
the API. If you are aiming for full portability from the start (only a
recompile needed), then you should of course avoid APIs that will not be
available. However in other cases it can be better to use whichever APIs are
best suited initially so that early development and debugging will be as
efficient as possible -- as long as major redesign would not be required to
later avoid these APIs.
Below, the Base and Base Additions APIs are covered in overview fashion,
organized according to functionality. For detailed documentation on
individual classes and functions, you should consult the GSDoc API references
for @uref{../Reference/index.html, Base} and
@uref{../../BaseAdditions/Reference/index.html, Base Additions}. It may be
helpful, when reading this chapter, to keep a copy of this open in another
browser window for reference.
@section Copying, Comparing, Hashing Objects
Often in object-oriented code you need to make a duplicate copy of an existing
object. The @code{NSObject} method @code{-(id) copy} provides a standard
means of acquiring a copy of the object. The @i{depth} of the copy is not
defined. That is, if an object has instance variables or other references to
other objects, they may either themselves be copied or just the references to
them will be copied. The root class @code{NSObject} does @i{not} implement
the copy method directly; instead it calls the @code{-copyWithZone} method,
which is the sole method defined in the @code{@i{NSCopying}} informal
protocol. @code{NSObject} does not implement this protocol. If you want
objects of your class to support copying, you must implement this method
yourself. If it is not implemented, the @code{-copy} method will raise an
exception if you call it.
There is a related method @code{-(id) mutableCopy} (and an
@code{@i{NSMutableCopying}} informal protocol with a
@code{mutableCopyWithZone} method) which will be explained in the following
section.
GNUstep, largely via the @code{NSObject} class, provides a basic framework for
comparing objects for equality and ordering, used for sorting, indexing, and
other programming tasks. These operations are also used in several crucial
places elsewhere within the base library itself. For example, containers such
as lists, sets, and hash maps are discussed in the next section utilize these
methods.
The @code{- (BOOL) isEqual} method in @code{NSObject} is useful when you want to
compare objects with one another:
@example
if ([anObject isEqual: anotherObject])
@{
// do something ...
@}
@end example
The default implementation returns @code{YES} only if the two objects being
compared are the exact same object (which is the same as the result that would
be returned using '@code{==}' to perform the comparison). Sometimes it is
useful to have two objects to be equal if their internal state is the same, as
reflected in instance variables, for example. In this case, you can override
@code{isEqual} in your class to perform such a comparison.
The @code{-(unsigned int)hash} method is useful for indexing objects, and
should return the same value for two objects of the same class that
@code{isEqual} each other. The same reasoning applies as for the
@code{isEqual} method -- if you want this to depend on internal state rather
than the identity of the object itself, override it. The default @code{hash}
value is based on the memory address occupied by the object.
The @code{-(NSComparisonResult) compare: (id)object} method is used in Cocoa
for comparing objects. It should return @code{NSOrderedAscending} if the
receiver is less than the argument, @code{NSOrderedDescending} if it is
greater, otherwise @code{NSOrderedSame}. Note that this is not meaningful
for many types of objects, and is actually deprecated in GNUstep for this
reason.
The @code{-(NSString *) description} method in @code{NSObject} returns a
short description of the object, often used for debugging. The default
implementation lists the object's class and memory location. If you want
other information you can override it.
The methods discussed in this section are all very similar to counterparts in
Java: the @code{equals} and @code{hashCode} methods, and the
@code{@i{Comparable}} interface.
@section Object Containers
GNUstep defines three major utility classes for holding collections of other
objects. @code{NSArray} is an ordered collection of objects, each of which
may occur in the collection multiple times. @code{NSSet} is an unordered
collection of unique objects (according to @code{isEqual} and/or @code{hash}).
@code{NSDictionary} is an unordered collection of key-value pairs. The keys
form a set (and must be unique), however there are no restrictions on the
collection of values. The @code{-hash} and @code{-isEqual} @code{NSObject}
methods discussed above are used by collection instances to organize their
members. All collections @code{retain} their members (see @ref{Objects}).
Unlike container APIs in some other languages, notably Java, instances of
these GNUstep classes are all @i{immutable} -- once created, you cannot add or
remove from them. If you need the ability to make changes (often the case),
use the mutable classes @code{NSMutableArray}, @code{NSMutableSet}, and
@code{NSMutableDictionary}. The @code{-mutableCopy} method mentioned in the
previous section will return the mutable version of a container regardless of
whether the original was mutable or not. Likewise, the @code{-copy} method
returns an immutable version. You should generally use immutable variants of
objects when you don't need to modify them, because their implementations are
more efficient. Often it is worthwhile to convert a mutable object that has
just been built into an immutable one if it is going to be heavily accessed.
Also unlike container objects in Java, GNUstep containers possess utility
methods. For example, Arrays can sort their members, or send a message to
each member individually (like the @code{map} function in Lisp). Sets can
determine whether they are equal to or subsets of other sets. Dictionaries
can save to and restore themselves from specially formatted files.
In addition to the three container types already mentioned, there is a
fourth, @code{NSCountedSet}. This is an unordered collection whose elements
need not be unique, however the number of times a given unique element has
been added is tracked. This behavior is also known as @i{bag} semantics.
All collection classes support returning an @code{NSEnumerator} object which
will enumerate over the elements of the collection. Note that if a mutable
collection is modified while an enumerator is being used, the results are not
defined.
Collections do not allow @code{nil} values or keys, but you can explicitly
represent a nil object using the special @code{NSNull} class. You simply use
the singleton returned from @code{[NSNull null]}.
The four container types just described handle objects, but not primitives
such as @code{float} or @code{int}. For this, you must use an
@code{NSHashTable} or @code{NSMapTable}. Despite their names, these are not
classes, but data types. A set of functions is defined for dealing with them.
Each can store and retrieve arbitrary pointers keyed by other arbitrary
pointers. However you are responsible for implementing the hashing yourself.
To create an @code{NSHashTable}, use the function @code{NSCreateHashtable}.
@code{NSHashInsert} and @code{NSHashGet} are the major functions, but there
are many others. There is a mostly parallel but more sophisticated set of
functions dealing with @code{NSMapTables}.
@ignore
Need to explain why NSHashTable and NSMapTable are not classes, if there is a
good reason for it, or else make excuses for why it is the (at first glance
rather crappy) way it is...
@end ignore
@section Data and Number Containers
The data containers discussed in the previous section, with the exception of
@code{NSHashTable} and @code{NSMapTable}, can store objects, but not primitive
types such as @code{int}s or @code{float}s. The @code{NS...Table} structures
are not always appropriate for a given task. For this case, GNUstep offers
two alternatives.
@subsection NSData
The @code{NSData} and @code{NSMutableData} classes manage a buffer of bytes as
an object. The contents of the buffer can be anything that can be stored in
memory, a 4-dimensional array of @code{double} for example (stored as a linear
sequence). Optionally, objects of these classes can take care of the memory
management for the buffer, growing it as needed and freeing it when they are
released.
@subsection NSValue
The @code{NSValue} class can wrap a single primitive value as an object so it
can be used in the containers and other places where an object reference is
needed. Once initialized, an @code{NSValue} is immutable, and there is no
@code{NSMutableValue} class. You initialize it by giving it a pointer to the
primitive value, and you should be careful this does not get freed until after
the @code{NSValue} is no longer used. You can specify to the @code{NSValue}
what type the primitive is so this information can be accessed later:
@example
int n = 10;
NSValue *theValue = [NSValue value: &n withObjCType: @@encode(int)];
// ...
int *m = (int *) [theValue pointerValue];
@end example
Here, @code{@@encode} is a compile-time operator that converts the data type
into a string (char *) code used at runtime to refer to the type. Object ids
can also be stored within @code{NSValue}s if desired. Note that in the above
case, the @code{NSValue} will be pointing to invalid data once the local
variable @code{@i{n}} goes out of scope.
If you want to wrap @code{int} or other numeric values, you should use
@code{NSNumber} (a subclass of @code{NSValue}) instead. This maintains its
own copy of the data and provides convenience methods for accessing the value
as a primitive.
@example
int n = 10;
NSNumber *theNumber = [NSNumber numberWithInt: n];
// ...
int m = [theNumber intValue];
float f = [theNumber floatValue]; // this is also valid
@end example
Notice that @code{@i{n}}'s value is used in the initialization, not a pointer
to it.
@subsection NSNumber
@code{NSNumber} has a subclass called @code{NSDecimalNumber} that implements
a number of methods for performing decimal arithmetic to much higher
precision than supported by ordinary @code{long double}. The behavior in
terms of rounding choices and exception handling may be customized using the
@code{NSDecimalNumberHandler} class. Equivalent functionality to the
@code{NSDecimalNumber} class may be accessed through functions, mostly named
@code{NSDecimalXXX}. Both the class and the functions use a structure also
called @code{NSDecimal}:
@example
typedef struct @{
signed char exponent; // Signed exponent - -128 to 127
BOOL isNegative; // Is this negative?
BOOL validNumber; // Is this a valid number?
unsigned char length; // digits in mantissa.
unsigned char cMantissa[2*NSDecimalMaxDigit];
@}
@end example
Instances can be initialized using the @code{NSDecimalFromString(NSString *)}
function.
@subsection NSRange, NSPoint, NSSize, NSRect
There are also a few types (not classes) for representing common composite
structures. @code{NSRange} represents an integer interval. @code{NSPoint}
represents a floating point 2-d cartesian location. @code{NSSize} represents
a 2-d floating point extent (width and height). @code{NSRect} contains a
lower-left point and an extent. A number of utility functions are defined
for handling rectangles and points.
@ignore
Again, why aren't these things objects? Efficiency?
@end ignore
@section Date/Time Facilities
GNUstep contains the @code{NSDate} class and the @code{NSCalendarDate}
classes for representing and handling dates and times. @code{NSDate} has
methods just relating to times and time differences in the abstract, but not
calendar dates or time zones. These features are added in the
@code{NSCalendarDate} subclass. The @code{NSTimeZone} class handles time
zone information.
@section String Manipulation and Text Processing
Basic string handling in the GNUstep Base library was covered in
@ref{Objective-C, ,Strings in GNUstep}. Here, we introduce a number of
additional string and text processing facilities provided by GNUstep.
@subsection NSScanner and Character Sets
The @code{NSScanner} class can be thought of as providing a combination of the
capabilities of the C @code{sscanf()} function and the Java
@code{StringTokenizer} class. It supports parsing of NSStrings and extraction
of numeric values or substrings separated by delimiters.
@code{NSScanner} works with objects of a class @code{NSCharacterSet} and its
subclasses @code{NSMutableCharacterSet}, @code{NSBitmapCharSet}, and
@code{NSMutableBitmapCharSet}, which provide various means of representing
sets of unicode characters.
@subsection Attributed Strings
@i{Attributed strings} are strings that support the association of
@i{attributes} with ranges of characters within the string. Attributes are
name-value pairs represented by an @code{NSDictionary} and may include
standard attributes (used by GNUstep GUI classes for font and other
characteristics during rendering) as well as programmer-defined application
specific attributes. The classes @code{NSAttributedString} and
@code{NSMutableAttributedString} represent attributed strings. They are not
subclasses of @code{NSString}, though they bundle an instance of one.
@ignore
Need a lot more explanation -- where do you look for info on standard
attributes, what are common usage patterns, etc..
@end ignore
@subsection Formatters
@i{Formatters} are classes providing support for converting complex values
into text strings. They also provide some support for user editing of strings
to be converted back into object equivalents. All descend from
@code{NSFormatter}, which defines basic methods for obtaining either an
attributed string or a regular string for an object value. Specific classes
include @code{NSDateFormatter} for @code{NSDate} objects,
@code{NSNumberFormatter} for @code{NSNumber} objects. Instances of these
classes can be customized for specific display needs.
@section File Handling
A number of convenience facilities are provided for platform-independent
access to the file system. The most generally useful is the
@code{NSFileManager} class, which allows you to read and save files,
create/list directories, and move or delete files and directories. In
addition to simply listing directories, you may obtain an
@code{NSDirectoryEnumerator} instance from it, a subclass of
@code{NSEnumerator} which provides a full listing of all the files beneath a
directory and its subdirectories.
If you need to work with path names but don't need the full
@code{NSFileManager} capabilities, @code{NSString} provides a number of
path-related methods, such as @code{-stringByAppendingPathComponent:} and
@code{-lastPathComponent}. You should use these instead of working directly
with path strings to support cross-platform portability.
@code{NSFileHandle} is a general purpose I/O class which supports reading and
writing to both files and network connections, including ordinary and
encrypted (SSL) socket connections, and the standard in / standard out streams
familiar from Unix systems. You can obtain instances through methods
like @code{+fileHandleForReadingAtPath:(NSString *)path} and
@code{+fileHandleAsServerAtAddress:(NSString *)address service:(NSString
*)service protocol:(NSString *)protocol}. The network-related functions of
@code{NSFileHandle} (which are a GNUstep extension not included in Cocoa) will
be covered in a later section. Note this class also supports gzip
compression for reading and writing.
Finally, GNUstep also provides some miscellaneous filesystem-related utility
functions, including @code{NSTemporaryDirectory()} and
@code{NSHomeDirectoryForUser()}.
@section Persistence and Serialization
GNUstep provides robust facilities for persisting objects to disk or sending
them over a network connection (to implement @ref{Distributed Objects,
Distributed Objects}). One class of facilities is referred to as @i{property
list serialization}, and is only usually used for @code{NSDictionary} and
@code{NSArray} container objects, and @code{NSNumber}, @code{NSData},
@code{NSString}, and @code{NSDate} member objects. It utilizes primarily
text-based formats.
Saving to and loading back from a serialized property list representation will
preserve values but not necessarily the classes of the objects. This makes
property list representations robust across platforms and library changes, but
also makes it unsuitable for certain applications. @i{Archiving}, the second
class of GNUstep persistence facilities, provides for the persistence of a
@i{graph} of arbitrary objects, with references to one another, taking care to
only persist each individual object one time no matter how often it is
referred to. Object class identities are preserved, so that the behavior of a
reloaded object graph is guaranteed to be the same as the saved one. On the
other hand, the classes for these objects must be available at load time.
@subsection Property List Serialization
Serialized property list representations (sometimes referred to as
``@i{plists}'') are typically saved and restored using methods in collection
classes. For example the @code{NSDictionary} class has
@code{-writeToFile:atomically:} to save, @code{+dictionaryWithContentsOfFile}
to restore, and @code{NSArray} has similar methods. Alternatively, if you
wish to save/restore individual @code{NSData} or other objects, you can use
the @code{NSPropertyListSerialization} class. (There are also
@code{NSSerializer} and @code{NSDeserializer} classes, but these are
deprecated in Mac OS X and are not really needed in GNUstep either, so should
not be used.)
Serialized property lists can actually be written in one of three different
formats -- plain text, XML, and binary. Interconversion amongst these is
possible using the @code{pldes} and @code{plser} command-line tools (see the
@uref{../../Tools/Reference/index.html, tools reference}).
@ignore
Still need: the XML format; how to specify format in output; discussion of
compatibility with OS X; using serialization with NSData.
@end ignore
@subsection Archives
Archiving utilizes a binary format that is cross-platform between GNUstep
implementations, though not between GNUstep and Mac OS X Cocoa. Archiving,
like serialization in Java, is used both for saving/restoring objects on disk
and for interprocess communications with @ref{Distributed Objects, Distributed
Objects}. For an object to be archivable, it must adopt the @code{NSCoding}
protocol. The coding process itself is managed by instances of the
@code{NSCoder} class and its subclasses:
@table @code
@item NSCoder
Base class, defines most of the interface used by the others.
@item NSArchiver, NSUnarchiver
Sequential archives that can only be saved and restored en masse.
@item NSKeyedArchiver, NSKeyedUnarchiver
Random access archives that can be read from and written to on an
individual-object basis and provide more robust integrity in the face of
class changes.
@item NSPortCoder
Used for @ref{Distributed Objects, Distributed Objects}.
@end table
The basic approach to accessing or creating an archive is to use one of the
convenience methods in an @code{NSCoder} subclass:
@table @code
@item + (BOOL) archiveRootObject: (id)object toFile: (NSString *)file
Save object and graph below it to file. '@code{YES}' returned on success.
Both @code{NSArchiver} and @code{NSKeyedArchiver} support.
@item + (NSData *) archivedDataWithRootObject: (id)object
Save object and graph below it to a byte buffer. Both @code{NSArchiver} and
@code{NSKeyedArchiver} suport.
@item + (id) unarchiveObjectWithFile: (NSString *)file
Load object graph from file. Both @code{NSUnarchiver} and
@code{NSKeyedUnarchiver} support.
@item + (id) unarchiveObjectWithData: (NSData *)data
Load object graph from byte buffer. Both @code{NSUnarchiver} and
@code{NSKeyedUnarchiver} support.
@end table
To obtain more specialized behavior, instantiate one of the classes above and
customize it (through various method calls) before instigating the primary
archiving or unarchiving operation.
From the perspective of the objects being archived, the @code{NSCoding}
protocol declares two methods that must be implemented:
@table @code
@item -(void) encodeWithCoder: (NSCoder *)encoder
This message is sent by an @code{NSCoder} subclass or instance to request the
object to archive itself. The implementation should send messages to
@code{encoder} to save its essential instance variables. If this is
impossible (for whatever reason) an exception should be raised.
@item -(id) initWithCoder: (NSCoder *)decoder
This message is sent by an @code{NSCoder} subclass or instance to request the
object to restore itself from an archive. The implementation should send
messages to @code{decoder} to load its essential instance variables. An
exception should be raised if there is a problem restoring state.
@end table
Here is an example @code{NSCoding} implementation:
@example
@@interface City : PoliticalUnit
@{
private
float latitude;
float longitude;
CensusData *censusData;
State *state;
@}
// ...
@@end
...
@@implementation City
- (void) encodeWithCoder: (NSCoder *)coder
@{
[super encodeWithCoder:coder]; // always call super first
if (![coder allowsKeyedCoding])
@{
[coder encodeValueOfObjCType: @@encode(float) at: &latitude];
[coder encodeValueOfObjCType: @@encode(float) at: &longitude];
[coder encodeObject: censusData];
[coder encodeConditionalObject: state];
@}
else
@{
[coder encodeFloat: latitude forKey: @@"City.latitude"];
[coder encodeFloat: longitude forKey: @@"City.longitude"];
[coder encodeObject: censusData forKey: @@"City.censusData"];
[coder encodeConditionalObject: state forKey: @@"City.state"];
@}
return;
@}
- (id) initWithCoder: (NSCoder *)coder
@{
self = [super initWithCoder:coder]; // always assign 'self' to super init..
if (![coder allowsKeyedCoding])
@{
// Must decode keys in same order as encodeWithCoder:
[coder decodeValueOfObjCType: @@encode(float) at: &latitude];
[coder decodeValueOfObjCType: @@encode(float) at: &longitude];
censusData = [[coder decodeObject] retain];
state = [[coder decodeObject] retain];
@}
else
@{
// Can decode keys in any order
censusData = [[coder decodeObjectForKey: @@"City.censusData"] retain];
state = [[coder decodeObjectForKey: @@"City.state"] retain];
latitude = [coder decodeFloatForKey: @@"City.latitude"];
longitude = [coder decodeFloatForKey: @@"City.longitude"];
@}
return self;
@}
// ...
@@end
@end example
The primary wrinkle to notice here is the check to @code{[coder
allowsKeyedCoding]}. The object encodes and decodes its instance variables
using keys if this returns '@code{YES}'. Keys must be unique within a single
inheritance hierarchy -- that is, a class may not use keys the same as its
superclass or any of its ancestors or sibling classes.
Keyed archiving provides robustness against class changes and is therefore to
be preferred in most cases. For example, if instance variables are added at
some point to the @code{City} class above, this will not prevent earlier
versions of the class from restoring data from a later one (they will just
ignore the new values), nor does it prevent a later version from initializing
from an earlier archive (it will not find values for the added instance
variables, but can set these to defaults).
Finally, notice the use of @code{encodeConditionalObject} above for
@code{state}, in contrast to @code{encodeObject} for census data. The reason
the two different methods are used is that the @code{City} object @i{owns} its
census data, which is an integral part of its structure, whereas the
@code{state} is an auxiliary reference neither owned nor retained by
@code{City}. It should be possible to store the cities without storing the
states. Thus, the @code{encodeConditionalObject} method is called, which
only stores the @code{State} if it is already being stored unconditionally
elsewhere during the current encoding operation.
Note that within a given archive, an object will be written only once.
Subsequent requests to write the same object are detected and a reference is
written rather than the full object.
@ignore
Mention awake, substitution on encode, etc..?
@end ignore
@section Utility
The GNUstep Base library provides a number of utility classes that don't fall
under any other function category.
The @code{NSUserDefaults} class provides access to a number of system- and
user-dependent settings that should affect tool and application behavior. You
obtain an instance through sending @code{[NSUserDefaults
standardUserDefaults]}. The instance provides access to settings indexed by
string keys. The standard keys used are documented
@uref{../../../User/Gui/DefaultsSummary.html, here}. Users can adjust
settings for particular keys using the
@i{@code{@uref{../../Tools/Reference/defaults.html, defaults}}} command.
The @code{NSProcessInfo} class provides access to certain information about
the system environment such as the operating system and host name. It also
provides support for process logging (see @ref{Exception Handling, Logging,
Logging}). You obtain an instance through sending @code{[NSProcessInfo
processInfo]}.
The @code{NSUndoManager} class provides a general mechanism for supporting
@i{undo} of user operations in applications. Essentially, it allows you to
store sequences of messages and receivers that need to be invoked to undo or
redo an action. The various methods in this class provide for grouping of
sets of actions, execution of undo or redo actions, and tuning behavior
parameters such as the size of the undo stack. Each application entity with
its own editing history (e.g., a document) should have its own undo manager
instance. Obtain an instance through a simple @code{[[NSUndoManager alloc]
init]} message.
The @code{NSProtocolChecker} and @code{NSProxy} classes provide message
filtering and forwarding capabilities. If you wish to ensure at runtime that
a given object will only be sent messages in a certain protocol, you create
an @code{NSProtocolChecker} instance with the protocol and the object as
arguments:
@example
id versatileObject = [[ClassWithManyMethods alloc] init];
id narrowObject = [NSProtocolChecker protocolCheckerWithTarget: versatileObject
protocol: @@protocol(SomeSpecificProtocol)];
return narrowObject;
@end example
This is often used in conjunction with distributed objects to expose only a
subset of an objects methods to remote processes. The @code{NSProxy} class
is another class used in conjunction with distributed objects. It implements
no methods other than basic @code{NSObject} protocol methods. To use it,
create a subclass overriding @code{-(void) forwardInvocation:} and @code{-
(NSMethodSignature) methodForSelector:}. By appropriate implementations
here, you can make an @code{NSProxy} subclass instance act like an instance
of any class of your choosing.
@ignore
Much more needed about this -- why is a special class needed since all
objects have a forwardInvocation method, what is -methodForSelector and do all
classes that want to implement -forwardInvocation need to implement it as
well (in which case need to add to discussion in Advanced Messaging), ...
@end ignore
The @code{NSBundle} class provides support for run-time dynamic loading of
libraries and application resources, usually termed ``Bundles''. A bundle
consists of a top-level directory containing subdirectories that may include
images, text files, and executable binaries or shared libraries. The ``.app''
directory holding a NeXTstep/OpenStep/GNUstep/Cocoa application is actually a
bundle, as are the ``Frameworks'' containing shared libraries together with
other resources. Bundles and frameworks are covered in @ref{Bundles and
Frameworks}.
@section Notifications
GNUstep provides a framework for sending messages between objects within a
process called @i{notifications}. Objects register with an
@code{NSNotificationCenter} to be informed whenever other objects post
@code{NSNotification}s to it matching certain criteria. The notification
center processes notifications synchronously -- that is, control is only
returned to the notification poster once every recipient of the notification
has received it and processed it. Asynchronous processing is possible using
an @code{NSNotificationQueue}. This returns immediately when a notification
is added to it, and it will periodically post the oldest notification on its
list to the notification center. In a multithreaded process, notifications
are always sent on the thread that they are posted from.
An @code{NSNotification} consists of a string name, an object, and optionally
a dictionary which may contain arbitrary associations. Objects register with
the notification center to receive notifications matching either a particular
name, a particular object, or both. When an object registers, it specifies a
message selector on itself taking an @code{NSNotification} as its sole
argument. A message will be sent using this selector whenever the
notification center receives a matching notification in a post.
Obtain a notification center instance using @code{NSNotificationCenter
+defaultCenter}. An @code{NSDistributedNotificationCenter} may be used for
interprocess communication on the same machine. Interprocess notification will
be slower than within-process notification, and makes use of the
@uref{../../Tools/Reference/gdnc.html, gdnc} command-line tool.
Notifications are similar in some ways to @i{events} in other frameworks,
although they are not used for user interface component connections as in Java
(message forwarding and the target-action paradigm are used instead). In
addition, the GNUstep GUI (AppKit) library defines an @code{NSEvent} type for
representing mouse and keyboard actions.
@section Networking and RPC
GNUstep provides some general network-related functionality, as well as
classes supporting @ref{Distributed Objects, distributed objects} and related
forms of inter-process communication.
@subsection Basic Networking
GNUstep provides the following classes handling basic network communications:
@table @code
@item NSHost
Holds and manages information on host names and IP addresses. Use the
@code{+currentHost}, @code{+hostWithName:}, or @code{+hostWithAddress:} class
methods to obtain an instance.
@item NSFileHandle
On Unix, network connections are treated analogously to files. This
abstraction has proven very useful, so GNUstep supports it in the
@code{NSFileHandle} class, even on non-Unix platforms. You may use the class
methods @code{+fileHandleAsServerAtAddress:(NSString *)address
service:(NSString *)service protocol:(NSString *)protocol} and corresponding
client methods to access one side of a connection to a port on a networked
machine. (To use pipes, see the next section.)
@item NSURL
Provides methods for working with URLs and the data accessible through them.
Once an @code{NSURL} is constructed, data may be loaded asynchronously through
@code{NSURL -loadResourceDataNotifyingClient:usingCache:} or synchronously
through @code{NSURL -resourceDataUsingCache:}. It can also be obtained
through @code{NSString +stringWithContentsOfURL:} or @code{NSData
+dataWithContentsOfURL:}.
@item NSURLHandle
This class provides additional control over the URL contents loading
process. Obtain an instance through @code{NSURL -URLHandleUsingCache:}.
@end table
@subsection Remote Process Communications
GNUstep provides a number of classes supporting @ref{Distributed Objects,
distributed objects} and related forms of inter-process communication. In
most cases, you only need to know about the @code{NSConnection} class, but if
you require additional control over distributed objects, or if you wish to
use alternative forms of communications such as simple messaging, you may use
the classes listed here.
@table @code
@item NSConnection
This is the primary class used for registering and acquiring references to
distributed objects.
@item NSDistantObject
When a client acquires a remote object reference through @code{NSConnection
+rootProxyForConnectionWithRegisteredName:}, the returned object is an
instance of this class, which is a subclass of @code{NSProxy}. Since usually
you will just cast your reference to this to a particular protocol, you do
not need to refer to the @code{NSDistantObject} class directly.
@item NSPort, NSPortMessage
Behind the scenes in distributed objects, @code{NSPort} objects handle both
network communications and serialization/deserialization for
sending messages to remote objects and receiving the results. The actual
data sent over the network is encapsulated by @code{NSPortMessage} objects,
which consist of two ports (sender and receiver) and a body consisting of one
or more @code{NSData} or @code{NSPort} objects. (Data in the @code{NSData}
must be in network byte order.)
@item NSSocketPort, NSMessagePort
If you want to send custom messages between processes yourself, you can use
these classes. @code{NSSocketPort} can communicate to processes on the same
or remote machines. @code{NSMessagePort} is optimized for local
communications only.
@item NSPortNameServer, NSSocketPortNameServer, NSMessagePortNameServer
The @code{NSPortNameServer} class and subclasses are used behind the scenes
by the distributed objects system to register and look up remotely-accessible
objects.
@end table
@section Threads and Run Control
A GNUstep program may initiate independent processing in two ways -- it can
start up a separate process, referred to as a @i{task}, much like a @i{fork}
in Unix, or it may spawn multiple @i{threads} within a single process.
Threads share data, tasks do not. Before discussing tasks and threads, we
first describe the @i{run loop} in GNUstep programs.
@subsection Run Loops and Timers
@code{NSRunLoop} instances handle various utility tasks that must be performed
repetitively in an application, such as processing input events, listening for
distributed objects communications, firing @code{NSTimer}s, and sending
notifications and other messages asynchronously. In general, there is one run
loop per thread in an application, which may always be obtained through the
@code{+currentRunLoop} method, however unless you are using the AppKit and the
[NSApplication] class, the run loop will not be started unless you explicitly
send it a @code{-run} message.
At any given point, a run loop operates in a single @i{mode}, usually
@code{NSDefaultRunLoopMode}. Other modes are used for special purposes and
you usually need not worry about them.
An @code{NSTimer} provides a way to send a message at some time in the future,
possibly repeating every time a fixed interval has passed. To use a timer,
you can either create one that will automatically be added to the run loop in
the current thread (using the @code{-addTimer:forMode:} method), or you can
create it without adding it then add it to a run loop of your choosing later.
@subsection Tasks and Pipes
You can run another program as a subprocess using an @code{NSTask} instance,
and communicate with it using @code{NSPipe} instances. The following code
illustrates.
@example
NSTask *task = [[NSTask alloc] init];
NSPipe *pipe = [NSPipe pipe];
NSFileHandle *readHandle = [pipe fileHandleForReading];
NSData *inData = nil;
[task setStandardOutput: pipe];
[task setLaunchPath: [NSHomeDirectory()
stringByAppendingPathComponent:@@"bin/someBinary"]];
[task launch];
while ((inData = [readHandle availableData]) && [inData length])
@{
[self processData:inData];
@}
[task release];
@end example
Here, we just assume the task has exited when it has finished sending output.
If this might not be the case, you can register an observer for
@ref{Base Library, notifications, Notifications} named
@code{NSTaskDidTerminateNotification}.
@subsection Threads and Locks
@i{Threads} provide a way for applications to execute multiple tasks in
parallel. Unlike separate processes, all threads of a program share the same
memory space, and therefore may access the same objects and variables.
GNUstep supports multithreaded applications in a convenient manner through the
@code{NSThread} and @code{NSLock} classes and subclasses. @code{NSThread
+detachNewThreadSelector:toTarget:withObject:} allows you to initiate a new
thread and cause a message to be sent to an object on that thread. The thread
can either run in a ``one-shot'' manner or it can sit in loop mode (starting
up its own instance of the @code{NSRunLoop} class) and communicate with other
threads using part of the @ref{Distributed Objects, distributed objects}
framework. Each thread has a dictionary (accessed through
@code{-threadDictionary} that allows for storage of thread-local variables.
Because threads share data, there is the danger that examinations of and
modifications to data performed concurrently by more than one thread will
occur in the wrong order and produce unexpected results. (Operations with
immutable objects do not present this problem unless they are actually
deallocated.) GNUstep provides the @code{@i{NSLocking}} protocol and the
@code{NSLock} class and subclasses to deal with this. @code{@i{NSLocking}}
provides two methods: @code{-lock} and @code{-unlock}. When an operation
needs to be performed without interference, enclose it inside of lock-unlock:
@example
NSArray *myArray;
NSLock *myLock = [[NSLock alloc] init];
// ...
[myLock lock];
if (myArray == nil)
@{
myAray = [[NSMutableArray alloc] init];
[myArray addObject: someObject];
@}
[myLock unlock];
@end example
This code protects '@code{myArray}' from accidentally being initialized twice
if two separate threads happen to detect it is @code{nil} around the same
time. When the @code{lock} method is called, the thread doing so is said to
@i{acquire} the lock. No other thread may subsequently acquire the lock
until this one has subsequently @i{relinquished} the lock, by calling
@code{unlock}.
Note that the lock object should be initialized @i{before} any thread might
possibly need it. Thus, you should either do it before any additional threads
are created in the application, or you should enclose the lock creation inside
of another, existing, lock.
The @code{-lock} method in the @code{@i{NSLocking}} protocol blocks
indefinitely until the lock is acquired. If you would prefer to just check
whether the lock can be acquired without committing to this, you can use
@code{NSLock -tryLock} or @code{NSLock -lockBeforeDate:}, which return
@code{YES} if they succeed in acquiring the lock.
@code{NSRecursiveLock} is an @code{NSLock} subclass that may be locked
multiple times by the same thread. (The @code{NSLock} implementation will
not allow this, causing the thread to deadlock (freeze) when it attempts to
acquire the lock a second time.) Each @code{lock} message must be balanced
by a corresponding @code{unlock} before the lock is relinquished.
@code{NSConditionLock} stores an @code{int} together with its lock status.
The @code{-lockWhenCondition:(int)value} and related methods request the lock
only if the condition is equal to that passed in. The condition may be
changed using the @code{unlockWithCondition:(int)value} method. This
mechanism is useful for, e.g., a producer-consumer situation, where the
producer can ``tell'' the consumer that data is available by setting the
condition appropriately when it releases the lock it acquired for adding data.
Finally, the @code{NSDistributedLock} class does not adopt the
@code{@i{NSLocking}} protocol but supports locking across processes, including
processes on different machines, as long as they can access a common
filesystem.
If you are writing a class library and do not know whether it will be used in
a multithreaded environment or not, and would like to avoid locking overhead
if not, use the @code{NSThread +isMultiThreaded} method. You can also
register to receive @code{NSWillBecomeMultiThreadedNotification}s. You can
also use the @code{GSLazyLock} and @code{GSLazyRecursiveLock} classes (see
next section) which handle this automatically.
@subsection Using @code{NSConnection} to Communicate Between Threads
You can use the distributed objects framework to communicate between threads.
This can help avoid creating threads repeatedly for the same operation, for
example. While you can go through the full process of registering a server
object by name as described in @ref{Distributed Objects, distributed
objects}, a lighter weight approach is to create @code{NSConnection}s
manually:
@example
// code in Master...
- startSlave
@{
NSPort *master;
NSPort *slave;
NSArray *ports;
NSConnection *comms;
master = [NSPort port];
slave = [NSPort port];
comms = [[NSConnection alloc] initWithReceivePort: master sendPort: slave];
[comms setRootObject: self];
portArray = [NSArray arrayWithObjects: slave, master, nil];
[NSThread detachNewThreadSelector: @@selector(newWithCommPorts:)
toTarget: [Slave class]
withObject: ports];
@}
// code in Slave...
+ newWithCommPorts: (NSArray *)ports
@{
NSConnection *comms;
NSPort *slave = [ports objectAtIndex: 0];
NSPort *master = [ports objectAtIndex: 1];
comms = [NSConnection connectionWithReceivePort: slave sendPort: master];
// create instance and assign to 'self'
self = [[self alloc] init];
[(id)[comms rootProxy] setServer: self];
[self release];
[[NSRunLoop currentRunLoop] run];
@}
@end example
@section GNUstep Additions
The @uref{../../BaseAdditions/Reference/index.html, Base Additions} library
consists of a number of classes, all beginning with '@code{GC}' or
'@code{GS}', that are not specified in OpenStep or Cocoa but have been deemed
to be of general utility by the GNUstep developers. The library is designed
so that it can be built and installed on a system, such as OS X, where GNUstep
is not available but an alternate Foundation implementation is.
It contains the following five categories of classes:
@table @code
@item GCxxx
These are classes that are substituted (behind the scenes) for certain
Foundation classes if the Base library is compiled with garbage collection
enabled. (See @ref{Objects, , Memory Management}.)
@item GSXMLxxx
Classes for parsing XML using DOM- or SAX-like APIs, for processing XPath
expressions, and for performing XSLT transforms. These are implemented over
the @uref{http://xmlsoft.org, libxml2} C library, and using them should for
the most part protect you from the frequent API changes in that library.
@item GSHtmlXxx
Classes for parsing HTML documents (not necessarily XHTML).
@item GSMimeXxx
Classes for handling MIME messages or HTML POST documents.
@item GSLazyXxx
Classes implementing ``lazy'' locking that do not actually attempt any locking
unless running in a multithreaded application. See @ref{Base Library, ,
Threads and Run Control}.
@end table
All of these classes have excellent API reference documentation and you
should look @uref{../../BaseAdditions/Reference/index.html, there} for
further information.
@page

View file

@ -0,0 +1,19 @@
@node Bundles and Frameworks
@appendix Application Resources: Bundles and Frameworks
@cindex bundles
@cindex frameworks
@cindex resources, application
@i{TBD}
@ignore
GNUstep does not have frameworks as such but it still has bundles and the
means of loading them. IMHO frameworks ought to be reconsidered since they
are a very useful construct. Java uses them to great benefit now (resources
go into jars, which are like frameworks, and there are .war and .ear archive
types with more specialized roles). It is true that dylib loading is a
system-dependent process, however this could be solved by the use of symbolic
links on unix systems, and post-install copying on Windows systems.
@end ignore
@page

View file

@ -0,0 +1,114 @@
@node Compliance to Standards
@appendix GNUstep Compliance to Standards
@cindex standards, GNUstep compliance to
@cindex standards compliance
@cindex OpenStep compliance
@cindex OS X compatibility
GNUstep is generally compatible with the OpenStep specification and with
recent developments of the MacOS-X (Cocoa) API. Where MacOS deviates from the
OpenStep API, GNUstep generally attempts to support both versions. In some
cases the newer MacOS APIs are incompatible with OpenStep, and GNUstep usually
supports the richer version.
In order to deal with compatiblity issues, GNUstep uses two mechanisms - it
provides conditionally compiled sections of the library header files, so that
software can be built that will conform strictly to a particular API, and it
provides user default settings to control the behavior of the library at
runtime.
@section Conditional Compilation
@cindex compilation, conditional
Adding an option to a makefile to define one of the following preprocessor
constants will modify the API visible to software being compiled -
@deffn {} NO_GNUSTEP
GNUstep specific extensions to the OpenStep and MacOS cocoa APIs are
excluded from the headers.
@end deffn
@deffn {} STRICT_MACOS_X
Only methods and classes that are part of the MacOS cocoa API are made
available in the headers.
@end deffn
@deffn {} STRICT_OPENSTEP
Only methods and classes that are part of the OpenStep specification are
made available in the headers.
@end deffn
Note, these preprocessor constants are used in developer code (ie the code
that users of GNUstep write) rather than by the GNUstep software itself. They
permit a developer to ensure that he/she does not write code which depends
upon API not present on other implementations (in practice, MacOS-X or some
old OPENSTEP systems). The actual GNUstep libraries are always built with the
full GNUstep API in place, so that the feature set is as consistent as
possible.
@section User Defaults
@cindex user defaults, API compliance
User defaults may be specified ///
@deffn {} GNU-Debug
An array of strings that lists debug levels to be used within the
program. These debug levels are merged with any which were set on the command
line or added programmatically to the set given by the
[NSProcessInfo-debugSet] method.
@end deffn
@deffn {} GSLogSyslog
Setting the user default GSLogSyslog to YES will cause log/debug output to be
sent to the syslog facility (on systems which support it), rather than to the
standard error stream. This is useful in environments where stderr has been
re-used strangely for some reason.
@end deffn
@deffn {} GSMacOSXCompatible
Setting the user default GSMacOSXCompatible to YES will cause MacOS compatible
behavior to be the default at runtime. This default may however be overridden
to provide more fine grained control of system behavior.
@end deffn
@deffn {} GSOldStyleGeometry
Specifies whether the functions for producing strings describing geometric
structures (NSStringFromPoint(), NSStringFromSize(), and NSStringFromRect())
should produce strings conforming to the OpenStep specification or to MacOS-X
behavior. The functions for parsing those strings should cope with both cases
anyway.
@end deffn
@deffn {} GSSOCKS
May be used to specify a default SOCKS5 server (and optionally a port
separated from the server by a colon) to which tcp/ip connections made using
the NSFileHandle extension methods should be directed.
This default overrides the SOCKS5_SERVER and SOCKS_SERVER environment variables.
@end deffn
@deffn {} {Local Time Zone}
Used to specify the name of the timezone to be used by the NSTimeZone class.
@end deffn
@deffn {} NSWriteOldStylePropertyLists
Specifies whether text property-list output should be in the default MacOS-X
format (XML), or in the more human readable (but less powerful) original
OpenStep format.
Reading of property lists is supported in either format, but only if GNUstep
is built with the libxml library (which is needed to handle XML parsing).
NB. MacOS-X generates illegal XML for some strings - those which contain
characters not legal in XML. GNUstep always generates legal XML, at the cost
of a certain degree of compatibility. GNUstep XML property lists use a
backslash to escape illegal chatracters, and consequently any string
containing either a backslash or an illegal character will be written
differently to the same string on MacOS-X.
@end deffn
@deffn {} NSLanguages
An array of strings that lists the users prefered languages, in order or
preference. If not found the default is just English.
@end deffn

View file

@ -0,0 +1,556 @@
@paragraphindent 0
@node Exception Handling
@chapter Exception Handling, Logging, and Assertions
@cindex exception facilities
@cindex logging facilities
@cindex assertion facilities
No matter how well a program is designed, if it has to interact with a user or
other aspect of the outside world in any way, the code is bound to
occasionally meet with cases that are either invalid or just plain unexpected.
A very simple example is when a program asks the user to enter a filename, and
the user enters the name of a file that does not exist, or does not enter a
name at all. Perhaps a valid filename @i{is} entered, but, due to a previous
disk write error the contents are garbled. Any number of things can go wrong.
In addition, programmer error inevitably occurs and needs to be taken account
of. Internal functions may be called with invalid arguments, either due to
unexpected paths being taken through the code, or silly things like typos
using the wrong variable for something. When these problems happen (and they
@i{will} happen), it is better to handle them gracefully than for the program
to crash, or worse, to continue processing but in an erroneous way.
To allow for this, many computer languages provide two types of facilities.
The first is referred to as @i{exception handling} or sometimes @i{error
trapping}. The second is referred to as @i{assertion checking}. Exceptions
allow the program to catch errors when they occur and react to them
explicitly. Assertions allow a programmer to establish that certain
conditions hold before attempting to execute a particular operation. GNUstep
provides both of these facilities, and we will cover each in turn. The
assertion facility is tied in with the GNUstep @i{logging} facilities, so we
describe those as well.
To use any of the facilities described in this chapter requires that you
include @code{Foundation/NSException.h}.
@section Exceptions
@cindex exceptions
@cindex NSException class
@cindex NS_DURING macro
@cindex NS_HANDLER macro
@cindex NS_ENDHANDLER macro
@cindex NSUncaughtExceptionHandler
GNUstep exception handling provides for two things:
@enumerate
@item
When an error condition is detected during execution, control is passed to a
special error-handling routine, which is given information on the error that
occurred.
@item
This routine may itself, if it chooses, pass this information up the function
call stack to the next higher level of control. Often higher level code is
more aware of the context in which the error is occurring, and can therefore
make a better decision as to how to react.
@end enumerate
@subsection Catching and Handling Exceptions
GNUstep exception handling is implemented through the macros @code{NS_DURING},
@code{NS_HANDLER}, and @code{NS_ENDHANDLER} in conjunction with the
@code{NSException} class. The following illustrates the pattern:
@example
NS_DURING
@{
// do something risky ...
@}
NS_HANDLER
@{
// a problem occurred; inform user or take another tack ...
@}
NS_ENDHANDLER
// back to normal code...
@end example
For instance:
@example
- (DataTree *) readDataFile: (String *)filename
@{
ParseTree *parse = nil;
NS_DURING
@{
FileHandle *handle = [self getFileHandle: filename];
parse = [parser parseFile: handle];
@}
NS_HANDLER
@{
if ([[localException name] isEqualToString: MyFileNotFoundException])
@{
NS_VALUERETURN([self readDataFile: fallbackFilename]);
@}
else if ([[localException name] isEqualToString: NSParseErrorException])
@{
NS_VALUERETURN([self readDataFileInOldFormat: filename]);
@}
else
@{
[localException raise];
@}
@}
NS_ENDHANDLER
return [[DataTree alloc] initFromParseTree: parse];
@}
@end example
Here, a file is parsed, with the possibility of at least two different errors:
not finding the file and the file being misformatted. If a problem does
occur, the code in the @code{NS_HANDLER} block is jumped to. Information on
the error is passed to this code in the @code{localException} variable, which
is an instance of @code{NSException}. The handler code examines the name of
the exception to determine if it can implement a work-around. In the first
two cases, an alternative approach is available, and so the
@code{NS_VALUERETURN} macro is used to return an alternative value to the
@code{readDataFile:} caller. Note that it is @i{not} allowed to simply write
``@code{return x;}'' inside an exception handler, owing to the nature of the
behind-the-scenes C constructs implementing the mechanism (the @code{setjmp()}
and @code{longjmp()} functions). If you are in a void function not returning
a value, you may use simply ``@code{NS_VOIDRETURN}'' instead. Finally, notice
that in the third case above the handler does not recognize the exception
type, so it passes it one level up to the caller by calling @code{-raise} on
the exception object.
@subsection Passing Exceptions Up the Call Stack
If the caller of @code{-readDataFile:} has enclosed the call inside its own
@code{NS_DURING} @dots{} @code{NS_HANDLER} @dots{} @code{NS_ENDHANDLER} block,
it will be able to catch this exception and react to it in the same way as we
saw here. Being at a higher level of execution, it may be able to take
actions more appropriate than the @code{-readDataFile:} method could have.
If, on the other hand, the caller had @i{not} enclosed the call, it would not
get a chance to react, but the exception would be passed up to the caller of
@i{this} code. This is repeated until the top control level is reached, and
then as a last resort @code{NSUncaughtExceptionHandler} is called. This is a
built-in function that will print an error message to the console and exit
the program immediately. If you don't want this to happen it is possible to
override this function by calling
@code{NSSetUncaughtExceptionHandler(fn_ptr)}. Here, @code{fn_ptr} should be
the name of a function with this signature (defined in @code{NSException.h}):
@example
void NSUncaughtExceptionHandler(NSException *exception);
@end example
One possibility would be to use this to save files or any other unsaved state
before an application exits because of an unexpected error.
@subsection Where do Exceptions Originate?
You may be wondering at this point where exceptions come from in the first
place. There are two main possibilities. The first is from the Base library;
many of its classes raise exceptions when they run into error conditions. The
second is that application code itself raises them, as described in the next
section. Exceptions do @i{not} arise automatically from C-style error
conditions generated by C libraries. Thus, if you for example call the
@code{strtod()} function to convert a C string to a double value, you still
need to check @code{errno} yourself in standard C fashion.
Another case that exceptions are @i{not} raised in is in the course of
messaging. If a message is sent to @code{nil}, it is silently ignored
without error. If a message is sent to an object that does not implement it,
the @code{forwardInvocation} method is called instead, as discussed in
@ref{Advanced Messaging}.
@subsection Creating Exceptions
If you want to explicitly create an exception for passing a particular error
condition upwards to calling code, you may simply create an
@code{NSException} object and @code{raise} it:
@example
NSException myException = [[NSException alloc]
initWithName: @@"My Exception"
reason: @@"[Description of the cause...]"
userInfo: nil];
[myException raise];
// code in block after here is unreachable..
@end example
The @code{userInfo} argument here is a @code{NSDictionary} of key-value pairs
containing application-specific additional information about the error. You
may use this to pass arbitrary arguments within your application. (Because
this is a convenience for developers, it should have been called
@code{developerInfo}..)
Alternatively, you can create the exception and raise it in one call with
@code{+raise}:
@example
[NSException raise: @@"My Exception"
format: @@"Parse error occurred at line %d.",lineNumber];
@end example
Here, the @code{format} argument takes a printf-like format analogous to
@code{[NSString -stringWithFormat:]} discussed @ref{Objective-C, previously,
Strings in GNUstep}. In general, you should not use arbitrary names for
exceptions as shown here but constants that will be recognized throughout your
application. In fact, GNUstep defines some standard constants for this
purpose in @code{NSException.h}:
@table @code
@item NSCharacterConversionException
An exception when character set conversion fails.
@item NSGenericException
A generic exception for general purpose usage.
@item NSInternalInconsistencyException
An exception for cases where unexpected state is detected within an object.
@item NSInvalidArgumentException
An exception used when an invalid argument is passed to a method or function.
@item NSMallocException
An exception used when the system fails to allocate required memory.
@item NSParseErrorException
An exception used when some form of parsing fails.
@item NSRangeException
An exception used when an out-of-range value is encountered.
@end table
Also, some Foundation classes define their own more specialized exceptions:
@table @code
@item NSFileHandleOperationException (NSFileHandle.h)
An exception used when a file error occurs.
@item NSInvalidArchiveOperationException (NSKeyedArchiver.h)
An archiving error has occurred.
@item NSInvalidUnarchiveOperationException (NSKeyedUnarchiver.h)
An unarchiving error has occurred.
@item NSPortTimeoutException (NSPort.h)
Exception raised if a timeout occurs during a port send or receive operation.
@item NSUnknownKeyException (NSKeyValueCoding.h)
An exception for an unknown key.
@end table
@subsection When to Use Exceptions
As might be evident from the @code{-readDataFile:} example above, if a
certain exception can be anticipated, it can also be checked for, so you
don't necessarily need the exception mechanism. You may want to use
exceptions anyway if it simplifies the code paths. It is also good practice
to catch exceptions when it can be seen that an unexpected problem might
arise, as any time file, network, or database operations are undertaken, for
instance.
Another important case where exceptions are useful is when you need to pass
detailed information up to the calling method so that it can react
appropriately. Without the ability to raise an exception, you are limited to
the standard C mechanism of returning a value that will hopefully be
recognized as invalid, and perhaps using an @code{errno}-like strategy where
the caller knows to examine the value of a certain global variable. This is
inelegant, difficult to enforce, and leads to the need, with void methods, to
document that ``the caller should check @code{errno} to see if any problems
arose''.
@section Logging
@cindex logging
@cindex NSLog function
@cindex NSDebugLog function
@cindex NSWarnLog function
@cindex profiling facilities
GNUstep provides several distinct logging facilities best suited for different
purposes.
@subsection NSLog
The simplest of these is the @code{NSLog(NSString *format, ...)} function.
For example:
@example
NSLog(@@"Error occurred reading file at line %d.", lineNumber);
@end example
This would produce, on the console (stderr) of the application calling it,
something like:
@example
2004-05-08 22:46:14.294 SomeApp[15495] Error occurred reading file at line 20.
@end example
The behavior of this function may be controlled in two ways. First, the user
default @code{GSLogSyslog} can be set to ``@code{YES}'', which will send
these messages to the syslog on systems that support that (Unix variants).
Second, the function GNUstep uses to write the log messages can be
overridden, or the file descriptor the existing function writes to can be
overridden:
@comment{Need ref to where user defaults are explained.}
@example
// these changes must be enclosed within a lock for thread safety
NSLock *logLock = GSLogLock();
[logLock lock];
// to change the file descriptor:
_NSLogDescriptor = <fileDescriptor>;
// to change the function itself:
_NSLog_printf_handler = <functionName>;
[logLock unlock];
@end example
Due to locking mechanisms used by the logging facility, you should protect
these changes using the lock provided by @code{GSLogLock()} (see @ref{Base
Library, , Threads and Run Control} on locking).
The @code{NSLog} function was defined in OpenStep and is also available in Mac
OS X Cocoa, although the overrides described above may not be. The next set of
logging facilities to be described are only available under GNUstep.
@subsection NSDebugLog, NSWarnLog
The facilities provided by the @code{NSDebugLog} and @code{NSWarnLog} families
of functions support source code method name and line-number reporting and
allow compile- and run-time control over logging level.
The @code{NSDebugLog} functions are enabled at compile time by default. To
turn them off, set @code{'diagnose = no'} in your makefile, or undefine
@code{GSDIAGNOSE} in your code before including @code{NSDebug.h}. To turn
them off at runtime, call @code{[[NSProcessInfo processInfo]
setDebugLoggingEnabled: NO]}. (An @code{NSProcessInfo} instance is
automatically instantiated in a running GNUstep application and may be
obtained by invoking @code{[NSProcessInfo processInfo]}.)
At runtime, whether or not logging is enabled, a debug log method is called
like this:
@example
NSDebugLLog(@@"ParseError", @@"Error parsing file at line %d.", lineNumber);
@end example
Here, the first argument to @code{NSDebugLog}, ``@code{ParseError}'', is a
string @i{key} that specifies the category of message. The message will only
actually be logged (through a call to @code{NSLog()}) if this key is in the
set of active debug categories maintained by the @code{NSProcessInfo} object
for the application. Normally, this list is empty. There are
three ways for string keys to make it onto this list:
@itemize
@item
Provide one or more startup arguments of the form @code{--GNU-Debug=<key>} to
the program. These are processed by GNUstep and removed from the argument
list before any user code sees them.
@item
Call @code{[NSProcessInfo debugSet]} at runtime, which returns an
@code{NSMutableSet}. You can add (or remove) strings to this set directly.
@item
The @code{GNU-Debug} user default nay contain a comma-separated list of keys.
However, note that @code{[NSUserDefaults standardUserDefaults]} must first be
called before this will take effect (to read in the defaults initially).
@end itemize
While any string can be used as a debug key, conventionally three types of
keys are commonly used. The first type expresses a ``level of importance''
for the message, for example, ``Debug'', ``Info'', ``Warn'', or ``Error''.
The second type of key that is used is class name. The GNUstep Base classes
used this approach. For example if you want to activate debug messages for
the @code{NSBundle}'' class, simply add '@code{NSBundle}' to the list of keys.
The third category of key is the default key, '@code{dflt}'. This key can be
used whenever the specificity of the other key types is not required. Note
that it still needs to be turned on like any other logging key before
messasges will actually be logged.
There is a family of @code{NSDebugLog} functions with slightly differing
behaviors:
@table @code
@item NSDebugLLog(key, format, args,...)
Basic debug log function already discussed.
@item NSDebugLog(format, args,...)
Equivalent to @code{NSDebugLLog} with key ``dflt'' (for default).
@item NSDebugMLLog(level, format, args,...)
Equivalent to @code{NSDebugLLog} but includes information on which method the
logging call was made from in the message.
@item NSDebugMLog(format, args,...)
Same, but use 'dflt' log key.
@item NSDebugFLLog(level, format, args,...)
As @code{NSDebugMLLog} but includes information on a function rather than a
method.
@item NSDebugFLog(format, args,...)
As previous but using 'dflt' log key.
@end table
The implementations of the @code{NSDebugLog} functions are optimized so that
they consume little time when logging is turned off. In particular, if debug
logging is deactivated at compile time, there is NO performance cost, and if
it is completely deactivated at runtime, each call entails only a boolean
test. Thus, they can be left in production code.
There is also a family of @code{NSWarn} functions. They are similar to the
@code{NSDebug} functions except that they do not take a key. Instead, warning
messages are shown by default unless they are disabled at compile time by
setting @code{'warn = no'} or undefining @code{GSWARN}, or at runtime by
@i{adding} ``@code{NoWarn}'' to @code{[NSProcessInfo debugSet]}.
(Command-line argument @code{--GNU-Debug=NoWarn} and adding ``NoWarn'' to the
@code{GNU-Debug} user default will also work.) @code{NSWarnLog()},
@code{NSWarnLLog()}, @code{NSWarnMLLog}, @code{NSWarnMLog},
@code{NSWarnFLLog}, and @code{NSWarnFLog} are all similar to their
@code{NSDebugLog} counterparts.
@subsection Last Resorts: GSPrintf and fprintf
Both the @code{NSDebugLog} and the simpler @code{NSLog} facilities utilize a
fair amount of machinery - they provide locking and timestamping for example.
Sometimes this is not appropriate, or might be too heavyweight in a case where
you are logging an error which might involve the application being in some
semi-undefined state with corrupted memory or worse. You can use the
@code{GSPrintf()} function, which simply converts a format string to UTF-8 and
writes it to a given file:
@example
GSPrintf(stderr, "Error at line %d.", n);
@end example
If even this might be too much (it uses the @code{NSString} and @code{NSData}
classes), you can always use the C function @code{fprintf()}:
@example
fprintf(stderr, "Error at line %d.", n);
@end example
Except under extreme circumstances, the preferred logging approach is either
@code{NSDebugLog}/@code{NSWarnLog}, due the the compile- and run-time
configurability they offer, or @code{NSLog}.
@subsection Profiling Facilities
GNUstep supports optional programmatic access to object allocation
statistics. To initiate collection of statistics, call the function
@code{GSDebugAllocationActive(BOOL active)} with an argument of
``@code{YES}''. To turn it off, call it with ``@code{NO}''. The overhead
of statistics collection is only incurred when it is active. To access the
statistics, use the set of @code{GSDebugAllocation...()} functions defined in
@code{NSDebug.h}.
@section Assertions
@cindex assertions
@cindex NSAssert macro
@cindex NSAssertionHandler class
Assertions provide a way for the developer to state that certain conditions
must hold at a certain point in source code execution. If the conditions do
not hold, an exception is automatically raised (and succeeding code in the
block is not executed). This avoids an operation from taking place with
illegal inputs that may lead to worse problems later.
The use of assertions is generally accepted to be an efficient means of
improving code quality, for, like unit testing, they can help rapidly uncover
a developer's implicit or mistaken assumptions about program behavior.
However this is only true to the extent that you carefully design the nature
and placement of your assertions. There is an excellent discussion of this
issue bundled in the documentation with Sun's Java distribution.
@comment{Add link to appropriate java.sun.com page.}
@subsection Assertions and their Handling
Assertions allow the developer to establish that certain conditions hold
before undertaking an operation. In GNUstep, the standard means to make an
assertion is to use one of a collection of @code{NSAssert} macros. The
general form of these macros is:
@example
NSAssert(<boolean test>, <formatString>, <argumentsToFormat>);
@end example
For instance:
@example
NSAssert1(x == 10, "X should have been 10, but it was %d.", x);
@end example
If the test '@code{x == 10}' evaluates to @code{true}, @code{NSLog()} is
called with information on the method and line number of the failure, together
with the format string and argument. The resulting console message will look
like this:
@example
Foo.m:126 Assertion failed in Foo(instance), method Bar. X should have been
10, but it was 5.
@end example
After this is logged, an exception is raised of type
'@code{NSInternalInconsistencyException}', with this string as its
description.
In order to provide the method and line number information, the
@code{NSAssert()} routine must be implemented as a macro, and therefore to
handle different numbers of arguments to the format string, there are 5
assertion macros for methods: @code{NSAssert(condition, description)},
@code{NSAssert1(condition, format, arg1)}, @code{NSAssert2(condition, format,
arg1, arg2)}, ..., @code{NSAssert5(...)}.
If you need to make an assertion inside a regular C function (not an
Objective-C method), use the equivalent macros @code{NSCAssert()}, etc..
@i{@b{Note}}, you can completely disable assertions (saving the time for the
boolean test and avoiding the exception if fails) by putting @code{#define
NS_BLOCK_ASSERTIONS} before you include @code{NSException.h}.
@subsection Custom Assertion Handling
The aforementioned behavior of logging an assertion failure and raising an
exception can be overridden if desired. You need to create a subclass of
@code{NSAssertionHandler} and register an instance in each thread in which
you wish the handler to be used. This is done by calling:
@example
[[[NSThread currentThread] threadDictionary]
setObject:myAssertionHandlerInstance forKey:@"NSAssertionHandler"];
@end example
See @ref{Base Library, , Threads and Run Control} for more information on what
this is doing.
@section Comparison with Java
@cindex exception handling, compared with Java
@cindex logging, compared with Java
@cindex assertion handling, compared with Java
GNUstep's exception handling facilities are, modulo syntax, equivalent to
those in Java in all but three respects:
@itemize
@item
There is no provision for a ``finally'' block executed after either the main
code or the exception handler code.
@item
You cannot declare the exception types that could be raised by a method in its
signature. In Java this is possible and the compiler uses this to enforce
that a caller should catch exceptions if they might be generated by a method.
@item
Correspondingly, there is no support in the @ref{GSDoc, documentation system}
for documenting exceptions potentially raised by a method. (This will
hopefully be rectified soon.)
@end itemize
The logging facilities provided by @code{NSDebugLog} and company are similar
to but a bit more flexible than those provided in the Java/JDK 1.4 logging APIs,
which were based on the IBM/Apache Log4J project.
The assertion facilities are similar to but a bit more flexible than those in
Java/JDK 1.4 since you can override the assertion handler.
@page

View file

@ -0,0 +1,122 @@
@paragraphindent 0
@node GSDoc
@appendix The GNUstep Documentation System
@cindex gsdoc
The GNUstep documentation markup language (GSdoc) is an XML language designed
specifically for writing documentation for the @uref{http://www.gnustep.org,
GNUstep project}. In practice, that means that it is designed for writing
about software, and in particular, for writing about Objective-C classes.
It may be used to write narrative documentation by hand, and it can also be
autogenerated by the @i{autogsdoc} tool, which parses Objective-C source
files and documents classes, methods, functions, macros, and variables found
therein, picking up on special comments when provided to enhance the
documentation.
You can read more about GSdoc itself in this
@uref{../../Tools/Reference/gsdoc.html, document}.
The @i{autogsdoc} tool is described
@uref{../../Tools/Reference/autogsdoc.html, here}.
(Both of these documents are part of the
@uref{../../Tools/Reference/index.html, Base Tools} documentation.)
@section Quick Start
The basic approach to using GSdoc is this: when writing source code, put
comments that begin with ``@code{/**}'' instead of the usual C ``@code{/*}''
in your @code{@@interface} or @code{@@implementation} file above class,
variable, and method declarations. If you have any functions or macros you
are making available put such comments in front of them too. The comments
still end with the regular ``@code{*/}'', no ``@code{**/}'' is necessary.
@example
/**
* The point class represents 2-d locations independently of any graphical
* representation.
*/
@@interface Point : NSObject
@{
// instance variables ...
@}
/**
* New point at 0,0.
*/
+ new;
// ...
/**
* Return point's current X position.
*/
- (float) x;
// ...
@@end
@end example
When you are finished, invoke @i{autogsdoc} giving it the names of all
your header files. (It will find the implementation files automatically, as
long as they have the same names; alternatively, give it the names of the
implementation files as well.) This will produce a set of HTML files
describing your classes. If you include the '@code{-MakeFrames YES}'
argument, the HTML will be structured into frames for easy navigation.
(Autogsdoc, like all GNUstep command line tools, is found in the
$@{GNUSTEP_SYSTEM_ROOT@}/Tools directory.)
You can also generate documentation automatically using the GNUstep make
utility. Consult its primary @uref{../../Make/Manual/make_toc.html,
documentation} for details. The short story is:
@example
include $(GNUSTEP_MAKEFILES)/common.make
DOCUMENT_NAME = MyProject
MyProject_AGSDOC_FILES = <space-separated list of header files>
MyProject_AGSDOC_FLAGS = <flags, like MakeFrames YES>
include $(GNUSTEP_MAKEFILES)/documentation.make
@end example
Usually this is put into a separate makefile called ``@code{DocMakeFile}'' in
the source directory.
@section Comment the Interface or the Implementation?
Since @code{autogsdoc} picks up comments both from interface/header files and
implementation/source files, you might be wondering where it is best to put
them. There is no consensus on this issue. If you put them in the interface,
then anyone you distribute your library to (with the headers but not the
source) will be able to generate the documentation. The header file carries
all of the specification for the class's behavior. On the other hand, if you
put the comments in the implementation, then people editing the source code
will have the method descriptions handy when they need them. If @i{autogsdoc}
finds comments for the same entity in both interface and implementation, the
version in the implementation file ``wins''.
@section Comparison with OS X Header Doc and Java JavaDoc
The HTML output from all of these systems is roughly comparable. In terms of
and comments needed in the source code to produce good class documentation,
the GSdoc / autogsdoc system aims for maximal simplicity. In practice,
requiring lots of special formatting makes developers less likely to document
things. For example, to refer to an argument of the method or function you
are documenting, just type it normally. To refer to another method within the
same class you are documenting, just type its selector with the + or - sign in
front. No need to enclose it in special markup. To refer to another class in
documentation, you just type the class's name in [Brackets]. To refer to a
function, simply type its name with parentheses().
In terms of non-HTML output formats and control over the HTML format, these
are not provided with GSdoc, yet, but there are plans to provide them through
the use of XSLT as a presentation layer.
@page

View file

@ -0,0 +1,255 @@
@node Objective-C Java and C++
@appendix Differences and Similarities Between Objective-C, Java, and C++
@cindex Objective-C and Java, differences and similarities
@cindex differences and similarities, Objective-C and Java
@cindex Objective-C and C++, differences and similarities
@cindex differences and similarities, Objective-C and C++
@paragraphindent 0
This appendix explains the differences/similarities between Objective-C and
Java. It does not cover the Java Interface to GNUstep (JIGS; see @ref{Java and
Guile}), but is included to help people who want to learn Objective-C and know
Java already.
@section General
@itemize @bullet
@item
C programmers may learn Objective-C in hours (though real expertise
obviously takes much longer).
@item
Java has global market acceptance.
@item
Objective-C is a compiled OO programming language.
@item
Java is both compiled and interpreted and therefore does not offer
the same run-time performance as Objective-C.
@item
Objective-C features efficient, transparent Distributed Objects.
@item
Java features a less efficient and less transparent Remote Machine
Interface.
@item
Objective-C has basic CORBA compatibility through official C bindings,
and full compatibility through unofficial Objective-C bindings.
@item
Java has CORBA compatibility through official Java bindings.
@item
Objective-C is portable across heterogeneous networks by virtue of a
near omnipresent compiler (gcc).
@item
Java is portable across heterogeneous networks by using client-side JVMs
that are software processors or runtime environments.
@end itemize
@section Language
@itemize @bullet
@item
Objective-C is a superset of the C programming language, and may
be used to develop non-OO and OO programs. Objective-C provides
access to scalar types, structures and to unions, whereas Java
only addresses a small number of scalar types and everything else
is an object. Objective-C provides zero-cost access to existing
software libraries written in C, Java requires interfaces to be
written and incurs runtime overheads.
@item
Objective-C is dynamically typed but also provides static typing.
Java is statically typed, but provides type-casting mechanisms to
work around some of the limitations of static typing.
@item
Java tools support a convention of a universal and distributed
name-space for classes, where classes may be downloaded from
remote systems to clients. Objective-C has no such conventions
or tool support in place.
@item
Using Java, class definitions may not be extended or divided through
the addition of logical groupings. Objective-C provides categories
as a solution to this problem.
@item
Objective-C provides delegation (the benefits of multiple inheritance
without the drawbacks) at minimal programming cost. Java requires
purpose written methods for any delegation implemented.
@item
Java provides garbage collection for memory management. Objective-C
provides manual memory management, reference counting, and garbage
collection as options.
@item
Java provides interfaces, Objective-C provides protocols.
@end itemize
@section Source Differences
@itemize @bullet
@item
Objective-C is based on C, and the OO extensions are comparable with
those of Smalltalk. The Java syntax is based on the C++ programming
language.
@item
The object (and runtime) models are comparable, with Java's
implementation having a subset of the functionality of that
of Objective-C.
@end itemize
@section Compiler Differences
@itemize @bullet
@item
Objective-C compilation is specific to the target system/environment,
and because it is an authentic compiled language it runs at higher
speeds than Java.
@item
Java is compiled into a byte stream or Java tokens that are interpreted
by the target system, though fully compiled Java is possible.
@end itemize
@section Developer's Workbench
@itemize @bullet
@item
Objective-C is supported by tools such as GNUstep that provides
GUI development, compilation, testing features,
debugging capabilities, project management and database access.
It also has numerous tools for developing projects of different
types including documentation.
@item
Java is supported by numerous integrated development environments
(IDEs) that often have their origins in C++ tools.
Java has a documentation tool that parses source code and creates
documentation based on program comments. There are similar features
for Objective-C.
@item
Java is more widely used.
@item
Objective-C may leverage investment already made in C based tools.
@end itemize
@section Longevity
@itemize @bullet
@item
Objective-C has been used for over ten years, and is considered to be
in a stable and proven state, with minor enhancements from time to time.
@item
Java is evolving constantly.
@end itemize
@section Databases
@itemize @bullet
@item
Apple's EOF tools enable Objective-C developers to build object
models from existing relational database tables. Changes in the
database are automatically recognised, and there is no requirement
for SQL development.
@item
Java uses JDBC that requires SQL development; database changes
affect the Java code. This is considered inferior to EOF. Enterprise
JavaBeans with container managed persistence provides a limited database
capability, however this comes with much additional baggage. Other
object-relational tools and APIs are being developed for Java (ca. 2004), but
it is unclear which of these, if any, will become a standard.
@end itemize
@section Memory
@itemize @bullet
@item
For object allocation Java has a fixed heap whose maximum size
is set when the JVM starts and cannot be resized unless the
JVM is restarted. This is considered to be a disadvantage in
certain scenarios: for example, data read from databases may
cause the JVM to run out of memory and to crash.
@item
Objective-C's heap is managed by the OS and the runtime system.
This can typically grow to consume all system memory (unless
per-process limits have been registered with the OS).
@end itemize
@section Class Libraries
@itemize @bullet
@item
Objective-C: Consistent APIs are defined by the OpenStep specification.
This is implemented by GNUstep and Mac OS X Cocoa. Third-party APIs are
available (called Frameworks).
@item
Java: APIs are defined and implemented by the Sun Java Development
Kit distributions. Other providers of Java implementations (IBM, BEA, etc.)
implement these as well.
@item
The Java APIs are complex owing to the presence of multiple layers of
evolution while maintaining backwards compatibility. Collections, IO, and
Windowing are all examples of replicated functionality, in which the copies
are incompletely separated, requiring knowledge of both to use.
@item
The OpenStep API is the result of continuing evolution but backward
compatibility was maintained by the presence of separate library versions.
Therefore the API is clean and nonredundant. Style is consistent.
@item
The OpenStep non-graphical API consists of about 70 classes and about 150
functions.
@item
The equivalent part of the Java non-graphical API consists of about 230
classes.
@item
The OpenStep graphical API consists of about 120 classes and 30 functions.
@item
The equivalent part of the Java graphical API consists of about 450 classes.
@end itemize