mirror of
https://github.com/gnustep/libs-base.git
synced 2025-04-23 00:41:02 +00:00
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:
parent
49d11595cd
commit
948b5dfb97
8 changed files with 2441 additions and 130 deletions
392
Documentation/manual/AdvancedMessaging.texi
Normal file
392
Documentation/manual/AdvancedMessaging.texi
Normal 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
|
|
@ -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]].
|
983
Documentation/manual/BaseLibrary.texi
Normal file
983
Documentation/manual/BaseLibrary.texi
Normal 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
|
19
Documentation/manual/Bundles.texi
Normal file
19
Documentation/manual/Bundles.texi
Normal 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
|
114
Documentation/manual/Compliance.texi
Normal file
114
Documentation/manual/Compliance.texi
Normal 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
|
556
Documentation/manual/ExceptionHandling.texi
Normal file
556
Documentation/manual/ExceptionHandling.texi
Normal 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
|
122
Documentation/manual/GSDoc.texi
Normal file
122
Documentation/manual/GSDoc.texi
Normal 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
|
255
Documentation/manual/ObjcAndJavaC++.texi
Normal file
255
Documentation/manual/ObjcAndJavaC++.texi
Normal 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
|
||||
|
Loading…
Reference in a new issue