PATH Documentation > Release Notes
Mac OS X Leopard Developer Release Notes
Cocoa Foundation Framework
The Foundation Framework is a library of Objective-C classes that provide the infrastructure for object-based applications without graphical user interfaces.
This document describes the changes in Foundation Framework since Mac OS X release 10.4. Changes since the WWDC 2007 seed of Leopard are highlighted (search for "WWDC 2007").
Links to some of the significant notes in this document:
You can find release notes for the Application Kit as well as some notes on general backward compatibility issues, version handling, etc, here.
Backward Compatibility
One backward compatibility mechanism that is occasionally used in the frameworks is to check for the version of the SDK an application was built against, and if an older SDK, modify the behavior to be more compatible. This is done in cases where bad incompatibility problems are predicted or discovered; and most of these are listed below in these notes.
Typically we detect where an application was built by looking at the version of the system frameworks the application was linked against. Thus, as a result of relinking your application on Leopard or against Leopard SDK, you might notice different behaviors, some of which might cause incompatibilities. In these cases because the application is being rebuilt, we expect you to address these issues at the same time as well. For this reason, if you are doing a small incremental update of your application to address a few bugs, it's usually best to continue building on the same build environment and libraries used originally, or against the original SDKs.
In some cases, we provide defaults (preferences) settings which can be used to get the old or new behavior, independent of what system an application was built against. Often these preferences are provided for debugging purposes only; in some cases the preferences can be used to globally modify the behavior of an application by registering the values (do it somewhere very early, with -[NSUserDefaults registerDefaults]).
Performance and compatibility
As in any major software update, many things have changed their specific performance characteristics in 10.5. Some things may be somewhat slower, but we try not to do too much of that. Some things may be faster, perhaps much faster, and thus may be much slower when the same app is run on 10.4 or earlier. Always check and test your app on the earlier release that you want to run on, for performance as well as just for correct functioning.
64 Bit
Leopard contains 64-bit versions of system frameworks, enabling building and running many Cocoa apps as 64-bit.
There are a significant number of API changes in Cocoa to accomodate and enable 64-bit. Most are due to the introduction of two new types, NSInteger and NSUInteger, as a way to represent "address-sized" integers on both 32 and 64-bit. NSInteger is defined as "int" on 32-bit and "long" on 64-bit, and NSUInteger is its unsigned counterpart. Almost all Cocoa-based APIs have been upgraded to use NSInteger or NSUInteger in place of int or unsigned int. NSInteger is analogous to CoreFoundation's CFIndex type.
(Note that early in Leopard, NSInteger and NSUInteger were named NSInt and NSUInt, respectively. These old names have been removed before final release of Leopard.)
Moving forward, applications should be using these new types (and CGFloat - see below) instead of int, unsigned int, and float, since this will make an eventual move to 64-bit much easier. We recommend this even for apps that need to run on Tiger; they can accomplish this with their own, Tiger-only definitions of these types.
We have a "tops"-based conversion script in /Developer/Extras/64BitConversion to help convert Cocoa applications to 64-bit. Information about this script and the Cocoa 64-bit effort in general can be found in the 64-Bit Transition Guide for Cocoa.
In general it should be possible to use the same source base for both the 32 and 64-bit versions of an application or framework. Running this script on your source base to convert your sources to 64-bit should still enable them to build and run correctly under 32-bit. If needed, you can do:
#if __LP64__
...
#endif
as a way to do 64-bit specific code.
In APIs where the term "int" appeared as a part of the method name (for instance, "intValue"), the term "integer" is used to represent this new NSInteger type, while "int" continues to refer to the native int type (which is 32-bit under both 32 and 64). Thus methods like intValue, numberWithInt:, scanInt:, etc continue to take or return ints, while methods such as integerForKey: in NSUserDefaults have been changed to take NSInteger. We are adding a number of counterpart methods in Foundation and AppKit that take or return NSInteger or NSUInteger arguments.
The new methods in Foundation are:
NSCoder:
- (void)encodeInteger:(NSInteger)intv forKey:(NSString *)key;
- (NSInteger)decodeIntegerForKey:(NSString *)key;
NSString:
- (NSInteger)integerValue;
NSScanner:
- (BOOL)scanInteger:(NSInteger *)ptr;
NSNumber:
- (NSInteger)integerValue;
- (NSUInteger)unsignedIntegerValue;
- (id)initWithInteger:(NSInteger)value;
- (id)initWithUnsignedInteger:(NSUInteger)value;
+ (NSNumber *)numberWithInteger:(NSInteger)value;
+ (NSNumber *)numberWithUnsignedInteger:(NSUInteger)value;
We also have the following new constants in NSObjCRuntime.h:
#define NSIntegerMax LONG_MAX
#define NSIntegerMin LONG_MIN
#define NSUIntegerMax ULONG_MAX
Note that by design, keyed archiving's handling of integral types is not strict. An integer quantity written with any of encodeInteger:forKey:, encodeInt32:forKey:, or encodeInt64:forKey: can be read back using any of the integer decode methods. If the value is too large to read using the specified decode method, an exception is raised.
For most integral values, we recommend the use of encodeInteger:forKey: and decodeIntegerForKey:. For values whose ranges are larger than what 32-bit signed integers can hold, the Int64: variants continue to be the more appropriate choice, even on 32-bit.
There are additional archiving and other considerations in the presence of 64-bit changes in our APIs. The 64-bit Transition Guide referred to above has more information on this topic and more.
CGFloat
Another major change in Cocoa APIs is the introduction of the CGFloat type in Quartz. This replaces the use of float, and is defined as double for 64-bit. Note that this is not a change dictated by the 64-bit move; however, we are taking advantage of the move to introduce this new type. The purpose of CGFloat is to provide higher precision and range in graphical values, for 64-bit applications. This type replaces the use of all graphical float types in Cocoa APIs, including those in Foundation's NSGeometry.h.
Another change in NSGeometry.h is the redeclaration of NSRect, NSPoint, and NSSize using the Quartz counterparts, CGRect, CGPoint, and CGSize. Unfortunately, due to binary compatibility considerations, this change is done for 64-bit only. Note that the Objective C type signatures of these types thus differs on 64-bit from that on 32-bits.
Enum name removal
As a part of 64-bit clean-up, we added explicitly sized types where we were previously using enums. For instance, we went from:
typedef enum NSAlertStyle {
NSWarningAlertStyle = 0,
NSInformationalAlertStyle = 1,
NSCriticalAlertStyle = 2
} NSAlertStyle;
to
enum {
NSWarningAlertStyle = 0,
NSInformationalAlertStyle = 1,
NSCriticalAlertStyle = 2
};
typedef NSUInteger NSAlertStyle;
The latter makes sure that NSAlertStyle remains a fixed size and signedness no matter how the enum contents change.
In doing this, we removed the enum names from the enum declarations, so any attempt to use "enum NSAlertStyle" will now fail. Please switch to using the typedef instead, which is fixed size.
Fast enumeration
Leopard introduces the NSFastEnumeration protocol which allows a fast, safe method for objects to provide object enumerations:
@protocol NSFastEnumeration
- (NSUInteger)countByEnumeratingWithState:(NSFastEnumerationState *)state
objects:(id *)stackbuf
count:(NSUInteger)len;
@end
typedef struct {
unsigned long state;
id *itemsPtr;
unsigned long *mutationsPtr;
unsigned long extra[5];
} NSFastEnumerationState;
This protocol is implemented by Foundation collections as well as NSEnumerator, and is used by the new language "for...in" feature for enumerating:
for (id myObj in myArray) { ... do something with myObj ... }
Mutation of the object is forbidden during iteration, and there can be several iterations executing concurrently.
The following rules must be obeyed by any implementation:
1. On first entry, the "state" field will be 0, otherwise the client is neither allowed or required to alter state. State must be set to a non-zero before returning a non-zero count (otherwise the client will go into an infinite loop expecting a zero return, and the object will always be starting a new enumeration). For complicated enumerations "extra" is supplied to hold extra state.
2. On exit, a count of 0 means that there are no objects available for enumeration. This may reflect a bad or inconsistent internal state, or more normally it may simply reflect that no more objects are available. But if the value is zero, the client can make no assumptions about the content of state.
3. A non-zero count return implies that itemsPtr has been set to point to the first of the non-zero count objects. This is encouraged to be a pointer to internal object state where feasible. If not feasible, the client has supplied a stack buffer at "objects" and the length in the "count" parameter, and the object pointers to be iterated should be copied there (no GC primitives required). In addition, mutationsPtr is set to a valid address that should track some form of change counter for this object. If the object is immutable, this pointer could point to the object itself.
This protocol is designed to work when sent to nil objects.
Warning about mutations during enumerations
As mentioned above, in the discussion for fast enumeration, it is a significant programming error to enumerate a mutable collection and mutate that same collection. This has always been the case, but in Tiger, many applications got away with this due to an implementation detail of most NSEnumerators. A link check has been provided for these applications in order to allow them to continue to function safely.
For applications linked on Leopard, when a mutation is detected during enumeration, an NSInvalidArgumentException will be thrown:
2006-05-23 13:46:08.945 MyTestApp[756] *** Uncaught exception: <NSInvalidArgumentException>
Collection <NSCFArray: 0x303d70> was mutated while being enumerated.
Garbage Collection
In Leopard it is now possible to write Cocoa applications which are garbage collected. Application developers choose (in Xcode, or through compiler flags) whether they want their applications to run garbage collected or not. System frameworks are designed to work with both garbage collected and non-garbage collected apps. Note that all binaries (bundles, frameworks, plug-ins) loaded by a garbage collected app also need to be garbage collected, otherwise they are not loaded.
Please refer to developer documentation for more details on garbage collection.
Foundation includes a new class, NSGarbageCollector, which provides a default shared instance that can be messaged to control garbage collection behavior.
NSMapTable, NSHashTable
NSMapTable and NSHashTable are now available as objects. They are generally usable, but are especially useful in garbage collected applications. The existing functional API continues to work as well.
As objects, these classes provide new APIs for accessing them as if they always and only contain objects. We also provide common and interesting options for construction - to be created with an option to copy in its arguments, to treat the objects as pointers with regard to hashing and equality, and option to hold them in a non-retained zero-ing weak manner. These, and especially the latter, are the predominant uses that have turned up as code has been converted to be GC-compatible.
Note that even as objects NSMapTable and NSHashTable are distinct from NSDictionary and NSSet, which have rigorous semantic definitions that a lot of code relies upon. NSMapTable and NSHashTable are not plist types.
NSMapTable and NSHashTable conform to NSFastEnumeration, like other collections.
Exceptions
Zero-overhead exceptions in 64-bit
In 64-bit, Objective C uses the same technology as C++ to implement exception throwing, which makes the cost of entering a @try block fall to zero, and the cost of raising an exception much higher.
New NSException API
The NSException class now offers this new API:
- (NSArray *)callStackReturnAddresses;
This method returns an array of NSNumbers with the return addresses from the thread's stack, with the first values in the array being from the lowest frames on the stack, at the time and on the thread on which the exception was first raised. Re-raising the exception does not reset this value. There is no way to set this value.
NSException macro changes
The _NSSETJMP macro is no longer defined. It was not for your use.
The NSHandler and NSHandler2 and struct _NSHandler2 types are no longer defined. They were not for your use.
The _NSAddHandler2, _NSRemoveHandler2, and _NSExceptionObjectFromHandler2 functions are no longer declared. They were not for your use.
The NS_DURING, NS_HANDLER, and NS_ENDHANDLER macros have been redefined in terms of @try/@catch Objective C syntax. The NS_VALUERETURN and NS_VOIDRETURN macros have been updated to match.
Throwing objects other than NSExceptions in Cocoa apps
Do not throw objects other than NSExceptions (or, perhaps, a subclass thereof) in Cocoa apps. Doing so is a recipe for potential disaster if the exception is seen by Cocoa code. Just don't do it. Cocoa code may also completely and silently squash any non-object type, and possibly any non-NSException * type, exceptions that get to the Cocoa code.
Setting a breakpoint to catch exception raises
To trap exceptions being thrown in the debugger, break on objc_exception_throw. This will catch all exception throwing, in 32-bit and 64-bit, and whether the exception was thrown with @throw or thrown with -[NSException raise]. Setting a breakpoint on the latter has never caught exception throwing due to @throw.
Exceptions caught from outside callbacks no longer dropped
Foundation used to catch exceptions in certain places and not re-raise them, just log a message like "Exception ignored while..." or "Exception raised during... Ignored. ...". For apps linked on 10.5 and later, Foundation no longer does this, it just lets the exception pass through those points.
Note that letting exception escape from application code back up into system framework/library code (Cocoa or non-Cocoa code) in inheritently unpredictable. C code, for example, cannot react to exceptions being raised across a C language activation frame on the stack, partly because the syntax isn't available and partly because exceptions are not part of the language so there should be no need for C code to be aware of exceptions. So, data structures, locks, and other things may be left in an unpredictable/inconsistent state, and memory or other resources leaked. Even existing Objective C code is not necessarily robust in these regards. It is perfectly possible -- just as one example which isn't a crash -- that a raised exception will cause the application UI to freeze up and be completely unresponsive after the exception, which means the user will not be able to save any documents or other unsaved changes.
NSOperation, NSOperationQueue
NSOperation is an object which performs some encapsulated task. NSOperationQueue holds a priority queue of NSOperation instances to execute, and provides a flow regulation mechanism for operation execution.
NSOperations need not be put in NSOperationQueues to be executed - they can be executed at any time, and NSOperations which are designed as "active" objects may in fact start themselves when the appropriate conditions exist.
NSOperation has dependency management; an operation is not ready to be executed until all of the other operations in its dependency list are finished.
NSOperation provides methods to enable declaring whether it can be executed asynchronously; NSOperationQueue in turn provides methods to specify how many concurrent operations to allow. These features make NSOperation/NSOperationQueue a good fit for specifying encapsulated tasks in a way that will take advantage of multi-processor machines.
Please refer to the documentation for more information on NSOperation and NSOperationQueue.
NSThread
NSThread now enables setting a name. The primary purpose of this method is debugging:
- (void)setName:(NSString *)n;
- (NSString *)name;
You now can specify a stack size for a thread. This is obeyed if it's set only before the thread has been started. The underlying operating system may impose constraints on the value:
- (void)setStackSize:(NSUInteger)s;
- (NSUInteger)stackSize;
The following methods enable finding out about the main thread:
- (BOOL)isMainThread;
+ (BOOL)isMainThread; // reports whether current thread is main
+ (NSThread *)mainThread;
NSThread now has init methods to enable creation without starting:
- (id)init; // designated initializer
- (id)initWithTarget:(id)target selector:(SEL)selector object:(id)argument;
If the target object does not implement the selector, the -initWithTarget:selector:object: method returns nil. The target object and argument are retained for the life of the NSThread.
The following methods enable more control over NSThread execution:
- (BOOL)isExecuting;
- (BOOL)isFinished;
- (BOOL)isCancelled;
- (void)cancel;
- (void)start;
- (void)main; // thread body method
The -start method creates an underlying thread object and starts it executing; it can fail due to OS resource limits being reached or the thread being previously cancelled. -start causes -main to be called in the context of the new thread. The default behavior of -main is to do nothing if the thread was not initialized with a target/selector/argument, otherwise it invokes the method on the target. A subclass of NSThread can override -main to perform whatever work the thread is supposed to do (analogous to the thread function given to pthread_create()).
The -start method is the one that should be called by clients of NSThread to start a thread running; -main should not be called from outside the thread object.
The executing pthread has a logical retain on the thread object, once -start has been called. When the control flow of a thread terminates, the backing pthread is destroyed, but the NSThread object may continue to exist if there are additional retains.
The -main method is implemented to perform the function of the operation. The -main method must properly maintain the isExecuting and isFinished states. For example, -main must capture exceptions raised back to it and change the states if before returning or re-raising the exception (actions which imply that the operation is transitioning from executing to finished). However, it is legitimate for the -main method to never return and continue to execute indefinitely.
The "cancel" state is advisory: this state can be polled by code to find out if it should stop what it is doing, but it does not force stoppage in any way. This is not the same as pthread cancellation. 'Cancelled' is a one-way state transition, you cannot set a operation object back to "uncancelled". The code being executed by the operation can terminate the execution by causing control flow to exit the -main method (by returning from that method or raising an exception from that method). Because the cancelled state is advisory, it is orthogonal to the "executing" and "finished" states.
The following is a slightly less expensive version of the +sleepUntilDate: method, since an NSDate object need not be created. Although it has just been publicized, it has been in Foundation since 10.0 and can be used on older systems:
+ (void)sleepForTimeInterval:(NSTimeInterval)ti;
The following new method on NSObject enables executing in the context of a specific NSThread:
- (void)performSelector:(SEL)aSelector
onThread:(NSThread *)thr
withObject:(id)arg
waitUntilDone:(BOOL)wait
modes:(NSArray *)array;
There is also a version without the modes: argument, which is equivalent to the above method called with kCFRunLoopCommonModes.
The naming matches the existing performSelectorOnMainThread:... methods, which become a special case of these methods. These new methods have the same semantics as the existing performSelectorOnMainThread:... methods, except that a particular NSThread object can be specified.
Finally the following method is a convenience to encapulate the process of creating a new thread to run the given method. No 'modes' argument is needed, as the run loop is not involved here. Semantically similar to other existing performSelector-style methods.
- (void)performSelectorInBackground:(SEL)aSelector withObject:(id)arg;
Another new method in NSThread is:
+ (NSArray *)callStackReturnAddresses;
This method returns an array of NSNumbers with the return addresses from the current thread's stack, with the first values in the array being from the lowest frames on the stack, at the time of the call to this method.
NSProcessInfo
NSProcessInfo now exposes a new method for returning the amount of physical memory installed in the computer.
- (unsigned long long)physicalMemory;
returns the amount of memory in bytes physically installed in the computer. Developers may use this method as a way of determining memory allocation patterns particularly in 64 bit applications.
The following new methods return the number of processors as well as the number of active processors in the machine:
- (NSUInteger)processorCount;
- (NSUInteger)activeProcessorCount;
Note that the number of available processors can vary over time, for example, if CPUs are turned off or on by the user.
NSCondition
NSCondition is a new class in Foundation. An NSCondition is a pthread-style condition variable, combined with the associated mutex lock. NSCondition operates just like pthread_conds with the same usage patterns and potential pitfalls.
The existing NSConditionLock class is a more limited version of this. An NSConditionLock defines only an integer state that the condition test tests against. So, NSCondition, by allowing the while predicate test to be moved outside the object, allows for greater flexibility, beyond simple integer equality.
The usage pattern is almost always this:
[cond lock];
while (TEST) {
[cond wait];
}
...
[cond signal]; // or broadcast
[cond unlock];
NSCondition already existed inside Foundation, and has since before 10.0. So it can be used on older operating systems.
NSLock logging
NSLock and subclasses will now indicate erroneous lock and unlock attempts with logs such as:
2006-07-14 09:17:00.729 MyTestApp *** -[NSConditionLock unlockWithCondition:]: lock (<NSConditionLock: 0x183b3800>)
unlocked when not locked
2006-07-14 09:17:00.729 MyTestApp *** Break on _NSLockError() to debug.
These almost always indicate problems that should be fixed. In many cases the problems were there in 10.4 as well, but not being reported.
NSLock naming
NSLock, NSRecursiveLock, NSConditionLock, and NSCondition objects can now be named with two new methods in each class:
- (void)setName:(NSString *)n;
- (NSString *)name;
The name is emitted in NSLogs about the objects and in their descriptions.
Distributed Objects
Distributed Objects and 64 bit
In a distributed objects environment prior to Leopard, method signatures of the local and remote objects were assumed to be the same; if they were different an exception would be thrown. With the introduction of 64 bit Foundation, the signatures may differ. For example, a 32 bit spell server communicating with a 64 bit text editor will result in different NSRange types - the server will consider it to be a struct of two 32 bit ints, and the client will consider it to be a struct of two 64 bit longs.
To provide for DO communication between these processes, the DO signature equality requirement has been relaxed to method signature "compatibility." Two method signatures are compatible if the type of each argument (and return value) in the signature can be converted to the corresponding type in the other signature. Conversions within (but not between) the following groups are allowed:
• int, long, long long
• unsigned int, unsigned long, unsigned long long
• float, double
Aggregate types such as structs are compatible if their members are compatible, recursively. For example, float can be converted to or from double, and therefore NSPoints and NSSizes can be passed between 32 bit and 64 bit processes because they are composed of floats and doubles, and therefore NSRects can be passed as well because they are composed of NSPoints and NSSizes.
Distributed Objects overflow and underflow behavior
If a conversion would result in an out of range value, the result is set to the closest value supported by that type. For example, if the 64 bit signed integer value 5000000000 (five billion) is passed via DO to an object expecting a 32 bit signed integer value, it will receive the value INT_MAX. The possible results of integer overflow or underflow are therefore:
INT_MAX
INT_MIN
UINT_MAX
Double values smaller than the smallest floating point value are always rounded towards zero. The possible results of floating point overflow or underflow are therefore:
FLT_MAX
-FLT_MAX
0.f
-0.f
Be aware that this behavior may not preserve the semantics of certain special values. For example, -[NSArray indexOfObject:] called on a 64 bit process will return UINT_MAX to a 32 bit process instead of the 32 bit value of NSNotFound.
If overflow or underflow occurs for any type, a message is logged by the server to the console.
Distributed Objects local signature search sequence
When a method to be forwarded is called on an NSDistantObject, the object needs information about how the method was called to properly construct the NSInvocation - specifically, it needs the NSMethodSignature corresponding to the method signature that the compiler used. NSDistantObject searches for the method signature in the following places, in order:
• Within the Protocol set on the NSDistantObject via setProtocolForProxy:
• Within the local class of the same name as the remote object's class
• Within the remote object
Therefore, if the call may have been compiled against a different method signature than that of the remote object, you must ensure that the class is available locally, or better yet, that the methods you call are present in the NSDistantObject's Protocol. If the method signature is only available remotely, and it differs from what the compiler saw, parameters and return values will not be passed correctly. For example, if you compile a 32 bit client against a method signatures that uses NSInteger, but the actual server is 64 bit, and no protocol is set on the object, and the class is not present in the client, the parameters will not be passed correctly.
Distributed Objects Tiger compatibility
These conversions are not supported if either the client or server is running Tiger or earlier. To use distributed objects on a pre-Leopard version of the OS, you must ensure that the client and server method signatures match exactly in both size and type.
NSNotFound
As part of the 64-bit porting, NSNotFound is now defined as NSIntegerMax. Formerly it was 0x7fffffff, effectively the same thing on 32-bit. Note that since the value is different in 32-bit and 64-bit, it is a bad idea to [continue to] save it in files or archives, if you are today, and sending it between 32-bit and 64-bit processes via Distributed Objects will not get you NSNotFound on the other side. This applies to any Cocoa methods invoked over D.O. as well, which might return NSNotFound, such as -indexOfObject: in NSArray (specifically, when sent to a proxy to an array, of course).
Leaks in Distributed Objects plugged
Some leaks, and places where objects could leak if the timing was right, in Distributed Objects have been fixed in 10.5. This may mean that you may no longer get away with something you used to get away with due to the leak. Not retaining the root proxy you get from the connection, if you're going to hold onto it, seems to be a common pitfall.
Key Value Coding and Observing (KVC, KVO)
New KVO Options
Two new key-value observing options that can be used when invoking -[NSObject(NSKeyValueObserverRegistration) addObserver:forKeyPath:options:context:] have been added in Mac OS 10.5. The first merely allows to you specify that the observer should receive a notification about the observed property's value right away:
NSKeyValueObservingOptionInitial = 0x04,
Specifies whether a notification should be sent to the observer immediately, before the observer registration method even returns. The change dictionary in the notification will always contain an NSKeyValueChangeNewKey entry if NSKeyValueObservingOptionNew is also specified but will never contain an NSKeyValueChangeOldKey entry. (In an initial notification the current value of the observed property may be old, but it's new to the observer.) You can use this option instead of explicitly invoking, at the same time, code that is also invoked by the observer's -observeValueForKeyPath:ofObject:change:context: method. When this option is used with -addObserver:toObjectsAtIndexes:forKeyPath:options:context: a notification will be sent for each indexed object to which the observer is being added.
The second allows you to specify that the observer should receive change notifications before and after changes, instead of just after:
NSKeyValueObservingOptionPrior = 0x08
Specifies whether separate notifications should be sent to the observer before and after each change, instead of a single notification after the change. The change dictionary in a notification sent before a change always contains an NSKeyValueChangeNotificationIsPriorKey entry (also declared in <Foundation/NSKeyValueObserving.h>) whose value is [NSNumber numberWithBool:YES], but never contains an NSKeyValueChangeNewKey entry. When this option is specified the change dictionary in a notification sent after a change contains the same entries that it would contain if this option were not specified. You can use this option when the observer's own KVO-compliance requires it to invoke one of the -willChange... methods for one of its own properties, and the value of that property depends on the value of the observed object's property. (In that situation it's too late to easily invoke -willChange... properly in response to receiving an -observeValueForKeyPath:ofObject:change:context: message after the change.)
Support for Key Paths in KVO's Dependency Mechanism (Updated since WWDC 2007)
A simple property dependency mechanism was included in KVO when it was first published in Mac OS 10.3, in the form of the +[NSObject(NSKeyValueObservingCustomization) setKeys:triggerChangeNotificationsForDependentKey:] method and KVO's use of the information recorded by your application's invocation of it. This mechanism however:
• Did not support key paths.
• Was not very easy to program with, because it was difficult to determine when exactly to invoke +setKeys:triggerChangeNotificationsForDependentKey:.
In Mac OS 10.5, +setKeys:triggerChangeNotificationsForDependentKey: has been deprecated and a new method, +keyPathsForValuesAffectingValueForKey: has been published. It doesn't suffer from either of the just-described problems. See the comments for it in <Foundation/NSKeyValueObserving.h> for more information.
Note: This was not yet true in the WWDC 2007 seed, even though this enhancement was mentioned in the seed's version of this release note.
Better Support in KVO for Properties Added By Categories (Updated since WWDC 2007)
+automaticallyNotifiesObserversForKey: did not lend itself well to situations where the getter for the keyed property was added by a class category. To fix this problem, the default implementation of +automaticallyNotifiesObserversForKey: has been updated to find methods whose names follow the pattern +automaticallyNotifiesObserversOf<Key>. (This is consistent with the way the new +keyPathsForValuesAffectingValueForKey: method works.) Such methods can be easily implemented in categories right next to the corresponding getter methods. See the comments for it in <Foundation/NSKeyValueObserving.h> for more information.
Note: This was not yet true in the WWDC 2007 seed, even though this enhancement was mentioned in the seed's version of this release note.
Support in KVO for Cascading Property Dependencies (New since WWDC 2007)
In Mac OS 10.3 and Mac OS 10.4 you could use the now-deprecated +setKeys:triggerChangeNotificationsForDependentKey: method to declare that property X of a class depends on property Y, and that property Y depends on property Z, but changes to the value of Z would not result in notifications sent to observers of X. In Mac OS 10.5 changes to the value of Z now result in notifications sent to observers of both X and Y, regardless of whether the dependencies were registered using +setKeys:triggerChangeNotificationsForDependentKey: or the newer +keyPathsForValuesAffectingValueForKey: mechanism described above.
Bug Fix in KVO's Dependency Mechanism
In Mac OS 10.3 and Mac OS 10.4 there was a bug in which KVO's dependency mechanism did not interoperate well with observing by key path. For example, given a class Foo with properties "visible" and "visibleThing," where -visibleThing would always return nil if visible was set to NO, or always return an object that itself had a "name" attribute if visible was set YES, and given that the dependency of "visibleThing" on "visible" was declared by invoking [Foo setKeys:[NSArray arrayWithObject:@"visible"] triggerChangeNotificationsForDependentKey:@"visibleThing"], observers of a Foo's "visibleThing.name" would not be notified when the value of the Foo's "visible" property changed. This bug has been fixed in Mac OS 10.5.
Better Interoperability Between KVO and Class Categories Loaded From Bundles
In Mac OS 10.3 and 10.4 there was a bug in which methods added to classes by categories loaded from bundles would not work in the variant of the class that's created by the KVO autonotification isa-swizzling machinery. So, it was possible to add a KVO observer to an object, load a bundle that was supposed to add methods to the class of observed object, and then have those methods not be responded to. This bug has been fixed in Mac OS 10.5.
Support for the Class Type in KVC and KVO
In Mac OS 10.5, KVC now works with the Class type. For example, -valueForKey: will invoke methods like -(Class)key, and -setValue:forKey: will invoke methods like -(void)setKey:(Class)aClass. Both methods work with appropriately named instance variables whose type is Class. KVO's automatic observer notification machinery also handles Class properties properly.
Support for Arbitrary Types in KVC and KVO
In Mac OS 10.5, KVC now work with arbitrary types. For example, if you have a class like this:
typedef struct {
float x, y, z;
} ThreeFloats;
@interface MyClass
- (void)setThreeFloats:(ThreeFloats)threeFloats;
- (ThreeFloats)threeFloats;
@end
[anInstanceOfMyClass valueForKey:@"threeFloats"] will invoke -[MyClass threeFloats] and return the result wrapped in an NSValue. Likewise [anInstanceOfMyClass setValue:anNSValueWrappingThreeFloats forKey:@"threeFloats"] will invoke -[MyClass setThreeFloats:] with the result of sending -getValue: to anNSValueWrappingThreeFloats. Both methods work with appropriately named instance variables of arbitrary type. KVO's automatic observer notification machinery also handles arbitrarily-typed properties properly. This mechanism doesn't take reference counting or garbage collection into account, so take care when using with object-pointer-containing structure types.
Less Exception Throwing for Zero-Length Keys and Paths in KVC
In Mac OS 10.5, the overrides of -valueForKey: and -valueForKeyPath: in the NSDictionary, NSArray, NSSet, and NSUserDefaults classes no longer throw spurious "Range or index out of bounds" exceptions for zero-length keys and key paths.
Support for Debugging of Bad KVO Removal
In Mac OS 10.3 and 10.4, -[NSObject(NSKeyValueObserverRegistration removeObserver:forKeyPath:] would do one of two things when passed an object that was not registered as an observer of the receiver at that moment:
1) Crash
2) Nothing
In Mac OS 10.5 KVO has been update to always throw an exception for bad key-value observer removal. For backward binary compatibility no exception is thrown in case #2, in applications linked against Mac OS 10.4 or earlier.
Support for Debugging of Bad KVO Compliance
The most common mistake that people make when trying to make a class key-value observing (KVO) compliant for a particular key is neglecting to arrange for the sending of appropriate observer notifications when the value for that key changes. This is especially easy to do when you forgo automatic key-value observing in your class. The most readily visible symptom of this mistake is that views that are bound in some way to the keyed property don't update to reflect changed values as you would expect. When you see problems like this review the "Ensuring KVO Compliance" page and the related pages of the Key-Value Observing Programming Guide.
A more serious symptom of bad KVO compliance appears when the key is used in a key path. In Mac OS 10.3 and 10.4 bad KVO-compliance can cause crashes in KVO's own path-observing machinery. Such a crash usually looks something like this:
Program received signal EXC_BAD_ACCESS, Could not access memory.
Reason: KERN_PROTECTION_FAILURE at address: 0x00000006
0x90285e24 in CFRetain ()
(gdb) bt 4
#0 0x90285e24 in CFRetain ()
#1 0x90b8165c in _NSKeyValueObservationInfoCreateByRemoving ()
#2 0x90b81434 in -[NSObject(NSKeyValueObserverRegistration) _removeObserver:forProperty:] ()
#3 0x90b81324 in -[NSObject(NSKeyValueObserverRegistration) removeObserver:forKeyPath:] ()
#4 0x90b81274 in -[NSObject(NSKeyValueObserverRegistration) removeObserver:forKeyPath:] ()
(More stack frames follow...)
(gdb)
In Mac OS 10.5 KVO has been updated to throw an exception when this crash would have happened. Now, for example, executing this code:
- (void)demonstrateExceptionsForBadKVOCompliance {
/* Allocate an object that can be used as a key-value observer.
In a typical Cocoa application using Bindings the observers are usually private
objects created by the key-value bindings machinery, but any class can be used as a
key-value observer as long as it implements the -observeValueForKeyPath:ofObject:change:context:
method properly.
*/
KeyValueObserver *observer = [[KeyValueObserver alloc] init];
/* Allocate an instance of a class that has a to-one relationship to a mutable dictionary, keyed
by "toOneRelationshipWithBadKVOCompliance," but doesn't properly notify key-value observers when
the dictionary itself is replaced by another dictionary. The use of a mutable dictionary as the
related object in this example is arbitrary; key-value coding (KVC) and key-value observing work
with all sorts of objects as long as they are KVC and KVO compliant for the keys in use.
(Dictionaries are automatically KVC and KVO compliant for all keys.)
*/
PlentyOProperties *plentyOProperties = [[PlentyOProperties alloc] init];
/* Start observing an entry in that mutable dictionary. This causes KVO to not only start
observing the dictionary, but also to register itself as an observer of the plentyOProperties
object, so it knows when the dictionary has changed and it therefore needs to stop observing
the old dictionary and start observing the new dictionary.
*/
[plentyOProperties addObserver:observer forKeyPath:@"toOneRelationshipWithBadKVOCompliance.anyOldKey"
options:0 context:NULL];
/* Change the pointed-to dictionary. For this demonstration we made the PlentyOProperties
class KVO noncompliant by overriding +automaticallyNotifiesObserversForKey: to turn off
automatic observer notification and by neglecting to implement a -setToOneRelationshipWithBadKVOCompliance:
method that does manual observer notification using -willChangeValueForKey: and -didChangeValueForKey:.
Because PlentyOProperties is not KVO compliant, the KVO mechanism that's used when observing
key paths doesn't get notified that it should stop observing the old dictionary and start observing
the new one here.
*/
[plentyOProperties setValue:[NSMutableDictionary dictionaryWithObject:@"anyOldValue" forKey:@"anyOldKey"]
forKey:@"toOneRelationshipWithBadKVOCompliance"];
/* Stop observing what we started observing up above. In Panther and Tiger: Crash! Because KVO itself tries
to stop observing the newly-related dictionary, but it never started observing it in the first place.
In Mac OS 10.5: A helpful exception is thrown.
*/
[plentyOProperties removeObserver: observer forKeyPath:@"toOneRelationshipWithBadKVOCompliance.anyOldKey"];
/* Etc, etc. */
}
will cause something like this to appear in the console:
Cannot remove an observer <KeyValueObserver 0x40fdb0> for the key path
"toOneRelationshipWithBadKVOCompliance.anyOldKey" from <PlentyOProperties 0x410a30>,
most likely because the value for the key "toOneRelationshipWithBadKVOCompliance" has
changed without an appropriate KVO notification being sent. Check the KVO-compliance
of the PlentyOProperties class.
If you break on objc_exception_throw in the debugger, you'll probably see two exceptions go by. In addition to the just-described exception, you'll see something like this, first:
Cannot remove an observer <NSKeyValueObservationForwarder 0x3125c0> for the key path "anyOldKey"
from <NSCFDictionary 0x312250> because it is not registered as an observer.
The shorter exception is the result of KVO sensing the symptom of our KVO-compliance problem. The longer exception is the result of KVO catching that exception and throwing one with, hopefully, more descriptive information about the problem.
For the curious: What is NSKeyValueObservationForwarder? It's the private class of objects that KVO uses to implement observing of key paths. Your application shouldn't depend on it. It may go away in future releases of Mac OS X.
Advice for Fixing One Kind of Bad KVO Compliance
One internal Apple application was throwing the kind of exception described above. It looked like this:
2005-09-04 17:42:16.146 MyTestApp[936] *** -[NSAutoreleasePool dealloc]: Exception ignored while
releasing an object in an autorelease pool: Cannot remove an observer <NSArrayDetailBinder 0x3e48890>
for the key path "myBook.indexMarkersInBook" from <MyDocument 0x439930>, most likely because
the value for the key "myBook" has changed without an appropriate KVO notification being sent.
Check the KVO-compliance of the MyDocument class.
Here's what the accessor for the myBook property in the MyDocument class looked like:
- (Book *) myBook {
return [[self myChapter] myBook];
}
That looks pretty simple, and the MyDocument class was KVO-compliant for the myChapter property. So what was the problem? The problem was that KVO can't infer that the value of myBook changes when the value of myChapter changes. Problems like this can be fixed in at least two ways:
• Use a different key path in bindings. In this example binding an NSArrayController to the document's "myChapter.myBook.indexMarkersInBook" instead of it's myBook.indexMarkersInBook" fixed the problem. Because MyDocument is KVO-compliant for myChapter in this example, and the Chapter class is KVO-compliant for myBook, everything works. This kind of solution isn't always desirable though; perhaps the author of the MyDocument class doesn't want to publish the fact that instances of it even have "chapters" to other parts of the program, for design reasons.
• Use +[NSObject(NSKeyValueObservingCustomization) setKeys:triggerChangeNotificationsForDependentKey:] to tell KVO that the value of MyDocument's myBook depends on the value of its myChapter. That way, with the implementation of -myBook above, MyDocument is KVO-compliant for myBook.
Bug Fix in Observing A Key Path Of Self
In Mac OS 10.3 and 10.4 there was a bug in which a debugging feature of KVO made it difficult for an object to observe one of its own values using a multicomponent key path: right before the class' -dealloc method would be invoked, with the object still as an observer of itself, Foundation would log something like "An instance 0x123456 of class MySelfObservingClass is being deallocated while key value observers are still registered with it. Break on _NSKVODeallocateLog to start debugging." Then if the object correctly removed itself as an observer of itself, an exception would be thrown or a crash would occur. This bug has been fixed in Mac OS 10.5. KVO still has a feature in which it logs a warning if an object is being deallocated with observers registered with it, but it now reliably ignores the object itself as an observer.
NSBundle
NSBundle Load Errors, Preflighting, and Architecture Detection
NSBundle now contains methods to allow it to return an NSError if bundle loading fails, to allow preflight testing of bundle loading without actually causing the bundle to be loaded, and to determine the processor architectures that a Mach-O executable contains. The method -loadAndReturnError: behaves like the existing -load method, except that if the optional by-reference error parameter is non-NULL and the load fails, then it will be filled in with a suitable NSError providing a description of the problem suitable for presenting to the user. If the method returns YES--that is, if the bundle was already loaded, or has now been successfully loaded--then the contents of the error parameter will not be touched. All of the errors returned are in the Cocoa error domain, and their codes are described in FoundationErrors.h. The caller does not gain a reference to a returned NSError, and should retain it if it wishes to hold on to it beyond the lifetime of the current autorelease pool. Note that if the error parameter is non-NULL and the load fails, then this method may do additional work over and beyond what -load would do, in order to determine the precise error type.
The current possible error codes are: NSFileNoSuchFileError, if the bundle's executable cannot be located; NSExecutableNotLoadableError, if the bundle's executable exists but is not a loadable executable; NSExecutableArchitectureMismatchError, if the bundle's executable exists but does not provide a version for the processor architecture of the current process; NSExecutableRuntimeMismatchError, if the bundle's executable exists but contains Objective-C runtime information that is not compatible with the current process; NSExecutableLoadError, if the bundle's executable fails to be loadable for some other reason detectable prior to linking, notably the lack of a required library, or the lack of an architecture- and runtime-compatible version of a required library; and NSExecutableLinkError, if the bundle's executable passes all other checks but fails to load due to link errors. Note that NSExecutableNotLoadableError will be returned if the bundle's executable is PEF/CFM but the current process does not support CFM. Other error codes may be added in future releases. More specific information may be shown in the error's debug description, available via -description or the gdb print-object command.
Similar information about load errors can also be obtained without actually loading the bundle, using the method -preflightAndReturnError:. This method returns YES if the bundle is already loaded, or if it appears to be loadable by all tests short of actual linking. The optional by-reference error parameter behaves like the error parameter to -loadAndReturnError:, except that it cannot return NSExecutableLinkError.
The -executableArchitectures method can be used to determine the list of processor architectures that a bundle's executable supports. If the executable is Mach-O, then this function returns an array of NSNumbers of integer type, each of which represents a cpu type for which the executable has a version. NSBundle declares constants for certain well-known types (NSBundleExecutableArchitecturePPC, NSBundleExecutableArchitecturePPC64, NSBundleExecutableArchitectureI386, and NSBundleExecutableArchitectureX86_64) but the values are taken directly from the executable, so other values may occur, and other values may be added in the future. If the executable is not Mach-O, then this method returns nil.
NSBundle Loading vs. CFBundle Loading
Previously it has been recommended that bundles containing Objective-C code or Cocoa Java code should be loaded using NSBundle rather than CFBundle. In Leopard, there are fewer differences between CFBundle and NSBundle loading, and bundles containing Objective-C code may be loaded with either. However, there are still a few remaining differences. First, bundles with an executable type of MH_BUNDLE (that is, loadable bundles rather than frameworks) loaded using CFBundle are loaded privately and with immediate binding, while the same bundles loaded using NSBundle are loaded globally and with lazy binding. Bundles with an executable type of MH_DYLIB (that is, frameworks) are loaded globally and with lazy binding in either case. Second, loading of bundles using NSBundle will cause NSBundleDidLoadNotification notifications to be sent, while loading of the same bundle using CFBundle will not produce these notifications. Third, bundles containing Cocoa Java code should still be loaded using NSBundle.
NSBundle Unloading
In Leopard, NSBundle exposes a - (BOOL)unload method. This method attempts to unload the bundle if it is loaded, and returns YES if the bundle is not loaded at the end of the call, i.e., if it was successfully unloaded or if it was not loaded in the first place. Success or failure in unloading depends on the underlying dynamic loader, usually dyld. (Note that in Leopard, dyld now supports the unloading of MH_DYLIB as well as MH_BUNDLE executables.) Bundles may also be unloaded using CFBundle, but it is recommended that bundles loaded with NSBundle be unloaded with NSBundle and those loaded with CFBundle be unloaded with CFBundle. As usual, it is the responsibility of the client to make sure that there are no dangling pointers to the code that is being unloaded, and in particular that there are no extant instances of classes defined in the bundle. This method exists in previous versions of Mac OS X, but always returns NO on pre-Leopard systems, because unloading of NSBundles is not supported on those systems.
NSFileManager
NSFileManager delegates and instances (Updated since WWDC 2007)
In versions of Mac OS X prior to Leopard, the only supported NSFileManager instance was the instance returned from +[NSFileManager defaultManager] (a singleton instance). Calling [[NSFileManager alloc] init] would return a new object instance of NSFileManager, but this instance might behave strangely in the face of multiple threads.
In Leopard, calling +[NSFileManager defaultManager] still gets you the same singleton instance no matter when or in what thread you call it, but calling [[NSFileManager alloc] init] is now explicitly supported and returns a new instance. In addition, NSFileManager instances can now have delegate objects. The delegate is set in the usual way:
- (void)setDelegate:(id)delegate;
- (id)delegate;
The delegate is not retained in usual operation. In GC, a strong reference is kept to the delegate.
NSFileManager copy/move/link/remove API (Updated since WWDC 2007)
Leopard introduces new API for copying, moving, linking and removing filesystem items.
- (BOOL)copyItemAtPath:(NSString *)srcPath toPath:(NSString *)dstPath error:(NSError **)error;
- (BOOL)moveItemAtPath:(NSString *)srcPath toPath:(NSString *)dstPath error:(NSError **)error;
- (BOOL)linkItemAtPath:(NSString *)srcPath toPath:(NSString *)dstPath error:(NSError **)error;
- (BOOL)removeItemAtPath:(NSString *)path error:(NSError **)error;
which replace the similarly-named methods currently extant in NSFileManager.
Events are passed to the delegate using the following methods defined in a category on NSObject:
- (BOOL)fileManager:(NSFileManager *)fileManager shouldCopyItemAtPath:(NSString *)srcPath toPath:(NSString *)dstPath;
- (BOOL)fileManager:(NSFileManager *)fileManager shouldProceedAfterError:(NSError *)error
copyingItemAtPath:(NSString *)srcPath toPath:(NSString *)dstPath;
- (BOOL)fileManager:(NSFileManager *)fileManager shouldMoveItemAtPath:(NSString *)srcPath toPath:(NSString *)dstPath;
- (BOOL)fileManager:(NSFileManager *)fileManager shouldProceedAfterError:(NSError *)error
movingItemAtPath:(NSString *)srcPath toPath:(NSString *)dstPath;
- (BOOL)fileManager:(NSFileManager *)fileManager shouldLinkItemAtPath:(NSString *)srcPath toPath:(NSString *)dstPath;
- (BOOL)fileManager:(NSFileManager *)fileManager shouldProceedAfterError:(NSError *)error
linkingItemAtPath:(NSString *)srcPath toPath:(NSString *)dstPath;
- (BOOL)fileManager:(NSFileManager *)fileManager shouldRemoveItemAtPath:(NSString *)path;
- (BOOL)fileManager:(NSFileManager *)fileManager shouldProceedAfterError:(NSError *)error removingItemAtPath:(NSString *)path;
Delegates in the "shouldXXXItemAtPath" methods have the opportunity to return "NO" to skip a particular item. Doing so does not trigger an error return at the top-level XXXItemAtPath:toPath:error: method. The default behavior is to act as if these methods return YES.
Delegates in the shouldProceedAfterError:XXXingItemAtPath:toPath: methods have the opportunity to return YES. This will suppress the error return from the top-level XXXItemAtPath:toPath:error:. Delegates in the shouldProceedAfterError: method can take the opportunity to attempt to fix the problem in order to let the operation continue. The default behavior is to act as if these methods return NO.
-[NSFileManager copyPath:toPath:handler:] and ACLs
Mac OS X 10.4 introduced Access Control Lists (ACLs), a sophisticated mechanism for access control on the filesystem. NSFileManager's copyPath:toPath:handler: method does not copy ACLs when copying a filesystem object. But the new Leopard API, copyItemAtPath:toPath:error:, does copy ACLs over.
NSFileManager APIs which return errors (Updated since WWDC 2007)
NSFileManager's error reporting has been improved in Leopard with the addition of a number of new methods which take a by-reference NSError parameter.
The following methods are new in Leopard and are intended as replacements for their non-error-taking counterparts:
- (BOOL)setAttributes:(NSDictionary *)attributes ofItemAtPath:(NSString *)path error:(NSError **)error;
- (BOOL)createSymbolicLinkAtPath:(NSString *)path withDestinationPath:(NSString *)destPath error:(NSError **)error;
- (NSArray *)contentsOfDirectoryAtPath:(NSString *)path error:(NSError **)error;
- (NSArray *)subpathsOfDirectoryAtPath:(NSString *)path error:(NSError **)error;
- (NSDictionary *)attributesOfItemAtPath:(NSString *)path error:(NSError **)error;
- (NSDictionary *)attributesOfFileSystemForPath:(NSString *)path error:(NSError **)error;
- (NSString *)destinationOfSymbolicLinkAtPath:(NSString *)path error:(NSError **)error;
- (BOOL)createDirectoryAtPath:(NSDictionary *)path
withIntermediateDirectories:(BOOL)createIntermediates
attributes:(NSDictionary *)attributes
error:(NSError **)error;
Some methods have not been enhanced; for those methods there is no useful user-presentable error to be generated or the general utility was questionable. One example of a method of this type is -isWritableFileAtPath:. Race windows exist between testing for writability and actually writing; a far better approach is to attempt writing to the file and handling the errors that may occur gracefully.
Grammar Checking
Grammar checking is a new feature associated with the existing spellchecking functionality. Any spellchecking server has the option of also providing grammar checking, by implementing the NSSpellServer delegate method
- (NSRange)spellServer:(NSSpellServer *)sender checkGrammarInString:(NSString *)stringToCheck
language:(NSString *)language details:(NSArray **)details;
The return value is intended to be the range of the next sentence or other grammatical unit that contains sections to be flagged for grammar, since grammar checking generally must be performed sentence by sentence. The details argument optionally returns by reference an array of dictionaries, each one describing a grammatical issue detected in the sentence (since a single sentence may contain more than one problem). In these dictionaries the following keys will be recognized:
NSString *NSGrammarRange;
NSString *NSGrammarUserDescription;
NSString *NSGrammarCorrections;
The value for the NSGrammarRange key should be an NSValue containing an NSRange, a subrange of the sentence range used as the return value, whose location should be an offset from the beginning of the sentence--so, for example, an NSGrammarRange for the first four characters of the overall sentence range should be {0, 4}. The value for the NSGrammarUserDescription key should be an NSString containing descriptive text about that range, to be presented directly to the user; it is intended that the user description should provide enough information to allow the user to correct the problem. A value may also be provided for the NSGrammarCorrections key, consisting of an NSArray of NSStrings representing potential substitutions to correct the problem, but it is expected that this may not be available in all cases. It is recommended that NSGrammarUserDescription be supplied in all cases; in any event, either NSGrammarUserDescription or NSGrammarCorrections must be supplied in order for something to be presented to the user. If NSGrammarRange is not present, it will be assumed to be equal to the overall sentence range. Additional keys may be added in future releases.
Immutable collections and copy behavior
In Mac OS X 10.4 and earlier, the default copy behavior of custom subclasses of NSArray, NSSet, and NSDictionary (the immutable variants) was to deep copy the contents of the collection. This meant that sending copy or copyWithZone: to any of these collections copied each element in the collection. This required that the contents of the collection conformed to the NSCopying protocol.
For applications linked on Tiger or earlier when running on Leopard, these collections will continue to perform a deep copy. For applications linked on Leopard or later, these collections will perform a shallow copy (and be more consistent with their mutable and CF equivalents).
If on Tiger you were using code like this:
NSArray *deepCopyOfArray = [someArray copyWithZone:nil]; // deep copy on Tiger
and relying on the deep copy behavior to get a deep copy, you would use the following code on both Tiger and Leopard:
NSArray *deepCopyOfArray = [[NSArray alloc] initWithArray:someArray copyItems:YES]; // explicitly deep copy
as a drop-in replacement (as the ownership rules are the same).
Collection construction methods and NS_REQUIRES_NIL_TERMINATION
There are six collection creation methods in Foundation which require nil termination to function properly. They are:
+[NSArray arrayWithObjects:]
-[NSArray initWithObject:]
+[NSDictionary dictionaryWithObjectsAndKeys:]
-[NSDictionary initWithObjectsAndKeys:]
+[NSSet setWithObjects:]
-[NSSet initWithObjects:]
These methods have been decorated with the NS_REQUIRES_NIL_TERMINATION macro, which adds an additional check to invocations of those methods to make sure the nil has been included at the end of the argument list. This warning is only available when compiling with -Wformat.
Order of values in hashing-based collections
The CoreFoundation and Foundation framework-provided implementations of hashing-based collections such as dictionaries have changed how they store elements, so elements may be retrieved in a different order than in previous releases. The order of elements in hashing-based collections is undefined and can change at any time, so developers must never rely on the order that elements are enumerated, or returned from a function like CFDictionaryGetKeysAndValues(). This is true even for cases where a developer may be trying to manipulate the hash codes of the objects in order to achieve some particular ordering.
NSSet
NSSet and NSMutableSet now have predicate-based methods for filtering. These are similar to the existing filtering methods on NSArray/NSMutableArray.
NSSet has the following new methods, which should be self-explanatory from the name:
- (NSSet *)setByAddingObject:(id)anObject;
- (NSSet *)setByAddingObjectsFromSet:(NSSet *)other;
- (NSSet *)setByAddingObjectsFromArray:(NSArray *)other;
NSIndexSet
Has the following new method for returning the number of indexes in the specified range:
- (NSUInteger)countOfIndexesInRange:(NSRange)range;
Advice for Invokers of -[NSUndoManager removeAllActions]
-[NSUndoManager removeAllActions] resets the "isUndoing" and "isRedoing" state of the undo manager. If your application invokes it during an undo or redo operation, the undo manager object will be left in an inconsistent state, causing hard-to-debug errors or crashes. Design your application so that this doesn't happen. There's no known good reason to send an undo manager a -removeAllActions message when it's in the middle of an undo operation. If necessary, you can use -isUndoing and -isRedoing to protect against doing such a thing.
NSGeometry.h and converting between CGRect and NSRect
In 32-bit code, CGRects and NSRects are distinct types. In order to aid in converting between CGRects and NSRects, NSGeometry.h defines 6 new functions:
NSRectFromCGRect
NSRectToCGRect
NSPointFromCGPoint
NSPointToCGPoint
NSSizeFromCGSize
NSSizeToCGSize
which do the pointer conversion between NSRects and CGRects.
-[NSData getBytes:range:] and NSRangeExceptions
-[NSData getBytes:range:] does not properly raise an NSRangeException for ranges which start inside the NSData, but end outside the NSData. Instead, it fills the provided buffer up to the end of the NSData. This will continue to be the case for Mac OS X 10.5 Leopard, but a future release of the operating system will start throwing range exceptions for applications linked later than Mac OS X 10.5.
NSSearchPathForDirectoriesInDomains and Developer directories
In Mac OS X 10.5 "Leopard" it is possible to have multiple versions of the Developer Tools software (Xcode, Interface Builder, etc.) installed on your system at one time. It is also possible to have them installed in a location that is not rooted at the "/Developer" path in the filesystem. As a result, the directories returned from NSSearchPathForDirectoriesInDomains by passing the NSDeveloperApplicationDirectory or NSDeveloperDirectory constants may not return something which corresponds to the actual location of the Developer Tools that are installed.
+[NSInputStream inputStreamWithData:] (New since WWDC 2007)
In Mac OS X 10.4 "Tiger", the NSData passed to +[NSInputStream inputStreamWithData:] would not be retained by the created stream. In Mac OS X 10.5 "Leopard" the NSData is now retained by the stream.
NSNetServices
It is an error to call -[NSNetService publish] on an NSNetService initialized with -[NSNetService initWithDomain:type:name:]. For applications linked on Mac OS X 10.5 "Leopard" or later, doing so will cause an exception to be thrown.
Applications which have been linked on Mac OS X 10.5 Leopard or later will raise an exception when passing nil to +[NSNetService dictionaryFromTXTRecordData:] or +[NSNetService dataFromTXTRecordDictionary:].
NSNetServices (New since WWDC 2007)
NSNetServices' behavior in handling timeouts is slightly different than what is provided by CFNetServices. In Leopard, CFNetServices will unconditionally report a timeout error when the timeout chosen in CFNetServiceResolveWithTimeout() is hit, regardless of whether or not any addresses were actually resolved.
NSNetServices will only report an NSNetServicesTimeoutError to the delegate's netService:didNotResolve: callback if no addresses were resolved by a call to -[NSNetService resolve] or -[NSNetService resolveWithTimeout:]. If addresses have been resolved, when the timeout is reached the delegate will be notified on its -netServiceDidStop: delegate method.
NSDateFormatter
NSDateFormatter has new methods:
- (NSArray *)longEraSymbols;
- (void)setLongEraSymbols:(NSArray *)array;
- (NSArray *)veryShortMonthSymbols;
- (void)setVeryShortMonthSymbols:(NSArray *)array;
- (NSArray *)standaloneMonthSymbols;
- (void)setStandaloneMonthSymbols:(NSArray *)array;
- (NSArray *)shortStandaloneMonthSymbols;
- (void)setShortStandaloneMonthSymbols:(NSArray *)array;
- (NSArray *)veryShortStandaloneMonthSymbols;
- (void)setVeryShortStandaloneMonthSymbols:(NSArray *)array;
- (NSArray *)veryShortWeekdaySymbols;
- (void)setVeryShortWeekdaySymbols:(NSArray *)array;
- (NSArray *)standaloneWeekdaySymbols;
- (void)setStandaloneWeekdaySymbols:(NSArray *)array;
- (NSArray *)shortStandaloneWeekdaySymbols;
- (void)setShortStandaloneWeekdaySymbols:(NSArray *)array;
- (NSArray *)veryShortStandaloneWeekdaySymbols;
- (void)setVeryShortStandaloneWeekdaySymbols:(NSArray *)array;
- (NSArray *)quarterSymbols;
- (void)setQuarterSymbols:(NSArray *)array;
- (NSArray *)shortQuarterSymbols;
- (void)setShortQuarterSymbols:(NSArray *)array;
- (NSArray *)standaloneQuarterSymbols;
- (void)setStandaloneQuarterSymbols:(NSArray *)array;
- (NSArray *)shortStandaloneQuarterSymbols;
- (void)setShortStandaloneQuarterSymbols:(NSArray *)array;
These set and return:
- "long" era names, for example "Anno Domini" instead of "AD"
- "very short" names for months and weekdays; for example, "F" instead of "Friday"
- "standalone" names for months and weekdays; for some locales/languages, a month name displayed in isolation needs to be written differently than a month name within a displayed date
- names of quarters; for example, "Q2" for a short quarter name
There is also two new methods to set and get the switchover date to be used for the Gregorian calendar:
- (NSDate *)gregorianStartDate;
- (void)setGregorianStartDate:(NSDate *)date;
This is used to specify the start date for the Gregorian calendar switch from the Julian calendar. Different locales switched at different times. Normally you should just accept the locale's default date for the switch.
New NSNumberFormatter API
There is some new API in NSNumberFormatter in 10.5:
- (NSString *)currencyGroupingSeparator;
- (void)setCurrencyGroupingSeparator:(NSString *)string;
This is the grouping separator for currency values, which could be different than the usual grouping separator in some locales.
- (BOOL)isLenient;
- (void)setLenient:(BOOL)b;
May enable greater leniency in parsing strings into numbers in some operating system releases when true.
- (BOOL)usesSignificantDigits; // whether to use the next two or not
- (void)setUsesSignificantDigits:(BOOL)b;
- (NSUInteger)minimumSignificantDigits;
- (void)setMinimumSignificantDigits:(NSUInteger)number;
- (NSUInteger)maximumSignificantDigits;
- (void)setMaximumSignificantDigits:(NSUInteger)number;
These are useful for scientific notation formatting.
- (BOOL)isPartialStringValidationEnabled;
- (void)setPartialStringValidationEnabled:(BOOL)b;
These methods are used to enable partial string validation, which by default NSNumberFormatters do not do (and have never done). However, the implementation in 10.5 doesn't do anything with this property.
Default Formatter behavior
When a new NSNumberFormatter or NSDateFormatter is created in apps linked on 10.5 and later, the default behavior setting for that formatter is the "10_4" behavior. It is still a good idea to set the desired behavior of a formatter explicitly just after creating it (when doing so in code) to make the intent clear.
New NSMachPort API
You can now specify some deallocation options to NSMachPort when you create one with a Mach port:
enum {
NSMachPortDeallocateNone = 0,
NSMachPortDeallocateSendRight = (1 << 0),
NSMachPortDeallocateReceiveRight = (1 << 1)
};
+ (NSPort *)portWithMachPort:(uint32_t)machPort options:(NSUInteger)f;
- (id)initWithMachPort:(uint32_t)machPort options:(NSUInteger)f;
These options let you specify whether the NSMachPort should effectively take ownership of a send right reference and/or a receive right references for the port when you create the port object. When the port object is deallocated, it will deallocate the specified rights. You should of course understand what all this means for a Mach port, and understand what type of references you may have, before using these new options. Plus, they come with a major caveat: your call must be the first the create a port object with that Mach port, or your options will be ignored, and there is no good way to tell if your options were ignored.
New NSCalendar APIs
NSCalendar has the following new API to compute the time range for a given unit surrounding a given moment:
- (BOOL)rangeOfUnit:(NSCalendarUnit)unit startDate:(NSDate **)datep
interval:(NSTimeInterval *)tip forDate:(NSDate *)date;
The second and third parameters are out parameters.
For example, to find the starting moment and length of the week around the current moment, for a given calendar, you might do:
NSDate *start;
NSTimeInterval length;
Boolean ret = [calendar rangeOfUnit:NSCalendarUnitWeek startDate:&start interval:&length forDate:[NSDate date]];
if (ret) { ...
Keep in mind that the time at (start + length) will usually be in the next occurrence of the unit, not in the current one, so you may need to fudge the arithmetic slightly to work with the end date of the unit. Also, some values have no defined end point (like usually, the current era), so an arbitrary point in the future is chosen.
+ (id)autoupdatingCurrentCalendar;
Returns a special NSCalendar instance which always reflects the current state of the current user's calendar settings. The existing currentCalendar method will continue to return the snapshot that was current at the time it's called.
Chinese calendar still not available
Although there is a constant for it, the Chinese calendar is not available from NSCalendar or related APIs yet. In 10.5, trying to create a NSCalendar with that constant will return nil (fail).
Calendrical computations
Some calendrical computations have been corrected in 10.5. In particular -[NSCalendar rangeOfUnit:inUnit:forDate:] has changed to a more literalist interpretation of "range" for applications linked on or after 10.5.
Use of NSCalendarDate discouraged
Use of the NSCalendarDate class is again discouraged in 10.5, but it is not deprecated yet. It may be in the next major OS release after 10.5. NSDateFormatter should be used for date formatting, and NSCalendar should be used for calendrical calculations. Where formatting differs between NSCalendarDate and NSDateFormatter (10.4-style) differ, the NSDateFormatter result will be considered to be the correct result (absent a bug being exercised). Where NSCalendar and NSCalendarDate calendrical calculations differ and the NSCalendar result is reasonable, we define its value to be the correct value. Developers should abandon hope for NSCalendarDate bug fixes.
New NSTimeZone API
- (NSTimeInterval)daylightSavingTimeOffsetForDate:(NSDate *)aDate;
- (NSDate *)nextDaylightSavingTimeTransitionAfterDate:(NSDate *)aDate;
The first method returns the daylight saving time offset from GMT at the given moment, or 0.0 if there is no data for that time. The second method returns the next moment after the given time at which a daylight saving time occurs, or nil if there is no data after that time.
- (NSTimeInterval)daylightSavingTimeOffset;
- (NSDate *)nextDaylightSavingTimeTransition;
These two are convenience methods for the two above, with the date taken to be the current time.
enum {
NSTimeZoneNameStyleStandard,
NSTimeZoneNameStyleShortStandard,
NSTimeZoneNameStyleDaylightSaving,
NSTimeZoneNameStyleShortDaylightSaving
};
typedef NSInteger NSTimeZoneNameStyle;
- (NSString *)localizedName:(NSTimeZoneNameStyle)style locale:(NSLocale *)locale;
This API returns the localized display string for the given time zone and locale, in the given style. If the data does not exist for that combination of parameters, returns nil.
NSTimeZone has the following new notification name API:
NSString * const NSSystemTimeZoneDidChangeNotification;
This notification is posted when the system time zone changes. The object of the notification is the previous system time zone object. This notification carries no user info. Keep in mind that there is no order in how notifications are delivered to observers, and frameworks or other parts of your code may be observing this notification as well to take their own actions, which may not have occurred by the time you receive the notification.
New NSPortNameServer API
- (NSPort *)servicePortWithName:(NSString *)name;
This method can be used to look up an auto-launched service port. This method is used by the service itself (if anybody) at launch time to check in with launchd.
New NSConnection API
+ (id)serviceConnectionWithName:(NSString *)name rootObject:(id)root usingNameServer:(NSPortNameServer *)server;
+ (id)serviceConnectionWithName:(NSString *)name rootObject:(id)root;
These new methods are used to create a new NSConnection by an autolaunched service process, for the service(s) they are providing. The connection is configured with the given root object. -registerName: should not be used with such an NSConnection, and -setRootObject: is unnecessary. This also checks the service in with launchd.
New NSRunLoop APIs
+ (NSRunLoop *)mainRunLoop;
Returns the run loop object of the main thread. At the present time, this method is of dubious value, since some NSRunLoop functionality is not thread-safe (all "perform" functionality in NSRunLoop.h, for example).
NSString * const NSRunLoopCommonModes;
This is a new constant for NSRunLoop that corresponds to CFRunLoop's kCFRunLoopCommonModes constant. Refer to CFRunLoop's documentation for more information.
NSURLConnection (Updated since WWDC 2007)
NSURLConnection now supports scheduling on individual run loops. If the delegate wishes to receive the delegation messages on a thread other than the current thread, they can create the connection using -initWithRequest:delegate:startImmediately: specifying NO for the last argument (startImmediately). They can then choose where to schedule the delegation methods using -scheduleInRunLoop:forMode: and -unscheduleFromRunLoop:forMode:. Once the connection has been scheduled, it can be started using -start. Once a connection has been started, its scheduling cannot be changed.
New constants NSURLRequestReloadIgnoringLocalAndRemoteCacheData and NSURLRequestReloadRevalidatingCacheData have been added to the list of caching policies on NSURLRequest. However, they are not implemented; they are simply placeholders at this time.
The delegate method connection:willSendRequest:redirectResponse: has changed behavior in 10.5. First, prior to 10.5, its behavior was inconsistent if nil was returned; sometimes a nil return would cancel the connection, but sometimes, a nil return would cause the connection to use the given request unmodified. In 10.5., a nil return will always cancel the connection; this matches the documented behavior. Second, prior to 10.5, NSURLConnection would often modify the incoming NSURLRequest prior to transmission without notifying the delegate. In 10.5, the delegate is always notified via the delegation method connection:willSendRequest:redirectResponse:. This means that the delegate will often receive a connection:willSendRequest:redirectResponse: message before the connection has even properly begun, prior to transmitting the request to the remote server. This may be surprising to older code, written assuming connection:willSendRequest:redirectResponse: will only be called if a redirection has occurred. To fix such code, simply check whether the redirectResponse is nil. If it is, no redirection has occurred and NSURLConnection is simply informing the delegate that it modified the request prior to transmission. If the delegate does not want to intervene, it should return the request unmodified. Here's an example:
- (NSURLRequest *)connection:(NSURLConnection *)connection
willSendRequest:(NSURLRequest *)request
redirectResponse:(NSURLResponse *)redirectResponse {
if (redirectResponse) {
// Handle the redirection; older code goes here
...
} else {
// Just being shown the final request prior to transmission
return request;
}
}
New NSLocale APIs
+ (NSArray *)commonISOCurrencyCodes;
Returns an array of CFStrings that represents ISO currency codes for currencies in common use, which is a more generally useful set than that returned by +ISOCurrencyCodes.
+ (NSArray *)preferredLanguages;
Returns an array of NSStrings giving the user's preferred language identifiers, canonicalized, in order.
NSTimeZone has the following new notification name API:
NSString * const NSCurrentLocaleDidChangeNotification;
This is a local notification posted when the user changes locale information in the System Preferences panel. Keep in mind that there is no order in how notifications are delivered to observers, and frameworks or other parts of your code may be observing this notification as well to take their own actions, which may not have occurred by the time you receive the notification. There is no object or user info for this notification.
+ (id)autoupdatingCurrentLocale;
Returns a special NSLocale instance which always reflects the current state of the current user's locale settings. This is useful in assigning to NSDateFormatter, for instance. This autoupdating instance will appear to have changed by the time NSCurrentLocaleDidChangeNotification is sent out.
The existing currentLocale method will continue to return the snapshot that was current at the time it's called.
Methods which take locale arguments
Some methods in Foundation used to take an NSDictionary * as a locale: (or Locale:) argument. The types of these arguments on those methods have been changed to id. For example:
- (NSString *)descriptionWithLocale:(NSDictionary *)locale; // previously
- (NSString *)descriptionWithLocale:(id)locale; // now
Such methods that are implemented in Foundation now accept either an old-style NSDictionary locale dictionary, or an NSLocale * locale. Use of NSLocales in new code is encouraged.
Note that some existing methods in Cocoa are typed to take an NSLocale * locale argument, and these still only accept an NSLocale object.
Methods which take locale dictionaries which are not in Foundation, CoreData, or AppKit (Cocoa itself) have not necessarily been improved with this capability. This includes overrides of these methods in subclasses which are not in Cocoa.
NSDate's -descriptionWithLocale: accepts either, but ignores locale dictionary arguments in 10.5 and later, giving results based on the current user's locale for non-nil locale dictionaries. NSLocale objects as the argument are honored.
Finally note that the NSCalendarDate class still only takes the old-style locale dictionary style locale parameters for its methods which take locales.
Avoid NSMessagePort
There's little reason to use NSMessagePort rather than NSMachPort or NSSocketPort. There's no particular performance or functionality advantage. We recommend avoiding it. It may be deprecated in the next major OS release after 10.5.
Avoid 'long double' and '_Complex' types
We strongly recommend avoiding all use of the "long double" type and the various C99 "_Complex" types other than -- at most -- purely local computational usage. In particular, we recommend not using it for parameter types; not using it for return values; not using or passing pointers to long double or _Complex types; not using arrays of long doubles or _Complex types or arrays of pointers to long doubles or _Complex types as parameters; not embedding long doubles or _Complex types or pointers to long doubles or _Complex types inside structures which are passed as parameters or returned as return values, nor using pointers to such structures; not using long doubles or _Complex types as object instance variable types; and so on. Do not mix Objective C method calls or variables with any long double or _Complex type usage; in other words, and do not attempt to use long doubles or _Complex types with any Cocoa API. You may notice that Cocoa does not offer any "long double" or "_Complex" type APIs (such as in NSNumber) -- we are avoiding them too.
Part of the issue is that the compiler emits "d" (double) as the type encoding string for @encode(long double), so there is no way to distinguish between the two, and this affects everything which uses Objective C type encoding strings, including key-value coding, forwarding and archiving. If the compiler were ever to fix that now, an app using long double will have binary compatibility problems.
Similarly for the _Complex types, the compiler emits "" (an empty string) for @encode(_Complex {float,double,long double}). Thus these types are completely invisible in method parameters and structure encodings and so on. This causes no end of havoc.
NSMethodSignature, NSInvocation
NSMethodSignature and NSInvocation were rewritten in 10.5. This probably means that there are some things behave differently on 10.5 than they did on 10.4. In particular, there were some bugs fixed, but there may be other subtle changes, undocumented behaviors that you may have been relying on. If you want your app to run well on 10.4 and 10.5, be sure to test on both.
NSInvocation notes on setting and retention of arguments and return values (New since WWDC 2007)
In 10.5, NSInvocation does not retain arguments or return values, unless -retainArguments is called on it. The primary purpose of -retainArguments is to cause the receiving invocation to copy or hold onto certain types of arguments as long as the invocation survives. You would do this if you are saving invocations for later use, or any use on another thread. For example, you would generally want to use this even if synchronously waiting on one thread for an invocation to finish being invoked on another, since the autorelease pools and garbage collector on the other thread are cleaning up objects asynchronously with the waiting thread.
Unfortunately, there is too much ambiguity and historical compatibility in the Objective C language and libraries for NSInvocation to "get this right" all the time for everybody. For example, for some methods, you may want a pointer return value preserved and returned unchanged, and for others, you might want the pointed-to items to be copied shallowly, or at other times deeply, in order to preserve the data being pointed to. In different contexts, you may even want different behaviors from NSInvocation for the same method being invoked. So NSInvocation implements some generic generally useful behaviors. Some of these behaviors may vary from those on 10.4 and earlier, which were a little more ad hoc.
In 10.5, the candidate types for retention are Objective C object [pointer] types, fixed-length arrays, and C strings. Note that there is an inherent ambiguity in the type "char *", which can variously mean, in Objective C, "pointer to single char", "pointer to array of char of some known length", and "pointer to null-terminated array of char". The Objective C compiler and runtime have historically chosen to interpret "char *" (and variations) as a C string (null-terminated array) pointer, and this tradition continues. You cannot use the other two interpretations with anything that uses the runtime type metadata, such as forwarding (NSInvocations) or key-value coding.
For Objective C object [pointer] types, like "NSArray *", the parameter and return objects are retained when -retainArguments has been invoked. For fixed-length arrays not embedded in a struct, the array is copied, and the pointer to the copy becomes the new argument or return value. For C strings, the C string is copied, and the pointer to the copy becomes the new argument or return value. NSInvocation also, recursively, retains (or copies) the Objective C object and C string types within C struct and C array arguments and return values (fixed-length arrays embedded within a struct are part of the struct).
Other pointer uses are not candidates for retention. For example, if a method takes an "int *" argument, NSInvocation takes no action (even when -retainArguments has been called) to copy/preserve the int which that pointer is pointing to. If you manually set that argument (-setArgument:atIndex:), you set the pointer only, not [also] the value being pointed to (and of course, since the first argument to -setArgument:atIndex: is a pointer to the value to be set, it should be a pointer to the pointer-to-int to be set, not the pointer-to-int itself). This non-copying behavior is generally desireable, since you usually don't want NSInvocation to attempt to copy a FILE * or a C++ object (which, as far as the Objective C runtime is concerned, is just a pointer to a struct, and no copy constructor would be invoked) parameter or return value.
Arithmetic types are naturally preserved/copied due to their simple nature, when set or captured as part of forwarding or NSInvocation invocation. Structs passed by value are also preserved/copied when -retainArguments has been invoked.
Note that for an invocation object that has been told to -retainArguments, which has arguments set on it multiple times, or is invoked multiple times, accumulates those retainable arguments and return values, and holds them for the lifetime of the invocation.
For a somewhat higher degree of safety/compatibility, for applications linked on or before 10.4, NSInvocations automatically retain return values after -invoke.
New NSMethodSignature API
+ (NSMethodSignature *)signatureWithObjCTypes:(const char *)types;
This method, available since Mac OS X 10.0, has been exposed. The method creates an NSMethodSignature for the given Objective C method type string. It is entirely the caller's responsibility to pass in type strings which are either from the current runtime data or match the style of type string in use by the runtime that the application is running on. Only type encoding strings of the style of the runtime that the application is running against are supported. If you hard-code method type strings into your framework or application and try to use this method, you may be unpleasantly surprised by any changes in type encoding strings. In exposing this method there is no commitment to binary compatibily supporting any "old-style" type encoding strings after such changes occur.
New NSObject class methods for resolving methods at runtime
Objective-C now gives a class the opportunity to dynamically resolve method implementations at runtime. A class can override +resolveInstanceMethod: and use class_addMethod() to add a method implementation to the class. +resolveClassMethod: is also provided for dynamically resolving class methods. These methods are invoked before the forwarding machinery is invoked, when an object does not implement a method.
Both methods return a BOOL used to indicate whether the selector in question was resolved. If the method returns NO, the Objective-C runtime will pass control to the method forwarding mechanism. If it is resolved, the method will be invoked. Once resolved, all future invocations will directly execute the methods in the same fashion that any other method is executed. Generally you should invoke super's implementation of this method first to give the super class a chance to resolve the method itself. If that returns YES, you shouldn't need to do anything yourself, just return the YES back to your caller. The NSObject class implements these methods with a default implementation that returns NO today, though you should still invoke it even if you're just directly subclassing NSObject.
New forwarding fast path
When the forwarding mechanism is invoked (that is, when an object does not respond to a message sent to it), the forwarding mechanism in 10.5 first attempts to send this message to the original receiver object of the message:
- (id)forwardingTargetForSelector:(SEL)sel;
If the object implements (or inherits) this method, and returns a non-nil and non-self result, that returned object is used as the new receiver object and the message dispatch resumes to that new object. (Obviously if 'self' were allowed to be returned from the method, the code would just fall into an infinite loop.) Thus this method gives an object a chance to redirect an unknown message sent to it before the much more expensive forwardInvocation: machinery takes over. This is useful in basic proxying situations and can be an order of magnitude faster than regular forwarding. It is not useful where the goal of the forwarding is to capture the NSInvocation, or manipulate the arguments or return value during the forwarding.
Non-root classes which implement this method should invoke super's implementation of this method if the class decides that it has nothing to return for the given selector, and return super's result.
Old forward:: Objective C method
The Objective C runtime no longer attempts to invoke the -forward:: method on an object when an object does not respond to a message which is sent to it. Cocoa replaces the runtime forwarding mechanism entirely with its own version in 10.5, which propagates the well-known methodSignatureForSelector: and forwardInvocation: methods to objects so they can forward methods.
Changes to NSZombie debug mechanism
NSZombieEnabled now works for general CFType objects, including toll-free bridged ones. If NSZombieEnabled is set to "YES", then the CFZombieLevel environment variable is ignored.
In 10.5, when zombies are enabled, a message something like this is logged and a debugger trap is invoked:
2006-09-09 19:24:31.122 MyTestApp[402] *** -[NSURLConnection release]: message sent to deallocated instance 0x2141e30
Thus you do not have to set breakpoints on lots of potential methods and/or re-run the application (assuming you ran it under the debugger the first time) and try to reproduce the problem in order to find out where it is happening.
NSPropertyListSerialization (Updated since WWDC 2007)
A previous release note in the Leopard Foundation release notes said that a leak has been fixed in the two NSPropertyListSerialization methods that return an NSString * error description by reference. This fix has been reverted, and will never be done. As stated in the documentation for those methods, and as was true in 10.4 and earlier, it is the client's responsibility to release that string (if either method returns nil) in 10.5 and beyond as well.
NSTimeZone names cannot be nil
The NSTimeZone methods:
- (id)initWithName:(NSString *)tzName;
- (id)initWithName:(NSString *)tzName data:(NSData *)aData;
and indirectly, any class methods which call them, now insist on the tzName and aData parameters not being nil. In prior OS releases this would have caused a crash. In 10.5 and later, this is now more explicitly an invalid argument exception.
NSDate method behavior changes (Updated since WWDC 2007)
NSDate methods which take an NSDate * argument have historically had undefined/arbitrary behavior when passed nil. In particular they would tend to use an unpredictable floating point value for nil's timeIntervalSinceReferenceDate. Now they behave as if nil's time interval is NaN.
When comparing against nil or an NSDate with NaN as its time interval, NSOrderedSame is consistently returned. Previously the return value was a little arbitrary. However, nil is not equal to any date object, and only a NaN-holding date can be equal to a NaN-holding date.
The -earlierDate: and -laterDate: methods tended to return their arguments when passed nil, a NaN-holding NSDate, or a date which was equal to the receiver, but not in all cases. In 10.5 and later, these methods return the receiver object for these ambiguous cases.
NSString
There are several new NSStringEncoding values:
NSUTF16StringEncoding
NSUTF16BigEndianStringEncoding
NSUTF16LittleEndianStringEncoding
NSUTF32StringEncoding
NSUTF32BigEndianStringEncoding
NSUTF32LittleEndianStringEncoding
NSUTF16StringEncoding is simply an alias for the existing NSUnicodeStringEncoding.
When creating an NSString from bytes, NSUTF16BigEndianStringEncoding and NSUTF16LittleEndianStringEncoding enable you to specify the endianness of a UTF-16 stream of bytes explicitly, without consulting a BOM character. Note that as a consequence, if there is a BOM character in the stream, it will be interpreted as an actual character and included in the created NSString.
The NSUTF32StringEncoding, NSUTF32BigEndianStringEncoding, and NSUTF32LittleEndianStringEncoding values are similar to their UTF16 counterparts, except they work with 4-byte Unicode characters.
Although these encoding names are being introduced in Leopard headers, the actual values do work back to Tiger.
NSProprietaryStringEncoding has been deprecated, since it has not actually been used at all since 10.0.
A clarification: The maxLength argument to getCString:maxLength:encoding: needs to accomodate both the returned bytes and the additional NULL byte. In this regard this method behaves differently than the deprecated getCString:maxLength: method.
The previous documentation and comment in NSString.h were both wrong in this regard. Rather than changing the implementation and introducing compatibility concerns, we are updating the documentation.
NS and CFString now check most immutable creation requests against a set of "popular" strings, and in some cases will return a pre-created string. What this means is that it's now more likely that two distinct creation requests for an NS or CFString with the same contents might return the same exact string; don't count on pointer inequality in those cases. It's also possible that in those cases any unbalanced retain/release requests will go unnoticed.
Note that the set of "popular" strings will change between releases, so do not make any assumptions about what strings are shared based on observations on Leopard. In fact, the set has been updated significantly between the WWDC 2007 seed and final release of Leopard.
The following new method enables convenient way grow a range to include all composed character sequences it overlaps. This can be used with substringWithRange:, etc, to get back "proper" substrings that don't break composed character sequences:
- (NSRange)rangeOfComposedCharacterSequencesForRange:(NSRange)range;
For convenience, a zero-length range is treated like a 1-length range, except when the range is at the end of the string (so, {length,0}), in which case it will return {length,0}. So for the string "abc", {0,0} will return {0,1}, and {3,0} will return {3,0}.
The following method enables incremental encoding conversion NSStrings. Pass the desired range to be converted, and get back the remaining range. This method returns YES if it was able to convert any characters, even if it had to stop at an unconvertible character. (This would mean the next conversion would return NO.)
enum {
NSStringEncodingConversionAllowLossy = 1,
NSStringEncodingConversionExternalRepresentation = 2
};
typedef NSUInteger NSStringEncodingConversionOptions;
- (BOOL)getBytes:(void *)buffer
maxLength:(NSUInteger)maxBufferCount
usedLength:(NSUInteger *)usedBufferCount
encoding:(NSStringEncoding)encoding
options:(NSStringEncodingConversionOptions)options
range:(NSRange)range
remainingRange:(NSRangePointer)leftover;
Although this method has been publicized in 10.5, it does exist back to 10.4.
The following method returns an array of strings resulting from dividing the receiver like componentsSeparatedByString: does, but at boundaries identified by any of the characters in the argument.
- (NSString *)componentsSeparatedByCharactersInSet:(NSCharacterSet *)set;
The following methods are for various convenient replacements in NSString. They already exist in NSMutableString.
- (NSString *)stringByReplacingOccurrencesOfString:(NSString *)target
withString:(NSString *)replacement
options:(NSUInteger)optionMask
range:(NSRange)searchRange;
- (NSString *)stringByReplacingOccurrencesOfString:(NSString *)target
withString:(NSString *)replacement;
- (NSString *)stringByReplacingCharactersInRange:(NSRange)range withString:(NSString *)replacement;
longLongValue parses a long long out of the string, using "loose" rules much like the existing intValue and floatValue methods. Will skip initial white characters (whitespaceSet) and ignore characters after the number. Use NSScanner for more formalized parsing:
- (long long)longLongValue;
boolValue will parse a boolean. Skips initial space characters (whitespaceSet), or optional -/+ sign followed by zeroes. Returns YES on encountering one of "Y", "y", "T", "t", or a digit 1-9. It ignores any trailing characters.
- (BOOL)boolValue;
The following new typedef is used in NSString APIs to indicate arguments which take a combination of compare options (such as NSCaseInsensitiveSearch, NSBackwardsSearch, etc):
typedef NSUInteger NSStringCompareOptions;
NSString now supports the formatting characters %L, %a, %A, %F, %z, %t, and %j when formatting strings. %n, which never worked properly (it always returned value of zero), is now disabled for applications linked on Leopard. %n in the format string is still processed as before, but the corresponding argument is no longer written to.
The locale argument for -compare:options:range:locale: now accepts NSLocale. When nil, it performs non-localized comparison. For backward compatibility, it treats non-NSLocale objects as if it is +[NSLocale currentLocale].
There is a new searching method taking a locale argument. When nil, it performs non-localized search.
- (NSRange)rangeOfString:(NSString *)aString options:(NSUInteger)mask range:(NSRange)searchRange locale:(NSLocale *)locale;
The following new constants are introduced for the search/compare option flag.
Ignore diacritics (o-umlaut == o):
NSDiacriticInsensitiveSearch = 128
Ignore width differences ('a' == UFF41):
NSWidthInsensitiveSearch = 256
Force comparisons to return either kCFCompareLessThan or kCFCompareGreaterThan if the strings are equivalent but not strictly equal, for stability when sorting (e.g. "aaa" > "AAA" with kCFCompareCaseInsensitive specified):
NSForcedOrderingSearch = 512
There is now a method "folding" characters:
- (NSString *)stringByFoldingWithOptions:(NSUInteger)options locale:(NSLocale *)theLocale;
Folding string returns a canonical representative of the class of strings that are equivalent with respect to the options passed. For example, if you fold two strings that differ only with respect to case, you will get the same string back. This is useful for making dictionaries keyed by case-insensitive strings or similar.
NSString plain text file encoding support
The methods writeToFile:atomically:encoding:error:, writeToURL:atomically:encoding:error:, the deprecated writeToFile:atomically:, and writeToURL:atomically: now store the specified encoding with the file, in an extended attribute. The methods initWithContentsOfFile:usedEncoding:error:, initWithContentsOfURL:usedEncoding:error:, and their stringWith... counterparts use this information to open the file using the right encoding.
The extended attribute is stored under the name "com.apple.TextEncoding". The value contains the IANA name for the encoding and the CFStringEncoding value for the encoding, separated by a semicolon. The CFStringEncoding value is written as an ASCII string containing an unsigned 32-bit decimal integer. The string is not terminated by a NUL character.
One or both of these values may be missing. If the IANA name is missing but the CFStringEncoding value is present, the semicolon should still be there. Foundation consults the encoding number first, then the IANA name.
Examples of the value written to extended attributes include:
MACINTOSH;0
UTF-8;134217984
UTF-8;
;3071
Note that in the future the attribute may be extended compatibly by adding additional information after what's there now, so any readers should be prepared for an arbitrarily long value for this attribute, with stuff following the CFStringEncoding value, separated by a non-digit.
initWithContentsOfURL:encoding:error:, initWithContentsOfURL:usedEncoding:error:, and their stringWith... counterparts now work with data that is http compressed, decompressing it first if needed. initWithContentsOfURL:usedEncoding:error: and its stringWith... counterpart now try to pick up the text encoding from http headers.
In the absence of all other encoding information, where they would have returned nil in Tiger, initWithContentsOfFile:usedEncoding:error:, initWithContentsOfURL:usedEncoding:error:, and their stringWith... counterparts now try UTF-8 as a fallback. So any ASCII file or file which looks like a valid UTF-8 stream will be loaded and reported as UTF-8.
NSString deprecations
NSString cString and related methods which have been deprecated since 10.4 are now formally marked as deprecated. All the deprecated methods have newer counterparts (added 10.4 or earlier) which take explicit encoding arguments.
NSMaximumStringLength is now deprecated. It does not work in 64bit applications. Use NSUIntegerMax instead.
NSAttributedString
Creation methods initWithString:attributes: and initWithString: now check for nil string argument and log (only once per session). The intent is to have this raise an exception for apps linked post-Leopard.
NSCharacterSet
NSCharacterSet now has a new factory method, +newlineCharacterSet.
The return type for all the factory methods is now (id) instead (NSCharacterSet *) eliminating the need for casting when creating mutable instances.
NSScanner
The following method is analogous to scanHexInt::
- (BOOL)scanHexLongLong:(unsigned long long *)result;
The following scan hex-format floating point values written out with %a or %A format characters in NSString or printf(). These require a 0x or 0X prefix:
- (BOOL)scanHexFloat:(float *)result;
- (BOOL)scanHexDouble:(double *)result;
CFError
A new CoreFoundation type, CFError, has been added for error management. It is toll-free bridged with NSError and provides the same level of functionality.
We don't expect Cocoa applications to make direct use of CFError, but we mention it here since it does enable lower-level non-Foundation based APIs to provide errors that can be automatically presented by Cocoa's error presentation and handling machinery.
As with NSError, providers of CFErrors are encouraged to make sure errors have user-presentable error messages that enable them to be presented with little or no extra work.
NSError
NSError now has two additional codes to for additional error conditions on file reading: NSFileReadTooLargeError, NSFileReadUnknownStringEncodingError.
NSValue
NSValue will now provide better descriptions for often-used structs such as NSRect, NSSize, NSPoint, and NSRange.
NSPredicate
Two new operators have been added: NSContainsPredicateOperatorType is intended to complement the NSInPredicateOperatorType, since IN and CONTAINS are not directly invertible when predicate modifiers are considered (ie 'ANY X in Y' does not achieve the same effect as 'ANY Y contains X'). NSBetweenPredicateOperatorType allows for more simplistic construction and evaluation of a common type of compound predicate that has a direct mapping in some external technologies to which predicates are mappable (ie X BETWEEN {LOWERBOUND, UPPERBOUND}). Between also allows for more efficient database operations than (x >= lower && x <= upper) due to the handling of indices.
The following new method is optimized for situations which require repeatedly evaluating a predicate with substitution variables with different variable substitutions:
- (BOOL)evaluateWithObject:(id)object substitutionVariables:(NSDictionary *)variables;
Evaluates the specified object, substituting in the values in the variables dictionary for any replacement tokens. This method returns the same result as the two step process of first invoking predicateWithSubstitutionVariables:, and then invoking evaluateWithObject:.
NSCompoundPredicate
For applications linked on Mac OS X 10.5 "Leopard" or later, initializing an NSCompoundPredicate now copies the subpredicates array rather than retaining it. Applications linked on Mac OS X 10.4 "Tiger" continue to only retain the subpredicates array for binary compatibility.
NSExpression
New expression types NSSubqueryExpressionType, NSAggregateExpressionType, NSUnionExpressionType, NSIntersectExpressionType, and NSMinusExpressionType permit CoreData to generate much more efficient SQL. On 10.4, working around the absence of these operations requires developers fetch intermediate results (wrapped as objects) and perform some operations in memory, which has impacted scalability. With these expressions, CoreData can offload substantially more work on the underlying database and avoid bringing otherwise unnecessary rows into memory.
NSExpression now also has a constructor for NSFunctionExpressionType which enables creating your own functions for use in predicate evaluation.
Scripting
Improved Error Sensing and Reporting in Scriptability
In Mac OS 10.5 many improvements have been made to Cocoa Scripting's sensing and reporting of errors. Among them:
• Cocoa's mechanism for converting Apple event object specifiers to NSScriptObjectSpecifiers and evaluating them now limits itself to using the standard error codes listed in the AppleScript documentation when reporting errors, and always tries to choose the most descriptive one. Your scripters won't have to figure out what "NSReceiverEvaluationScriptError: 4" means anymore. You can do the same in your application's code; it's completely valid to pass error codes declared in <CarbonCore/MacErrors.h> to -[NSScriptCommand setScriptErrorNumber:] or -[NSScriptObjectSpecifier setEvaluationErrorNumber:].
• NSIndexSpecifier evaluation now does much better range checking, and will always return an error for an invalid index instead of sometimes returning nothing.
• NSPositionalSpecifier construction and evaluation now checks for nonsense, and returns errors instead of letting the the command implementations that depend on it fail or malfunction in inexplicable ways. For example, telling TextEdit to 'make new window at before words of front document' no longer creates a new window and attempts to insert it in the words of the front document (!). Now it results in "TextEdit got an error: Can’t make or move that element into that container."
• NSSpecifierTest has improved type checking. For example telling TextEdit to 'get every word of the front document where it is the window of the front document' used to return nothing. Now it results in "TextEdit got an error: Can’t make window of document 1 into type word."
• NSWhoseSpecifier evaluation now returns errors for a number of constructs that are invalid, instead of returning gibberish. For example, when the front TextEdit document contains the text "The quick brown fox jumped over the lazy dog," telling TextEdit to 'get the fourth word of the front document whose third character is "e"' used to return "the," even though there was actually no fourth word whose third character is "e" at all. Now it results in "TextEdit got an error: Can’t get word 4 of document 1 whose character 3 = "e". Invalid index."
• Because the object specifier machinery is now much better at recording when errors have happened, command execution machinery now behaves more predictably. For example, telling TextEdit to 'move window "There's no window with this name!" to beginning of every window' used to do nothing. Now it results in "TextEdit got an error: Can’t get window "There's no window with this name!"."
Bug Fixes in .sdef-Declared Scriptability
Support for parsing of .sdef files was added to Cocoa's Scripting support in Mac OS 10.4. Some substantial bugs were fixed in Mac OS 10.4.3:
• Handling of whose clauses having unmatched but compatible object specifiers now works. For example, sending "the first paragraph of theDocument whose last word is equal to paragraph 3 of theDocument" to a version of TextEdit whose scriptability is declared with an .sdef file no longer results in "TextEdit got an error: Can't make paragraph 3 of document 1 into type word."
• Make commands with a "with data" parameter whose value is an object specifier now work. For example, sending "make new word at end of document 2 with data first word of document 1" to a version of TextEdit whose scriptability is declared with an .sdef file no longer results in "TextEdit got an error: Can't make word 1 of document 1 into type word."
• Count commands now return the correct results, instead of lists containing the correct results.
In Mac OS 10.4 the machinery that converts Objective-C objects to Apple event descriptors didn't take into account nesting of objects in arrays properly in application whose scriptability is declared in an .sdef file, so telling Sketch 2 to get "every graphic of every document" returned an error. This bug has been fixed in Mac OS 10.5.
In Mac OS 10.4 the machinery that converts Apple event descriptors to Objective-C objects didn't always take into account the possibility of evaluating an object specifier immediately to get a value. For example, telling a Sketch document to 'set fill color of graphic 1 to fill color of graphic 2' always failed, regardless of how many graphics there were in the document. For another example, this simple script:
tell application "Sketch"
set theDocument to make new document
set theWindow to the first window whose name is the name of theDocument
end tell
Returned "Sketch got an error: Can't make name of document "Untitled" into type string, even though the type of a document's name is of course a string. This bug has been fixed in Mac OS 10.5.
Bug Fix in -.scriptSuite/.scriptTerminology-Declared Scriptability
In all previous versions of Mac OS X there was a bug in which the determination of whether or not a command had a result that should be put in the reply Apple event was made using the return type of the script command handling method of the first receiver, instead of the .scriptSuite-declared result type of the command. This would cause, for example, the result of telling TextEdit to "close every window" to be a list of missing values, one per window. This bug has been fixed in Mac OS 10.5. Telling TextEdit to close every window now puts no result in the reply Apple event. For backward binary compatibility the old behavior remains in applications linked against Mac OS 10.4 or earlier (because the bug could mask missing result type declarations in .scriptSuite files).
Bug Fixes in General Scriptability (Updated since WWDC 2007)
In all previous versions of Mac OS X, the count command didn't work properly when the receivers were deeply nested in other objects. For example, while Sketch has always returned the correct number when asked to return the "count of every text area of every document," it has always returned the exact same number when asked to return the "count of words of every text area of every document," which was incorrect. This bug has been fixed in Mac OS 10.5.
The index specifiers resulting from the use of the AppleScript repeat with…in… construct did not handle deep nesting either. For example, telling Sketch to do something with theGraphic in a "repeat with theGraphic in every graphic of every document" clause would throw an exception, and return a very unfriendly error to the scripter. This bug has been fixed in Mac OS 10.5.
In all previous versions of Mac OS X, whose specifier evaluation did not take into account the fact that there's nothing really wrong with a test that uses a property that is not present on every tested object. For example, telling a Sketch document to get 'every graphic whose text contents is "Some text."' returned an error if any of the graphics didn't have text contents, like circles. In Mac OS 10.5 this sort of whose specifier now returns the matching objects instead of an error.
Likewise, whose specifier evaluation did not take into account the fact that there's nothing really wrong with a test that uses an out-of-range index specifier. For example, telling a TextEdit document to get 'every paragraph where the tenth word of it is "foo"' returned an error if any of the paragraphs did not have ten words. In Mac OS 10.5 this sort of whose specifier now returns the matching objects instead of an error.
Since -[NSObject(NSScripting) scriptingProperties]'s introduction in Mac OS 10.2 it has gratuitously caught and silently swallowed exceptions thrown by its invocations of -[NSObject(NSKeyValueCoding) valueForKey:]. This made it easy to overlook missing KVC-compliance in scriptable classes; getting the "properties" of a scriptable object with no error and no incorrect entries in the returned record didn't mean that everything was really working properly (and completely missing entries are easy to overlook!). -[NSObject(NSScripting) setScriptingProperties:] suffered from a similar problem. In Mac OS 10.5 these bugs are fixed. For backward binary compatibility the old behavior remains in applications linked against Mac OS 10.4 or earlier.
In recent versions of Mac OS X there was a bug that prevented NSPropertySpecifiers that specify all objects in a to-many relationship, NSMiddleSpecifiers, and NSRandomSpecifiers from being properly converted into Apple event descriptors. As a result AppleScript could not handle the result of returning one of these kinds of object specifiers from implementations of the -objectSpecifier method. This bug has been fixed in Mac OS 10.5.
Changed Behavior of -[NSSObject(NSScripting) setScriptingProperties:] (New since WWDC 2007)
Since -[NSSObject(NSScripting) setScriptingProperties:] was introduced in Mac OS 10.2, its default implementation has invoked [self coerceValue:theValue forKey:theKey] for each entry in the passed-in properties dictionary before setting the value of the individual property in the receiver. Cocoa Scripting's implementations of standard commands (Duplicate, Make, and Set, in particular) did not coerce the individual property values before invoking it. Considering that -setScriptingProperties: is just the setter of the "scriptingProperties" property, this behavior was inconsistent with how setting the value of properties is generally done by Cocoa; in every other case the setter is passed the result of applying coercion. Starting in Mac OS 10.5, this inconsistency has been fixed. -setScriptingProperties: is now passed a dictionary that contains values that are already coerced, and the default implementation of -setScriptingProperties: does no further coercion. For backward binary compatibility the old behavior remains in applications linked against Mac OS 10.4 or earlier.
Support for the Hidden Attribute in .sdef-Declared Scriptability
Support for parsing of .sdef files was added to Cocoa Scripting in Mac OS 10.4, but Cocoa's .sdef parser ignored all uses of the hidden attribute ('man 5 sdef' to see what elements could be hidden). This did not affect the appearance of an application's scriptability in 10.4's Script Editor, because Script Editor's dictionary viewer does its own .sdef parsing. It did however affect scripting applications that parsed a Cocoa application's reply to the Get Apple Event Terminology event (kASAppleScriptSuite/kGetAETE). In Mac OS 10.5, Cocoa Scripting now generates 'aete' data that takes hiding into account, by putting declarations of hidden scripting terminology elements into the implicitly hidden "Type Names" suite, where they can be found by the AppleScript interpreter but aren't to be presented to users by scripting dictionary viewers.
Make Commands with No "At" Parameter and Support for the Insert-At-Beginning Attribute in .sdef-Declared Scriptability (New since WWDC 2007)
The .sdef file format has no equivalent of the old .scriptSuite format's LocationRequiredToCreate entry, which means that the Make command's "at" parameter is always optional in applications with .sdef-declared scriptability. When a script sends a Make command with no "at" parameter to an application, NSCreateCommand's default implementation sends the container of the newly-created object an -[NSObject(NSScriptKeyValueCoding) insertValue:inPropertyWithKey:] message. In Mac OS 10.4 this would result in an exception if the class of the container did not implement an -insertIn<Key>: method. As a result every class of scriptable container had to implement an -insertIn<Key>: method for every to-many relationship (or, less commonly, override insertValue:inPropertyWithKey:) to be correct. This was very easy to overlook. In Mac OS 10.5, in applications with .sdef-declared scriptability, the default implementation of -[NSObject(NSScriptKeyValueCoding) insertValue:inPropertyWithKey:] now invokes [self insertValue:theNewObject atIndex:anIndex inPropertyWithKey:theKey] when no -insertIn<Key>: method is implemented. The value of the index is controlled by a new "insert-at-beginning" attribute in the <cocoa> subelement of the declaring <element> .sdef element. The default value of the attribute is "no," indicating that the insertion index to use is the same as the current count of related objects. If the value is "yes" the insertion index will be 0. So, by default new objects are added to the ends of lists of elements. In cases where that is not appropriate you can use "insert-at-beginning" to declare that by default new objects should be inserted at the beginning of lists of elements. See for example the declaration of the "graphic" element of Sketch's "document" class, at /Developer/Examples/AppKit/Sketch/Sketch.sdef.
Updated Support for the Responds-To Element in .sdef-Declared Scriptability
The .sdef file format has been changed in Mac OS 10.5. "responds-to" elements now have a "command" attribute instead of a "name" attribute. For backward binary compatibility Cocoa's .sdef parser recognizes either name for the attribute.
Support for Dynamic .sdef-Declared Scriptability
Cocoa did not handle Info.plist OSAScriptingDefinition entries whose values were "dynamic" in Mac OS 10.4. In Mac OS 10.5, Cocoa now uses the OSACopyScriptingDefinition() function to get the application's own .sdef data. For "dynamic" OSAScriptingDefinition Info.plist entries, this function sends an 'ascr'/'gsdf' Apple event, so you can return .sdef scripting declarations that are computed at run-time, to take plug-in scriptability into account, for instance. You have to register a handler for the Apple event. For example, you can do this in your application delegate's -applicationWillFinishLaunching: method:
// Register to provide .sdef data when asked by apps like Script Editor, or this app's own scripting machinery.
[[NSAppleEventManager sharedAppleEventManager] setEventHandler:self
andSelector:@selector(handleGetSDEFEvent:withReplyEvent:)
forEventClass:'ascr'
andEventID:'gsdf'];
And then implement the matching handler method:
- (void)handleGetSDEFEvent:(NSAppleEventDescriptor *)event withReplyEvent:(NSAppleEventDescriptor *)replyEvent {
// Our dynamic sdef isn't really that dynamic, but you can see that you have a great deal of flexibility here.
NSData *sdefData = [NSData dataWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"Sketch" ofType:@"sdef"]];
[replyEvent setDescriptor:[NSAppleEventDescriptor descriptorWithDescriptorType:typeUTF8Text data:sdefData]
forKeyword:keyDirectObject];
}
Support for Included .sdef-Declared Scriptability (New since WWDC 2007)
In Mac OS 10.5 there is a new file at /System/Library/ScriptingDefinitions/CocoaStandard.sdef that you can import from your application's .sdef file so it doesn't have to redeclare the standard classes and commands. You import it using Xinclude, like this:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE dictionary SYSTEM "file://localhost/System/Library/DTDs/sdef.dtd">
<dictionary title="Sketch Terminology" xmlns:xi="http://www.w3.org/2001/XInclude">
<xi:include href="file:///System/Library/ScriptingDefinitions/CocoaStandard.sdef"
xpointer="xpointer(/dictionary/suite)"/>
[…Stuff that's not in the Standard Suite, including stuff in the Text Suite, if that's applicable…]
<dictionary>
XPointer provides a great deal of flexibility in selecting which elements from CocoaStandard.sdef to actually include in your application's scripting declaration. See the documentation for that standard.
The declaration of the Save command in CocoaStandard.sdef requires that the "saveable file format" type be declared somewhere in your .sdef. See the 'Support for the "As" Parameter of the Save Command' section below. See also the next section for information about reusing CocoaStandard.sdef's declaration of the document class while still specifying a specific subclass of NSDocument, which is necessary.
Support for Class Extension Elements in .sdef-Declared Scriptability (Updated since WWDC 2007)
In Mac OS 10.5, Cocoa's .sdef parser understands a new <class-extension> element, which allows the declaration of additional features of an existing class. Its contents and placement are identical to those of the "class" element, but the only valid attribute is "extends," which is the name of the class being extended. A <class-extension> element may and typically will occur in a different suite than the original class.
A <class-extension> element can have a <cocoa> subelement that has a "class" attribute. For example:
<class-extension extends="document">
<cocoa class="SKTDrawDocument"/>
…
</class-extension>
The value of the "class" attribute must be the name of an Objective-C class that is a subclass of the one declared for the scripting class being extended. You can use this in apps whose .sdef imports CocoaStandard.sdef to declare the subclass of NSDocument to be be instantiated when a script tells your app "make new document." (CocoaStandard.sdef's declaration of the document class can't possibly name an Objective-C class more specific than NSDocument.) The result of multiple <class-extension> elements changing the Objective-C class of the same scripting class is undefined.
Support for Synonym Elements in .sdef-Declared Scriptability (New since WWDC 2007)
Support for parsing of .sdef files was added to Cocoa Scripting in Mac OS 10.4, but Cocoa's .sdef parser ignored all uses of the <synonym> element. In Mac OS 10.5 Cocoa parses <synonym> elements and uses the Apple event codes declared in them when converting incoming Apple events to NSScriptCommands.
Support for Custom Value Types in .sdef-Declared Scriptability
In Mac OS 10.4, you could put <value-type> elements in your application's .sdef and Cocoa would use them, but this support for custom value types was lacking in two ways:
• Corresponding hidden classes weren't put in 'aete' generated by Cocoa Scripting. This meant that AppleScript wouldn't recognize the name of the type unless it was one declared by AppleScript itself. In Mac OS 10.5 Cocoa now generates the right 'aete' data for <value-type> declarations. (In Mac OS 10.5, AppleScript asks apps with .sdef-declared scriptability for their sdef data instead of their 'aete' data so this fix is less important than it was, but it still might affect some scripting tools.)
• There was no documentation about what code had to be written to make custom value types work (though some people deduced it based on the exceptions thrown when required methods weren't implemented). Here's a little documentation.
When you put a <value-type> element in your application's .sdef, you also have to provide methods that Cocoa can use to convert Apple event descriptors of that type to Objective-C objects and vice versa. There must be a class method whose name matches the pattern +scripting<CondensedTypeName>WithDescriptor:, where CondensedTypeName is the type name with the first letter of each word capitalized and the spaces removed. Cocoa sends +scripting<CondensedTypeName>WithDescriptor: messages to the class named in the <cocoa> subelement of the <value-type> element in question when it needs to convert an Apple event descriptor into an Objective-C object. The method should return nil for failure, and take advantage of regular Apple event coercion where applicable. There must also be an instance method whose name matches the pattern -scripting<CondensedTypeName>Descriptor. Cocoa sends -scripting<CondensedTypeName>Descriptor messages to objects that it must convert into Apple event descriptors. This method should also return nil for failure. Neither kind of method needs to record error information in the current script command when it returns nil.
See NSColor_SKTScripting.m in /Developer/Examples/AppKit/Sketch for an example. It's Sketch's implementation of the "RGB color" value type.
Support for the Missing Value Type in .sdef-Declared Scriptability
In Mac OS 10.5 you can now use "missing value" as a type name. It corresponds to the Objective-C NSNull class. You will typically use it as an alternative in a complex type. For example, the declaration of the fill color property of the graphic class in Sketch.sdef now looks like this:
<property name="stroke thickness" code="slwd">
<type type="real"/>
<type type="missing value"/>
<cocoa key="scriptingStrokeWidth"/>
</property>
That means at least four things:
• An AppleScript can set the stroke thickness of a graphic to either a number or the missing value.
• The method that provides KVC compliance for setting the value for the "scriptingStrokeWidth" key must be prepared to handle either a floating point number or nil. See Sketch's -[SKTGraphic setScriptingStrokeWidth:] to see how it does this.
• The getter method for the "scriptingStrokeWidth" key is allowed to return either a floating point number or nil. See Sketch's -[SKTGraphic scriptingStrokeWidth].
• An AppleScript shouldn't be surprised if it asks for the stroke thickness of a graphic and the result is the missing value (which is distinct by the way from no value).
Most application code isn't supposed to have to deal with NSNull, so whenever Cocoa Scripting invokes one of your application's KVC setter methods, it always converts NSNull to nil first. For backward binary compatibility however it doesn't do this in applications linked against Mac OS 10.4 or earlier (because there was limited, unpublished support for NSNull values even before Mac OS 10.5, and there are likely to be shipping applications with setters that expect to be passed NSNull and would malfunction when passed nil). Likewise, your application's KVC getter methods can return nil instead of NSNull.
Also, Cocoa Scripting now does a good job of returning missing values in result lists. For example, telling Sketch to get the "text contents of every graphic of the front document," when the front document contains a text area and a circle (circles don't have text contents), now returns something like {"the contents of the text area", missing value} instead of an error.
How Support for Complex Types in .sdef-Declared Scriptability Works, and a Bug Fix (New since WWDC 2007)
When you declare that a class property or a command parameter is of complex type, like this example from iChat's .sdef file:
<enumeration name="InviteType" code="invt">
<enumerator name="audio invitation" code="acon">
<cocoa name="AudioInvitation"/>
</enumerator>
<enumerator name="text chat invitation" code="tcon">
<cocoa name="TextInvitation"/>
</enumerator>
<enumerator name="video invitation" code="vcon">
<cocoa name="VideoInvitation"/>
</enumerator>
</enumeration>
<command name="send" code="ichtsend" description="Sends a message or file to a buddy or to a chat.">
<cocoa class="SendCommand"/>
<direct-parameter>
<type type="text"/>
<type type="file"/>
<type type="InviteType" hidden="yes"/>
</direct-parameter>
[…]
</command>
The machinery in Cocoa Scripting that converts incoming Apple event descriptors to Objective-C objects tries to do so using information about each type, in turn, until a successful conversion has been done, in which case it stops trying and ignores the rest of the types. In this example, Cocoa will first try to convert an Apple event descriptor to an NSString (the Objective-C class that corresponds to the "text" type), then an NSURL (corresponding to "file"), and then an NSNumber (the default class corresponding to enumerators).
That was true in Mac OS 10.4, and is still generally true in Mac OS 10.5, with one new refinement: to accommodate the fact that Apple event coercions built into the Mac OS X frameworks sometimes make it possible to convert to a type that is not necessarily the best one out of the alternatives, Cocoa may now try to still convert to other types in the list, and choose the resulting value of one of those other types. In Mac OS 10.5 it does this by favoring any other value class over NSString or NSURL, because those are the two classes to which conversion is often successful only because of inadvertent coercion. When an Apple event descriptor can be converted to either an NSString or an NSURL according to the declared complex type, it favors NSURL if the original Apple event descriptor's type is one that explicitly indicates files (typeFileURL, typeAlias, etc.), NSString otherwise. Given these rules, in our example telling iChat to 'send video invitation to aBuddy' now results in a send command whose direct parameter is an NSNumber wrapping the four character code 'vcon', which is correct. On Mac OS 10.4 it would have resulted in a send command whose direct parameter is an NSString containing "vcon," which is incorrect. Similarly, telling iChat to 'send POSIX file "/Applications/Chess.app"' now results in a send command whose direct parameter is an NSURL containing "file://localhost/Applications/Chess.app," which is correct. On Mac 10.4 it would have resulted in a send command whose direct parameter is an NSString containing "YourRootVolumeName:Applications:Chess.app:," which is incorrect.
Support for Nondefault Enumerator Values in .sdef-Declared Scriptability
In Mac OS 10.5 you can now add an attribute to the "cocoa" subelement of .sdef-declared enumerator declarations to specify what value your code is passed when a script uses that enumerator. For example:
<enumeration name="printing error handling" code="enum">
<enumerator name="standard" code="lwst" description="Standard PostScript error handling">
<cocoa boolean-value="NO"/>
</enumerator>
<enumerator name="detailed" code="lwdt" description="print a detailed report of PostScript errors">
<cocoa boolean-value="YES"/>
</enumerator>
</enumeration>
The "boolean-value" attributes, in combination with this property in the standard print settings record declaration:
<property name="error handling" code="lweh" type="printing error handling" description="how errors are handled">
<cocoa key="NSDetailedErrorReporting"/>
</property>
Results in an entry whose key is "NSDetailedErrorReporting" and whose value is a boolean NSNumber with a value of NO or YES being put in the NSDictionary to which a print settings record Apple event descriptor is converted. (And that's convenient because such a dictionary can be used as the attributes dictionary of an NSPrintInfo without further processing, while the scripter just works with the kind of print settings record described in Technical Note 2082, "The Enhanced Print Apple Event.")
In addition to "boolean-value," "string-value" and "integer-value" attributes are supported. "string-value" not surprisingly corresponds to NSString, and the other two correspond to NSNumber. You can only use one per "cocoa" subelement. If you don't use any, the default behavior is the same as Mac OS 10.4's, which is to make the programmatic value associated with the enumerator an NSNumber containing the four character code of the enumerator.
This works with any kind of enumerator. For example, you can use "integer-value" attributes in an enumeration type that's used as the parameter type of a command, and deal with simple small integers in your code instead of four character codes. (Just make sure to keep the .sdef and the code consistent!)
Support for the "As" Parameter of the Save Command
In all previous versions of Mac OS X -[NSDocument handleSaveScriptCommand:] ignored the "as" parameter, even though Foundation's own declaration of the save command includes such a parameter. In Mac OS 10.5 -[NSDocument handleSaveScriptCommand:] now uses the "as" parameter if its value is an NSString, interpreting it as a type name of the sort used by NSDocument. In .sdef-declared scriptability you can take advantage of the enumerator value mechanism described in the previous section to allow for writing scripts that don't have to mention NSDocument type names, which can be too technical to make users deal with. For example, Sketch 2 (which uses UTIs as its document type names; see the AppKit release notes for information about doing that) declares a "saveable file format" enumeration and uses it as the type of the "as" parameter:
<enumeration name="saveable file format" code="savf">
<enumerator name="Sketch" code="sktc" description="The native Sketch 2 file format">
<cocoa string-value="com.apple.sketch2"/>
</enumerator>
<enumerator name="PDF" code="PDF " description="Portable Document Format">
<cocoa string-value="com.adobe.pdf"/>
</enumerator>
<enumerator name="TIFF" code="TIFF" description="Tagged Image File Format">
<cocoa string-value="public.tiff"/>
</enumerator>
</enumeration>
<command name="save" code="coresave" description="Save a document.">
<direct-parameter type="specifier" description="The document(s) or window(s) to save."/>
<parameter name="in" code="kfil" type="file" optional="yes" description="The file in which to save the document.">
<cocoa key="File"/>
</parameter>
<parameter name="as" code="fltp" type="saveable file format" optional="yes" description="The file format to use.">
<cocoa key="FileType"/>
</parameter>
</command>
This allows people to write this sort of thing in their scripts:
save theDocument in theFile as TIFF
Better Behavior of the Save Command in Unsaved Documents
In Mac OS 10.4 it was not possible to export a document to a non-native file format if the document had never been saved. (An application of a too-literal reading of the Scripting Interface Guidelines' "save in with an unsaved file acts like Save As.") In Mac OS 10.5, if the file format specified by a save command, either implicitly with an "as" parameter or implicitly with a file name extension, is not a native file format for the document, but it is one to which the document can be exported, the save command acts like Save a Copy (also known as NSSaveToOperation, also known as Export As, in the Human Interface Guidelines nowadays).
Support in NSCloneCommand for Making the "To" Parameter of the Duplicate Command Optional
NSCloneCommand's default implementation now duplicates the receivers of the command in place when a script does not specify a "to" parameter, inserting each duplicate after the original in the element sequence. For example, you can now tell a Sketch document to 'duplicate every graphic'. For apps with .scriptSuite/.scriptTerminology-declared scriptability, Cocoa's own declaration of the duplicate command has been updated to take advantage. For apps with .sdef-declared scriptability, this feature will be disabled until you've updated the application's .sdef to declare the "to" parameter optional.
Ending of Undo Manager Groups During Handling of Scripting Commands
In previous versions of Mac OS X the mechanism that automatically ends undo manager groups during event handling was not triggered during handling of Apple events, including those containing scripting commands. This meant that scripted changes were sometimes put in the same undo manager group as whatever change the user happened to make after switching back to the application. It also meant that things like documents' modification status weren't always updated in a timely fashion. Starting in Mac OS 10.5, any open undo manager groups are ended after the dispatch of each Apple event.
New Methods You Can Override to Customize Creation and Copying of Scripting Objects (New since WWDC 2007)
Historically Cocoa Scripting has created new scripting objects by sending +alloc to a class and -init to the resulting object. It's copied scripting objects by sending -copyWithZone:. People have discovered many situations where this is not sufficient. So that you can take more control over what happens when your application is sent a Make or Duplicate command, new methods have been added to NSObject(NSScripting) for you to override. These methods are invoked on the prospective container of the new or copied object. The returned objects or objects are then inserted into the container using key-value coding:
- (id)newScriptingObjectOfClass:(Class)class
forValueForKey:(NSString *)key
withContentsValue:(id)contentsValue
properties:(NSDictionary *)properties;
Create a new instance of a scriptable class to be inserted into the relationship identified by the key, set the contentsValue and properties of it, and return it. The contentsValue and properties are derived from the "with contents" and "with properties" parameters of a Make command. The contentsValue may be nil.
- (id)copyScriptingValue:(id)value forKey:(NSString *)key withProperties:(NSDictionary *)properties;
Create one or more scripting objects to be inserted into the relationship identified by the key by copying the passed-in value, set the properties in the copied object or objects, and return it or them. The value is, for example, derived from the receivers of a Duplicate command. Its type must match the type of the property identified by the key. For example, if the property is a to-many relationship, the value will always be an array of objects to be copied, and an array of objects must therefore be returned. The properties are derived from the "with properties" parameter of a Duplicate command.
New Method You Can Override to Customize Object Specifier Evaluation Without Making Up Object Indexes (New since WWDC 2007)
There have been several requests for an alternative to implementing -[NSObject(NSScriptObjectSpecifiers) indicesOfObjectsByEvaluatingObjectSpecifier:] to customize the evaluation of object specifiers, one that doesn't require the scripting container to make up indexes for contained objects that don't naturally have indexes. A new method has been added to NSObject(NSScripting) for you to override:
- (id)scriptingValueForSpecifier:(NSScriptObjectSpecifier *)objectSpecifier;
Given an object specifier return the specified object or objects in the receiving container. This might successfully return an object, an array of objects, or nil, depending on the kind of object specifier. Because nil is a valid value, failure is signaled by sending the object specifier -setEvaluationError: before returning. Your override doesn't also have to invoke any of the NSScriptCommand error signaling methods, though it can, to record very specific error information. The NSUnknownKeySpecifierError and NSInvalidIndexSpecifierError numbers are special, in that Cocoa may continue evaluating an outer specifier if they're encountered, for the convenience of scripters.
New NSScriptObjectSpecifier Methods for Accessing the Underlying Apple Event Descriptor (New since WWDC 2007)
Several people have requested a way to create an NSScriptObject specifier from an Apple event descriptor and a way to get the Apple event descriptor out of an NSScriptObjectSpecifier. New methods have been added to NSScriptObjectSpecifier:
+ (NSScriptObjectSpecifier *)objectSpecifierWithDescriptor:(NSAppleEventDescriptor *)descriptor;
Given a typeObjectSpecifier Apple event descriptor, create and return an object specifier, or nil for failure. If this is invoked and fails during the execution of a script command, information about the error that caused the failure is recorded in [NSScriptCommand currentCommand].
- (NSAppleEventDescriptor *)descriptor;
Return an Apple event descriptor that represents the receiver. If the receiver was created with +objectSpecifierWithDescriptor: the passed-in descriptor is returned. Otherwise a new one is created and returned (autoreleased, of course).
New NSScriptClassDescription Methods for Accessing Information from the Class Declaration (New since WWDC 2007)
Because the "name" of an NSScriptClassDescription resulting from an .sdef class declaration is its human-readable name, the -name method cannot be used to find out the Objective-C class that must be instantiated to make objects of that scriptable class. To let you get at that information, an existing method in NSScriptClassDescription has been published:
- (NSString *)implementationClassName;
Return the name of the Objective-C that implements the described scriptable class. This method also works on Mac OS 10.4.
NSScriptClassDescription hasn't had enough accessor methods to allow for some of the customizations that people want to do. Also, overriders of -[NSObject(NSScripting) scriptingValueForSpecifier:] may have to do some of the same error checking that the default implementation of that method does. New methods have been added to NSScriptClassDescription:
- (BOOL)hasPropertyForKey:(NSString *)key;
- (BOOL)hasOrderedToManyRelationshipForKey:(NSString *)key;
- (BOOL)hasReadablePropertyForKey:(NSString *)key;
- (BOOL)hasWritablePropertyForKey:(NSString *)key;
Return whether the described class has a property identified by the key, whether it's a to-many relationship, whether it's readable, or whether it's writable, respectively. For example, -[NSObject(NSScripting) scriptingValueForSpecifier:] uses -hasPropertyForKey: to make sure that the scripted object actually has the specified property. (Because Cocoa Scripting lets you do things like telling Sketch to get the "text contents of graphic 1 of document 1," and something has to make sure that graphic 1 is not actually a circle, which doesn't have text contents.) It then uses -isPropertyReadableForKey: to make sure that the property has not been declared to be write-only.
Because the existing -[NSScriptClassDescription isReadOnlyKey:] does not fit the pattern established by these new methods, and because it is a little dangerous (a result of NO could mean writing to that property is permitted, or it could just mean that the key is just unrecognized), it is deprecated in Mac OS 10.5.
New NSScriptCommand Methods for Error Reporting (New since WWDC 2007)
Cocoa Scripting's error reporting is much improved in Mac OS 10.5. One of the big improvements is that it now populates the reply Apple event with the standard kOSAErrorOffendingObject and kOSAErrorExpectedType parameters when those are applicable. So that your code can do the same, new methods have been added to NSScriptCommand:
- (void)setScriptErrorOffendingObjectDescriptor:(NSAppleEventDescriptor *)errorOffendingObjectDescriptor;
- (void)setScriptErrorExpectedTypeDescriptor:(NSAppleEventDescriptor *)errorExpectedTypeDescriptor;
- (NSAppleEventDescriptor *)scriptErrorOffendingObjectDescriptor;
- (NSAppleEventDescriptor *)scriptErrorExpectedTypeDescriptor;
Set or get the offending object or expected type descriptor that should be put in the reply to the Apple event from which this command was constructed, when execution of the command is completed, if the sender of the event requested a reply.
New NSPositionalSpecifier Accessor Methods (New since WWDC 2007)
So that you can get the values with which an NSPositionalSpecifier (a "location specifier," in AppleScript-speak, like the "at" parameter of a Make command) was initialized, new accessor methods have been added:
- (NSInsertionPosition)position;
- (NSScriptObjectSpecifier *)objectSpecifier;
Return the position or object specifier that was specified at initialization time.
Results Now Returned by the Open Command (New since WWDC 2007)
In previous versions of Mac OS X AppKit's default handling of the Open command never returned a result. Starting in Mac OS 10.5, it returns an NSDocument or an NSArray of NSDocuments, depending on whether the direct parameter of the command is a file or a list of files. For applications with .scriptSuite/.scriptTerminology-declared scriptability, Foundation's declaration of the standard suite (in its NSCoreSuite.scriptSuite resource file) has been updated to match. For applications with .sdef-declared scriptability, the CocoaStandard.sdef file mentioned elsewhere in these notes also includes a declaration of the Open command with appropriate result types.
NSURL methods
NSURL has new creation methods:
- initFileURLWithPath:(NSString *)path isDirectory:(BOOL)isDir;
+ (id)fileURLWithPath:(NSString *)path isDirectory:(BOOL)isDir;
These methods enable NSURL to avoid an extra I/O to check whether the path is a directory or not.
Note that NSURL.h lists these two methods as being available back to 10.4. This is incorrect; these methods were added in 10.5 and don't exist back on 10.4.
Deprecated NSURLHandle
NSURLHandle has been deprecated, as have all APIs that reference them. NSURLConnection (introduced in 10.3) should be used in its place.
NSJavaSetup.h deprecated
All API in NSJavaSetup.h has been deprecated in 10.5. The header will likely not be available in the next major OS release after 10.5.
NSInvocation.h API deprecations
The enum _NSObjCValueType type and the NSObjCValue type have been deprecated. These things will likely not be available in this header in the next major OS release after 10.5.
+poseAsClass: deprecated
The +poseAsClass: method in NSObject has been deprecated. Posing has been deprecated in the Objective C runtime, and this change is a reflection of that.
NSCoder.h API deprecated
The function NXReadNSObjectFromCoder() and the methods encodeNXObject: and decodeNXObject, which appear in NSCoder.h, have been deprecated in 10.5. If you've been putting up with the logged messages since 10.0, it's time for you to move on.
Deprecated NSRunLoop API
The -configureAsServer method is deprecated in 10.5. It never did anything, so there was never a point in calling it in Mac OS X.
Deprecated defaults constants in NSUserDefaults.h
As mentioned in the 10.4 release notes for Foundation, the following user defaults are deprecated in 10.5:
NSString * const NSWeekDayNameArray;
NSString * const NSShortWeekDayNameArray;
NSString * const NSMonthNameArray;
NSString * const NSShortMonthNameArray;
NSString * const NSTimeFormatString;
NSString * const NSDateFormatString;
NSString * const NSTimeDateFormatString;
NSString * const NSShortTimeDateFormatString;
NSString * const NSCurrencySymbol;
NSString * const NSDecimalSeparator;
NSString * const NSThousandsSeparator;
NSString * const NSDecimalDigits;
NSString * const NSAMPMDesignation;
NSString * const NSHourNameDesignations;
NSString * const NSYearMonthWeekDesignations;
NSString * const NSEarlierTimeDesignations;
NSString * const NSLaterTimeDesignations;
NSString * const NSThisDayDesignations;
NSString * const NSNextDayDesignations;
NSString * const NSNextNextDayDesignations;
NSString * const NSPriorDayDesignations;
NSString * const NSDateTimeOrdering;
NSString * const NSInternationalCurrencyString;
NSString * const NSShortDateFormatString;
NSString * const NSPositiveCurrencyFormatString;
NSString * const NSNegativeCurrencyFormatString;
Developers should use NSLocale, NSDateFormatter and NSNumberFormatter APIs instead.
Where possible, NSUserDefaults will supply compatible values for these keys, derived from the above sources. For the following keys, localized values are not available from the above sources and values will be provided in English for all localizations:
NSDecimalDigits, NSHourNameDesignations, NSYearMonthWeekDesignations, NSEarlierTimeDesignations, NSLaterTimeDesignations,
NSThisDayDesignations, NSNextDayDesignations, NSNextNextDayDesignations, NSPriorDayDesignations
Removed headers
The following previously deprecated headers have been removed from Foundation in 10.5:
NSCompatibility.h
NSUtilities.h
NSSerialization.h
Foundation profile binary
Foundation no longer provides a version of the binary built for profiling. Of course, Foundation used to be one of the few libraries that actually did provide one. Use dtrace instead.
Copyright © 2007 Apple Computer, Inc.