PATH Documentation > Release Notes
Mac OS X Tiger 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 as well as for most other Cocoa frameworks, most notably the Application Kit.
This document describes the changes in Foundation Framework in Mac OS X release 10.4, Tiger. You can find release notes for the Application Kit as well as some important notes on general backward compatibility issues, version handling, etc, here. The "Backward Compatibility" note is reproduced below.
Sections which are new in the release notes since WWDC Tiger Developer Preview are marked with "(Section added since WWDC)"; sections with significant updates are marked with "(Section updated since WWDC)".
Backward Compatibility
One backward compatibility mechanism that is occasionally used in the frameworks is to check for the version of the system an application was built against, and if an older system, 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 Tiger, 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.
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]).
NSMetadata
NSMetadata.h contains several classes which expose the Spotlight API to Cocoa developers. The principle class is NSMetadataQuery. The NSMetadata classes are bindings-compliant. Cocoa keys for the well-defined Spotlight attributes of MDItemRef are not available; use the keys of the Spotlight layer (such as kMDItemContentType) directly.
There is a new example, /Developer/Examples/AppKit/Spotlighter, which demonstrates the use of the NSMetadataQuery.
NSXMLNode, NSXMLDocument, NSXMLElement, NSXMLDTD, NSXMLDTDNode (Section updated since WWDC)
These are new classes to represent XML objects. There is reference documentation at Cocoa->Internet and Web->Tree-based XML Processing.
To provide a fast implementation NSXML does not check the validity of data when using setStringValue or setObjectValue. This means that, for example, the content of a comment could be set to "foo--bar" and NSXML will output an invalid comment: <!--foo--bar-->. To provide a robust implementation when handling unknown input, clients should check for "--" anywhere and "-" at the end of the string; processing instructions should be checked for "?>". NSXML breaks CDATA sections up on output if they contain "]]>". For example, if the content of a cdata node is set to "foo]]>bar", NSXML will output "<!CDATA[foo]]]]><!CDATA[>bar]]>". NSXML does not normalize data (change linebreaks, merge text nodes) when setting a node's value. Invalid XML characters such as control characters will be output if a node's value includes them.
The XQuery/XPath implementation conforms to the October 2004 draft specification. It supports the optional features "Full Axis" and "Module Feature". Regular expressions use pcre and do not support Unicode character classes such as \p{Lu} or block escapes.
NSLocale (Section updated since WWDC)
The new NSLocale class is a cover over the CFLocale API in CoreFoundation. NSLocales and CFLocales are toll-free bridged.
NSLocales cannot be passed into Cocoa APIs which take a locale: parameter -- these are expecting a dictionary for that parameter. It is unclear whether such APIs will be enhanced to take either NSDictionary * or NSLocale * in the future, as there are compatibility issues, such as the possible existence of subclasses which have overridden those methods and will fail if given an NSLocale *. There is no API for converting an NSLocale * to an NSDictionary *, and although both implement -objectForKey:, the two use different sets of keys.
There are some additional notes on CFLocale in the CoreFoundation Release Notes, which may be useful to users of the NSLocale API.
NSCalendar (Section added since WWDC)
The new NSCalendar class is a cover over the new CFCalendar API in CoreFoundation. NSCalendar allows you to ask for numeric properties of a calendar, convert between NSDates and decomposed unit representations, and perform some types of calendrical arithmetic. NSCalendars and CFCalendars are toll-free bridged.
NSCalendars are created using the calendar identifiers in NSLocale.h, and only those identifiers are supported. You cannot define your own calendars with NSCalendar, though you can subclass and override every instance method, and you would also have to create a custom NSDateFormatter to get date formatting using your calendar, as NSDateFormatter only understands the well-defined built-in calendars in Mac OS X 10.4 and does not necessarily invoke methods on its NSCalendar attribute to compute answers. The "current calendar" returned by +currentCalendar is the user's preferred calendar configured with the user's locale and the default time zone. The default locale for a NSCalendar is the System Locale (+[NSLocale systemLocale]).
Note: the Chinese calendar is currently unimplemented in the NSCalendar, and related, APIs. (Results are undefined.)
You can change some properties of an NSCalendar (locale, time zone, first day of the week, and the minimum number of days for a week to be the first week of the year). However, these are just a convenience for setting parameters to the calendrical calculations, and do not change the NSCalendar, say, for purposes of equality testing, and are not archived.
The values/computations/results of the NSCalendar API do not necessarily agree with the values/computations/results from the NSCalendarDate API in NSCalendarDate.h. The NSCalendarDate API is taking a secondary place to the NSCalendar and NSDateFormatter APIs as of Mac OS X 10.4, and may be deprecated in the next release.
There are many additional notes on CFCalendar in the CoreFoundation Release Notes, which will be useful to users of the NSCalendar API. The following notes describe the main difference between the CFCalendar and NSCalendar APIs.
Instead of variable-argument methods and component description strings as in the CFCalendar API, NSCalendar uses the simple NSDateComponents object to hold arbitrary sets of components for the calendrical calculation methods. NSDateComponents is basically just an object with fields that can be get and set, but can also be extended later, and results in an API which is more Cocoa-like than the CFCalendar API. Component fields which are not initialized or which should be ignored have the value NSUndefinedDateComponent. NSDateComponents can be used to represent dates/times, like, 26 March to variable degrees of specificity (e.g., the example doesn't specify which year, which could represent any), or quantities of components, like "5 months and 1 hour". It is important to note that NSDateComponents (1) does not do any calendrical calculations (it doesn't return "correct" answers for fields which have not been set), and (2) it does not check the fields being set for (a) consistency amongst the fields or (b) range validity. NSDateComponents is also not tied to any particular calendar, so in some situations, both an NSCalendar and an NSDateComponents may need to be kept together to make sense of the date later.
When an NSDateComponents is the return value, a unitFlags argument specifies which fields of the NSDateComponents are to be initialized/used. The unit constants are bitwise OR'd together to make the unitFlags argument.
The NSDateComponents approach does not allow for components to be specified in a particular order to the -dateByAddingComponents:toDate:options: and -components:fromDate:toDate:options: calendrical operations. NSCalendar always uses the components in the order that the unit constants are listed in NSCalendar.h, so to effect a particular computation order to the components, multiple calls to the computation methods may have to be made, and computation of intermediate values. Difference computations with the Week unit will be particularly troublesome in this regard.
Note that the NSDateComponents class does not implement the NSCopying or NSCoding protocols, which is an oversight in Mac OS X 10.4.
NSDateFormatter (Section updated since WWDC)
For Mac OS X 10.4, the NSDateFormatter class gets a major functionality overhaul. The new implementation is based on CFDateFormatter, which is based on the open-source ICU (International Components for Unicode) library, and should produce much better localized formatted dates. NSDateFormatter and CFDateFormatter, however, are not toll-free bridged.
There are basically two modes in which an NSDateFormatter can operate, called the "formatter behavior". The 10.0 (to 10.3) compatibility mode operates like NSDateFormatter has in previous Mac OS X releases, including the limitations and bugs. The new 10.4 behavior mode allows more configurability and better localization.
Developers are encouraged to use the NSDateFormatterStyle constants to specify how much information is displayed for the date and time parts of a formatted NSDate. The styles are NoStyle (omit this part, either date or time or both), ShortStyle, MediumStyle, LongStyle, and FullStyle (displaying the most information). These are styles that the user can configure in the International preferences panel in System Preferences. If you as a developer decide that you just don't like any of the styles, and set your own format string, then you can just just the components you want to be displayed, but you lose user-configurability.
In addition to the methods inherited from NSFormatter, NSDateFormatter adds the getObjectValue:forString:range:error: method. This method allows you to specify a subrange of the string to be parsed, and returns the range of the string which was actually parsed (which, on failure, indicates where the failure occurred). The method also returns an NSError object, which can contain richer information than the failure string returned by the inherited getObjectValue:... method. NSDateFormatter also adds two convenience methods, -stringFromDate: and -dateFromString:.
Note that NSCell, since it works with general NSFormatters, only invokes the NSFormatter getObjectValue:... method in Mac OS X 10.4. For a 10.4-style date formatter, that method calls the new getObjectValue:... method.
But, NSDateFormatters don't have to just be attached to cells. The new methods are provided to make it nicer to use an NSDateFormatter directly in code, and that is the direction in which the Foundation framework is moving. Developers wanting to format dates into strings will use date formatters.
There are several new attributes one can get and set on a 10.4-style date formatter, including the date style, time style, locale, time zone, calendar, format string, the two-digit-year cross-over date, the default date which provides unspecified components, and there is also access to the various textual strings, like the month names. But it will generally be atypical to change most of these attributes from their default values.
The new methods in 10.4 do not do anything when invoked on a 10.0-style formatter, and return a generic return value when required to return something. The new methods should not be invoked on a 10.0-style formatter.
The biggest change in a 10.4-style formatter is the format of the format string. The "%A %B %y" style of NSDateFormatter formats in 10.3 and earlier and NSCalendarDate formats has been replaced with the format string structure of CFDateFormatter (and ICU). These format strings are similar to those found in C#/.Net and Java APIs. See the documentation for CFDateFormatter or NSDateFormatter for more information. When the formatter is in "10.0" mode, the old-style format strings are required. One thing to note with the CFDateFormatter format string format is that literal text should be enclosed inside single quotes (') in the format string -- this is easy to forget.
The object type for "10.0" date formatters is still NSCalendarDates, but for new-style formatters, it is NSDates. You can configure a new-style formatter to generate NSCalendarDates with setGeneratesCalendarDates: if you want them. You are encouraged to switch to NSDates now, if possible, for new-style formatters.
The default behavior for NSDateFormatters in Mac OS X 10.4 is the 10.0 behavior, for backwards binary compatibility. Developers are encouraged to try out 10.4-style formatters, and switch to them if possible, to get the better localization support. Obviously that has to be conditionally done if the app is shipping on releases prior to 10.4 as well.
You can call [formatter setFormatterBehavior:NSDateFormatterBehavior10_4] on each individual formatter instance you want to change. Note that the old -initWithDateFormat:allowNaturalLanguage: method always initializes one to 10.0 behavior. But you may have to update the behavior of your app as well when you do that; for example, the new-style formatter will start returning NSDates instead of NSCalendarDates by default, and if your app is expecting NSCalendarDates later, there will be trouble.
There is a new default you can also set to have date formatters converted to new-style automatically (which could cause other trouble in the app, be warned). Set the "NSMakeDateFormatters10_4" default to a boolean YES/true value in the app's preferences using the 'defaults' command. The preference has to be set before any use of the NSDateFormatter class is made. The default has two effects: (1) date formatters which are created with +alloc/-init will be 10.4-style; (2) date formatters which are unarchived from either non-keyed or keyed archives will be converted to 10.4-style if the archived formatter has uncustomized format string -- most of those found in IB's NSDateFormatter inspector -- at unarchive time.
The main down-side that may be noticed with a new 10.4-style date formatter is that the lenient parsing mode is not as forgiving as the "natural language" parsing of NSDateFormatter when "allowsNaturalLanguage" was turned on in the formatter. This has a bad and a good side. Users will have to be a bit more careful and perhaps thorough when typing in dates, but they are more likely to find that the value they were trying to input was correctly set to the value they wanted rather than what the "natural language" parsing guessed they meant.
NSNumberFormatter (Section updated since WWDC)
For Mac OS X 10.4, the NSNumberFormatter class gets a major functionality overhaul. The new implementation is based on CFNumberFormatter, which is based on the open-source ICU (International Components for Unicode) library, and should produce much better localized formatted numbers. NSNumberFormatter and CFNumberFormatter, however, are not toll-free bridged.
There are basically two modes in which an NSNumberFormatter can operate, called the "formatter behavior". The 10.0 (to 10.3) compatibility mode operates like NSNumberFormatter has in previous Mac OS X releases, including the limitations and bugs. The new 10.4 behavior mode allows more configurability and better localization.
Developers are encouraged to use the NSNumberFormatterStyle constants to specify pre-canned sets of attributes which determine how a formatted number is displayed. The styles are NoStyle (use when you're going to set the format string yourself), DecimalStyle, CurrencyStyle, PercentStyle, ScientificStyle, and SpellOutStyle (textual number representation). These are styles that the user can configure in the International preferences panel in System Preferences. If you as a developer decide that you just don't like any of the styles, and set your own format string, then you can just just the components you want to be displayed, but you lose user-configurability.
In addition to the methods inherited from NSFormatter, NSNumberFormatter adds the getObjectValue:forString:range:error: method. This method allows you to specify a subrange of the string to be parsed, and returns the range of the string which was actually parsed (which, on failure, indicates where the failure occurred). The method also returns an NSError object, which can contain richer information than the failure string returned by the inherited getObjectValue:... method. NSNumberFormatter also adds two convenience methods, -stringFromNumber: and -numberFromString:.
Note that NSCell, since it works with general NSFormatters, only invokes the NSFormatter getObjectValue:... method in Mac OS X 10.4. For a 10.4-style number formatter, that method calls the new getObjectValue:... method.
But, NSNumberFormatters don't have to just be attached to cells. The new methods are provided to make it nicer to use an NSNumberFormatter directly in code, and that is the direction in which the Foundation framework is moving. Developers wanting to format numbers into strings in ways more complex or perhaps more convenient than NSString formatting allows will use number formatters.
There are several new attributes one can get and set on a 10.4-style number formatter, including the number style, locale, negative-number and positive-number format strings, various strings for special values, text attribute sets for created attributed strings, and various other configuration attributes. But it will generally be atypical to change most of these attributes from their default values.
The new methods in 10.4 do not do anything when invoked on a 10.0-style formatter, and return a generic return value when required to return something. The new methods should not be invoked on a 10.0-style formatter. On a 10.4-style formatter, the old methods map approximately to one or more new methods/attributes, but the new methods should be used directly when possible.
There are slight changes in a 10.4-style formatter to the format of the format string. The 10.0-style of NSNumberFormatter formats in 10.3 and earlier has been replaced with the format string structure of CFNumberFormatter (and ICU). These format strings are similar to those found in C#/.Net and Java APIs. See the documentation for CFNumberFormatter or NSNumberFormatter for more information. One thing to note with the CFNumberFormatter format string format is that literal text should be enclosed inside single quotes (') in the format string -- this is easy to forget. The main difference is that the '_' (underbar) format character of the 10.0-style formatter is not accepted by a 10.4-style formatter, and that the position of the comma(s), if they occur in the 10.4 format string (and they need not) is significant and determines where the grouping separators will be placed (where it is not significant in a 10.0-style format).
The object type for "10.0" number formatters is still NSDecimalNumbers, but for new-style formatters, it is NSNumbers. You can configure a new-style formatter to generate NSDecimalNumbers with setGeneratesDecimalNumbers: if you want them. You are encouraged to switch to NSNumbers now, if possible, for new-style formatters.
The default behavior for NSNumberFormatters in Mac OS X 10.4 is the 10.0 behavior, for backwards binary compatibility. Developers are encouraged to try out 10.4-style formatters, and switch to them if possible, to get the better localization support. Obviously that has to be conditionally done if the app is shipping on releases prior to 10.4 as well.
You can call [formatter setFormatterBehavior:NSNumberFormatterBehavior10_4] on each individual formatter instance you want to change. But you may have to update the behavior of your app as well when you do that; for example, the new-style formatter will start returning NSNumbers instead of NSDecimalNumbers by default, and if your app is expecting NSDecimalNumbers later, there will be trouble.
There is a new default you can also set to have date formatters converted to new-style automatically (which could cause other trouble in the app, be warned). Set the "NSMakeNumberFormatters10_4" default to a boolean YES/true value in the app's preferences using the 'defaults' command. The preference has to be set before any use of the NSNumberFormatter class is made. The default has two effects: (1) date formatters which are created with +alloc/-init will be 10.4-style; (2) date formatters which are unarchived from either non-keyed or keyed archives will be converted to 10.4-style if the archived formatter has uncustomized format string -- most of those found in IB's NSNumberFormatter inspector -- at unarchive time.
NSIndexPath
NSIndexPath is a new class for representing a sequence of indexes; its primary purpose is to encapsulate the information needed to navigate down a tree of objects. NSTreeController, a new class in the AppKit, makes use of NSIndexPath.
The designated initializer for NSIndexPath is:
- (id)initWithIndexes:(unsigned int *)indexes length:(unsigned int)length;
and the primitive accessors are:
- (unsigned int)indexAtPosition:(unsigned int)position;
- (unsigned int)length;
Please refer to NSIndexPath.h for the rest of the API.
Key-Value Coding and Observing for Sets (Section added since WWDC)
Mac OS 10.3 introduced key-value observing (KVO), a mechanism by which one object can observe the properties, including ordered to-many relationships, of another. It also introduced explicit support for ordered to-many relationships to the existing key-value coding (KVC) mechanism. Because some applications, especially those that use CoreData, need to represent unordered to-many relationships, support for unordered to-many relationships has been added to KVC/KVO. This support takes the form of additions to KVC's -valueForKey: method, new KVC methods, and new KVO methods.
To explicitly support nonmutating access of unordered to-many relationships, -[NSObject(NSKeyValueCoding) valueForKey:], an existing method, now finds KVC-compliance methods that correspond to the NSSet primitives. After looking for array accessor methods (as in Mac OS 10.3) but before looking for instance variables (as in Mac OS 10.3), it now looks for set accessor methods. From NSKeyValueCoding.h's comments for -valueForKey:
"3 (introduced in Mac OS 10.4). Otherwise (no simple accessor method or set of array access methods is found), searches the class of the receiver for a threesome of methods whose names match the patterns -countOf<Key>, -enumeratorOf<Key>, and -memberOf<Key>: (corresponding to the primitive methods defined by the NSSet class). If all three such methods are found a collection proxy object that responds to all NSSet methods is returned. Each NSSet message sent to the collection proxy object will result in some combination of -countOf<Key>, -enumeratorOf<Key>, and -memberOf<Key>: messages being sent to the original receiver of -valueForKey:."
Your class' implementations of such KVC-compliance methods should have the same signatures as:
- (unsigned int)countOf<Key>;
- (NSEnumerator *)enumeratorOf<Key>;
- (id)memberOf<Key>;
As has been the case for ordered relationships, it is reasonable and usually more convenient to merely implement a KVC-compliance accessor method for the entire collection. For an unordered relationship the accessor method should have the same signature as:
- (NSSet *)<key>;
To support mutation of unordered to-many relationships, two new methods have been added to NSObject(NSKeyValueCoding):
- (NSMutableSet *)mutableSetValueForKey:(NSString *)key;
- (NSMutableSet *)mutableSetValueForKeyPath:(NSString *)keyPath;
Given the key or key path that identifies a relationship, return an object that can be used to mutate the relationship. Several KVC-compliance method name patterns are recognized:
- (void)add<Key>Object:(id)objectToAdd;
- (void)remove<Key>Object:(id)objectToRemove;
- (void)add<Key>:(NSSet *)objectsToAdd;
- (void)remove<Key>:(NSSet *)objectsToRemove;
- (void)intersect<Key>:(NSSet *)intersectionObjects;
- (void)set<Key>:(NSSet *)replacementObjects;
Typically your class will implement one add and one remove method for a particular key. There may be substantial performance benefits to implementing the NSSet-taking ones. See NSKeyValueCoding.h's comments for details.
-mutableSetValueForKeyPath: follows the pattern established by existing KVC key path-taking methods; basically it just invokes [[self valueForKey:firstKeyPathComponent] mutableSetValueForKeyPath:theRestOfTheKeyPath].
To support observation of unordered to-many relationship mutations, a new enumeration has been added, and a pair of methods have been added to NSObject(NSKeyValueObserverNotification):
typedef enum {
// The set representing an unordered to-many relationship is being changed using NSMutableSet's
-unionSet:, -minusSet:, -intersectSet:, or -setSet: method, or something that has the same
semantics.
NSKeyValueUnionSetMutation = 1,
NSKeyValueMinusSetMutation = 2,
NSKeyValueIntersectSetMutation = 3,
NSKeyValueSetSetMutation = 4
} NSKeyValueSetMutationKind;
- (void)willChangeValueForKey:(NSString *)key withSetMutation:(NSKeyValueSetMutationKind)mutationKind
usingObjects:(NSSet *)objects;
- (void)didChangeValueForKey:(NSString *)key withSetMutation:(NSKeyValueSetMutationKind)mutationKind
usingObjects:(NSSet *)objects;
Given a key that identifies an unordered to-many relationship, prepare to send, and send, respectively, an -observeValueForKeyPath:ofObject:change:context: message. The passed-in mutation kind corresponds to an NSMutableSet method. The passed-in set must contain the set that would be passed to the corresponding NSMutableSet method. Invocations of these methods must always be paired, with identical arguments. The change dictionaries in notifications resulting from use of these methods always contain an NSKeyValueChangeKindKey entry. Its value will depend on the passed-in mutationKind value:
- NSKeyValueUnionSetMutation -> NSKeyValueChangeInsertion
- NSKeyValueMinusSetMutation -> NSKeyValueChangeRemoval
- NSKeyValueIntersectSetMutation -> NSKeyValueChangeRemoval
- NSKeyValueSetSetMutation -> NSKeyValueChangeReplacement
The change dictionary may also contain optional entries:
- The NSKeyValueChangeOldKey entry, if present (only for for NSKeyValueChangeRemoval and NSKeyValueChangeReplacement), contains the set of objects that were removed.
- The NSKeyValueChangeNewKey entry, if present (only for NSKeyValueChangeInsertion and NSKeyValueChangeReplacement), contains the set of objects that were added.
New Overrides of Public Key-Value Coding Methods By NSSet (Section added since WWDC)
For consistency with NSArray's existing KVC behavior, NSSet now overrides two public KVC methods:
- (id)valueForKey:(NSString *)key;
Return a set containing the results of invoking -valueForKey: on each of the receiver's members. The returned set might not have the same number of members as the receiver. The returned set will not contain any elements corresponding to instances of -valueForKey: returning nil (in contrast with -[NSArray(NSKeyValueCoding) valueForKey:], which may put NSNulls in the arrays it returns).
For backward binary compatibility, this method will merely invoke NSObject's default implementation of -valueForKey: in applications linked against Mac OS 10.3 or earlier.
- (void)setValue:(id)value forKey:(NSString *)key;
Invoke -setValue:forKey: on each of the receiver's members.
For backward binary compatibility, this method will merely invoke NSObject's default implementation of -setValue:forKey: in applications linked against Mac OS 10.3 or earlier.
Support for New Method Name Patterns in Key-Value Coding for Arrays (Section added since WWDC)
-[NSObject(NSKeyValueCoding) valueForKey:], an existing method, will now find methods whose names conform to the pattern:
- (NSArray *)<key>AtIndexes:(NSIndexSet *)indexes;
in addition to the -objectIn<Key>AtIndex: pattern supported in Mac OS 10.3. If the same class has both a -<key>AtIndexes: and an -objectIn<Key>AtIndex: method, automatic collection proxies returned by -valueForKey: will invoke whichever is best for performance, depending on the message that was sent to the collection proxy.
-[NSObject(NSKeyValueCoding) mutableArrayValueForKey:], an existing method, will now find methods whose names conform to the patterns:
- (void)insert<Key>:(NSArray *)objectsToAdd atIndexes:(NSIndexSet *)indexes;
- (void)remove<Key>AtIndexes:(NSIndexSet *)indexes;
- (void)replace<Key>AtIndexes:(NSIndexSet *)indexes with<Key>:(NSArray *)replacementObjects;
in addition to the -insertObject:in<Key>AtIndex:, -removeObjectFrom<Key>AtIndex:, and -replaceObjectIn<Key>AtIndex:withObject: patterns supported in Mac OS 10.3. If the same class has both an index-set-taking and an index-taking insertion, removal, or replacement method, automatic mutable collection proxies returned by -valueForKey: will invoke whichever is best for performance, depending on the message that was sent to the mutable collection proxy.
New NSIndexSet-Taking Method in NSArray
A new method has been added to NSArray:
- (NSArray *)objectsAtIndexes:(NSIndexSet *)indexes;
Return an array of the objects at the indexes, or throw an NSRangeException if the largest index in the set is greater than the receiving array's count.
New NSIndexSet-Taking Methods in NSMutableArray
New methods have been added to NSMutableArray:
- (void)insertObjects:(NSArray *)objects atIndexes:(NSIndexSet *)indexes;
Insert the objects at the indexes, or throw an NSRangeException if the largest index in the set is not less than the sum of the counts of the receiving array and the passed-in array, or throw an NSInvalidArgumentException if the passed-in NSIndexSet and NSArray don't have the same count. The passed-in indexes are the indexes at which the inserted objects are to be located after the entire operation is complete.
- (void)removeObjectsAtIndexes:(NSIndexSet *)indexes;
Remove the indexed objects, or throw an NSRangeException if the largest index in the set is greater than the receiving array's count. The passed-in indexes are the indexes at which the removed objects were before the operation.
- (void)replaceObjectsAtIndexes:(NSIndexSet *)indexes withObjects:(NSArray *)objects;
Replace the indexed objects with other objects, or throw an NSRangeException if the largest index in the set is greater than the receiving array's count., or throw an NSInvalidArgumentException if the passed-in NSIndexSet and NSArray don't have the same count.
Explicit Overriding of Key-Value Observer Registration Methods by NSArray and NSSet
NSArrays and NSSets are not observable, so these methods:
- (void)addObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath
options:(NSKeyValueObservingOptions)options context:(void *)context;
- (void)removeObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath;
raise exceptions when invoked on NSArrays and NSSets. Instead of observing an array or set, observe the ordered or unordered to-many relationship for which the array or set is the collection of related objects. For NSArrays, this behavior is unchanged since Mac OS 10.3; the only change is the explicit declaration of the exception-throwing method overrides in NSKeyValueObserving.h. For NSSets, this behavior is new since Mac OS 10.3; for backward binary compatibility, the exception-throwing method overrides merely invoke NSObject's default implementations in applications linked against Mac OS 10.3 or earlier.
Deprecation of Stored Key-Value Coding Methods
In Mac OS 10.3, the documentation for each of these methods:
+ (BOOL)useStoredAccessor;
- (id)storedValueForKey:(NSString *)key;
- (void)takeStoredValue:(id)value forKey:(NSString *)key;
claimed:
Note: This method is not deprecated as of Mac OS X v10.3, but may be deprecated in favor of a new method in a future release of Mac OS X.
These methods are now deprecated. Their implementations are virtually unchanged since Mac OS 10.3, and you may continue to use them, but their implementations will not be improved to keep pace with improvements to key-value coding and observing. -storeValueForKey: and -takeStoredValue:forKey: are not invoked from anywhere within Cocoa, as in Mac OS 10.3 and earlier. +useStoredAccessor is only invoked from within -storeValueForKey: and -takeStoredValue:forKey:, as in Mac OS 10.3 and earlier.
If you are using the new NSManagedObject class, use its -primitiveValueForKey: and -setPrimitiveValue:forKey: methods instead.
Publication of String Constants for Key-Value Coding Array Operator Names
Strings for the names of array operators, which have been supported by key-value coding since Mac OS 10.3, have been published:
NSString *NSAverageKeyValueOperator;
NSString *NSCountKeyValueOperator;
NSString *NSDistinctUnionOfArraysKeyValueOperator;
NSString *NSDistinctUnionOfObjectsKeyValueOperator;
NSString *NSMaximumKeyValueOperator;
NSString *NSMinimumKeyValueOperator;
NSString *NSSumKeyValueOperator;
NSString *NSUnionOfArraysKeyValueOperator;
NSString *NSUnionOfObjectsKeyValueOperator;
The values of these do not include '@' array operator prefixes.
Bug Fix in Key-Value Coding
In Mac OS 10.3, -[NSArray valueForKeyPath:]'s support for operators had bugs that caused crashing, hanging, and exception throwing when the @sum, @max, or @min operator was applied to an array containing an element that returned nil for the keyed value. For example:
[[NSArray arrayWithObject:[NSDictionary dictionary]] valueForKeyPath:@"@sum.anyOldKey"]
would crash or hang (because the nil that the dictionary returned from -valueForKey:@"anyOldKey" was mishandled). This problem has been fixed.
In both Mac OS 10.3 and Mac OS 10.4 the support for the @count and @avg operators do not take into account returned nils. This is true regardless of both -[NSArray valueForKeyPath:] and -[NSSet valueForKeyPath:].
Bug Fix in Key-Value Observing for -description Methods (Section added since WWDC)
In Mac OS 10.3, -description messages sent to any observed object would always result in the invocation of a private method that behaved more-or-less like -[NSObject description], even if -description was overridden by the receiver's class, unless key-value observing autonotification was disabled for all observed properties by overriding of +automaticallyNotifiesObserversForKey:. This was a bug and has been fixed. Your class' override of -description will now be invoked even if the receiver is observed and its "isa is swizzled" by KVO's autonotification machinery.
-[NSObject description] itself, which is primarily for use in debugging, does not attempt to hide isa-swizzling from you. For example, when -[NSObject description] would otherwise return something like "<Foo: 0x301780>" it will now return something like "<NSKVONotifying_Foo: 0x301780>" if the object's isa has been swizzled. If you see this while debugging and are surprised to see that an object is being observed you can send the object an -observationInfo message and view the description of the results. For example, a GDB command like 'po [mySurprisinglyObservedObject observationInfo]' will output a list of observances on that object.
Bug Fix in Key-Value Observing for Nested WillChange/DidChange Sequences (Section added since WWDC)
In Mac OS 10.3 there was a bug in which nested willChange/didChange sequences would result in observer notifications being sent too early. For example:
[observedObject addObserver:observer forKeyPath:@"someProperty" options:0 context:NULL];
[observedObject willChangeValueForKey:@"someProperty"];
[observedObject willChangeValueForKey:@"someProperty"];
[observedObject didChangeValueForKey:@"someProperty"];
// Observer is sent two -observeValueForKeyPath:... messages. It should be sent one.
[observedObject didChangeValueForKey:@"someProperty"];
// Observer is sent zero -observeValueForKeyPath:... messages.
// It should be sent one (unless the first -observeValueForKeyPath:... invoked
// [observedObject removeObserver:observer forKeyPath:@"someProperty"]).
This bug has been fixed. It was most noticeable when the observer did something like removing itself as an observer in response to the first observer notification, with the expectation that it would not receive a second.
NSAppleEventDescriptor Changes
+appleEventWithEventClass:eventID:targetDescriptor:returnID:transactionID: and -initWithEventClass:eventID:targetDescriptor:returnID:transactionID:] have each been updated to accept a nil target descriptor argument. The resulting Apple event descriptor has no keyAddressAttr attribute.
Key Value Observing and Cocoa Scripting
In Mac OS 10.3, Cocoa's scripting support did not use Key Value Coding methods introduced in Panther like -setValue:forKey: and -mutableArrayValueForKey:, so changes to model objects made by AppleScripts were not observable using automatic Key Value Observing. This has been fixed. Cocoa's scripting support now invokes -setValue:forKey: instead of -takeValue:forKey: unless the container in question overrides -takeValue:forKey:, in which case -takeValue:forKey: will be invoked for backward binary compatibility. The implementations of -insertValue:atIndex:inPropertyWithKey:, -removeValueAtIndex:fromPropertyWithKey:, and -replaceValueAtIndex:inPropertyWithKey:withValue: have been updated to invoke -mutableArrayValueForKey: and mutate the result if no corresponding scripting-KVC-compliant method (insertIn<Key>:atIndex:, -removeFrom<Key>AtIndex:, or replaceIn<Key>:atIndex:, respectively) is found.
Bug Fixes in NSScriptCommand Suspending and Resuming
In Mac OS 10.3, -[NSScriptCommand suspendExecution] could malfunction if the corresponding invocation of resumeExecutionWithResult:] was done very quickly in a different thread, leading to crashes. This bug has been fixed.
Execution of multiple-receiver commands could result in the command being sent to the same receiver repeatedly, if the receiver's command handler suspending the command. This bug has been fixed.
Cocoa Scripting Support for .sdef Files
Cocoa now supports declaration of scriptability in .sdef files instead of .scriptSuite/.scriptTerminology files. This support is incomplete in several ways in the WWDC 2004 seed of Tiger, but here are some interesting facts:
- 'man sdef' to find out what the file format is all about. See the .sdef files in Foundation and AppKit's Resources directories for examples. Also, check the Apple Developer Connection site at <connect.apple.com> for information about WWDC 2004 Session 430, "Advances in Cocoa Scripting," for more information.
- .sdefs are loaded instead of .scriptSuite/.scriptTerminology files only if the app is linked against Tiger or better and the app's main bundle includes at least one .sdef file. This will likely change so that Cocoa's decision to load .sdef instead of .scriptSuite/.scriptTerminology files depends on a new "OSAScriptingDefinition" Info.plist entry.
- A big difference between Cocoa's .sdef parsing and the version of sdp that came with Panther is that the name of the Cocoa attribute that identifies a property's KVC key is "key," not "method."
- Other big differences: use "specifier" now, not "object," and "location specifier" instead of "location."
- The color class in NSCoreSuite.[scriptSuite|scriptTerminology] won't be declared as a class in Cocoa's own .sdef files. One of Cocoa's .sdef files just declares a simple value type, "color." Apple event descriptors of several types are convertable to NSColors.
- The "file" type that .sdef has always had corresponds to the NSURL class.
- The "any" type that .sdef has always had corresponds to the NSAppleEventDescriptor class, not NSObject.
- The Objective-C implementation class of the "item" scriptable class is NSObject, not the artificial AbstractObject type that was used in .scriptSuite files.
- The standard for document classes has changed, to be consistent with the Scripting Interface Guidelines. Every document class should now have a read-only "file" property of type "file," instead of a read-write "path" property of string type. Document class' "name" property should now be read-only instead of read-write.
- The Cocoa key for the "name" property should be "displayName," not "lastComponentOfFileName." -[NSDocument(Scripting) lastComponentOfFileName] is probably going to be deprecated.
- Various window class properties have been removed to bring Cocoa in line with the new Scripting Interface Guidelines. Window names are now read-only. "Miniaturizable" and "miniaturized" have been renamed to "minimizable" and "minimized."
- The text class' "size" property's type is now real instead of integer.
- The text attachment class now has a read-only "file" property of type "file" instead of read-write "file name" string property.
- The open command's direct parameter is of type "list of file."
- The print command's direct parameter is of type "list of file | specifier," so you can either print files or documents (this may not work very well in the WWDC 2004 seed of Tiger).
- The close command's "saving in" parameter and the save command's "in" parameter are now of type "file."
- Various script command handler methods in AppKit have been updated to deal with NSURL arguments, because that's what "file" Apple event descriptors get converted to.
- The "with data" parameter of the make command has been renamed to "with contents."
- NSScriptClassDescription's -suiteName and -className return the human-readable strings by which .sdefs are keyed, when the class is declared in an .sdef.
- Ditto for NSScriptCommand's -suiteName and -commandName.
- NSScriptSuiteRegistry's -suiteNames returns the same sort of human-readable strings for .sdef-declared stuff, and -appleEventCodeForSuite:, -bundleForSuite:, -classDescriptionsInSuite:, and -commandDescriptionsInSuite: take the same sort of strings.
NSNetServices finite resolves
Leaving resolves on NSNetServices open generates (largely) unnecessary network traffic - resolves tend to happen either very quickly, or not at all. To this end, we are deprecating the original open-ended -resolve method in favor of:
/* Starts a resolve for the NSNetService of a finite duration. If your delegate is called before the
timeout expires, the resolve can be considered successful. If the resolve times out, your
netService:didNotResolve: callback will be called with the appropriate error dictionary.
*/
- (void)resolveWithTimeout:(NSTimeInterval)timeout;
This will allow a resolve of finite duration, limiting network traffic. For applications linked on Tiger, the now-deprecated -resolve will call -resolveWithTimeout with a timeout of 5 seconds (generally if something is going to happen, it'll happen within the first half-second or so). For applications linked on Panther running on Tiger, -resolve will call -resolveWithTimeout: with a timeout in the distant future.
NSNetServices TXT record support
In Tiger, we have deprecated the protocolSpecificInformation calls that work with NSStrings in favor of:
/* Allows the developer to use an NSData containing arbitrary bytes as the TXT record.
Returns YES if the data is successfully set as the TXT record. Returns NO if it cannot be set.
*/
- (BOOL)setTXTRecordData:(NSData *)recordData;
- (NSData *)TXTRecordData;
Developers checking to see if this is a key-value style text record can use the following API for conversion attempts:
/* TXT record data can be presented either as an NSData or an NSDictionary of key-value pairs.
It's very useful to be able to convert between the two. NSNetService provides a pair of class methods
to do this conversion. Each returns nil in the event that the conversion cannot take place.
*/
+ (NSDictionary *)dictionaryFromTXTRecordData:(NSData *)txtData;
+ (NSData *)dataFromTXTRecordDictionary:(NSDictionary *)txtDictionary;
The primary utility of this is for use in netService:didUpdateTXTRecordData:.
Applications linked on Panther or Jaguar and running on Tiger will continue to be able to interoperate with the same application running on other Panther or Jaguar machines on the network.
NSNetServices TXT record update observation
In the old behavior, an additional netService:didResolve: delegate method would be called when the protocolSpecificInformation updated. This requires leaving the resolve open, which generates unnecessary network traffic.
On Tiger, if a delegate implements the appropriate delegate method, they will get the new behavior instead, which does not require that a resolve be open at all (it will generate some network traffic, but the intent is that it will be less traffic).
First, on NSNetService itself, two new methods:
/* These calls control whether an NSNetService will watch for TXT record updates, notification
of which would be delivered to the delegate on the netServiceDidUpdateTXTRecord: method in the
NSNetServiceDelegateMethods category.
*/
- (void)startMonitoring;
- (void)stopMonitoring;
And on the NSNetServiceDelegateMethods category:
/* Called to inform the delegate that the TXT record associated with the sending NSNetService
object has updated. txtData contains the new TXT record as an NSData.
*/
- (void)netService:(NSNetService *)sender didUpdateTXTRecordData:(NSData *)txtData;
This method delivers the updated TXT record as an NSData to the delegate.
NSNetServices Publishing
There is a new delegate method indicating that the net service was successfully published:
- (void)netServiceDidPublish:(NSNetService *)sender;
An error (delivered on the current error delegate method) is triggered in one of two cases: (1) Timeout has been reached, or (2) Name collision has occurred.
There is a new error code for the timeout case:
NSNetServicesTimeoutError = -72007
NSDirectoryEnumerator (Section added since WWDC)
A long-standing bug in NSDirectoryEnumerator's -directoryAttributes method has been fixed. In Tiger, it now behaves as documented, returning the attributes of the directory at which the enumeration began.
For the common case of enumerating a directory without asking for attributes, performance is much improved over previous versions of OS X.
Performance Improvement in Keyed Archiving
In Mac OS X 10.4, there has been a significant performance improvement in creating keyed archives which have lots of array objects.
Performance Improvement in Notification Posting
In Mac OS X 10.4, there has been a significant performance improvement in posting notifications for which there are no observers. The performance of all posting has also generally improved.
NSNumber (Section added since WWDC)
Since NSNumbers are immutable, we now cache and reuse some "popular" numbers in order to reduce allocation activity. This means that some distinct NSNumber allocation calls might return the same exact object, with a incremented reference count. Applications should not rely on getting distinct objects from separate NSNumber creation requests.
In Tiger "popular" numbers include -1..12, although this might very well change at any point, including in a software update.
Comparisons against NAN (not a number) now work correctly in that no number is equal to NAN (including +[NSDecimalNumber notANumber]), except NAN itself (which has to be special case, since object equality must hold). Comparison against NAN will also give deterministic results; however, no assumptions should be made on the ordering, and the results may vary between system releases.
NSString
NSString's getCString:maxLength: and getCString:maxLength:range:remainingRange: methods will no longer raise if the provided buffer size is not large enough. Note that these did not raise in all cases.
More NSString and NSMutableString methods now detect out of bounds indexes and invalid ranges. One case which wasn't properly being detected so far was where the location and/or length were so large that the sum ended up being less than the length of the string. For applications linked on Tiger, this error will cause an exception after logging the problem in the console; for older apps, for compatibility, we just log once, but don't raise. Note that even if the old behavior seems work under a set of circumstances, it's actually just getting lucky and in many cases might end up crashing at some point. So any instances of these logs should be fixed.
If a call to componentsSeparatedByString: resulted in an array with one string, equal to the receiver, the one string was sometimes not copied and its value could change when the receiver string was subsequently edited. This has been fixed.
NSString cString API deprecation
In the continuing effort to deprecate cString methods without encoding arguments, NSString now has the following new API. Note that this new API also provides NSError returns as a way to provide more info about failures in cases where it might matter to the user, for instance, for reading/writing.
The following return the maximum and exact number of bytes needed to store the receiver in the specified encoding in non-external representation. The first one is O(1), while the second one is O(n). These do not include space for a terminating null. The second one will return 0 if the conversion to the specified encoding is not possible; the first one doesn't check.
- (unsigned)maximumLengthOfBytesUsingEncoding:(NSStringEncoding)enc;
- (unsigned)lengthOfBytesUsingEncoding:(NSStringEncoding)enc;
Methods to convert NSString to a NULL-terminated cString using the specified encoding. Note, these are the "new" cString methods, and are not deprecated like the older cString methods which do not take encoding arguments.
- (const char *)cStringUsingEncoding:(NSStringEncoding)encoding;
- (BOOL)getCString:(char *)buffer maxLength:(unsigned)maxBufferCount encoding:(NSStringEncoding)encoding;
The following are new and improved cString methods which take explicit encoding arguments.
- (id)initWithCString:(const char *)nullTerminatedCString encoding:(NSStringEncoding)encoding;
+ (id)stringWithCString:(const char *)cString encoding:(NSStringEncoding)enc;
This following is exposed in Tiger, but has actually been around since 10.3 and so is available for use on 10.3.
- (id)initWithBytesNoCopy:(void *)bytes length:(unsigned)len
encoding:(NSStringEncoding)encoding freeWhenDone:(BOOL)freeBuffer;
These use the specified encoding. If nil is returned, the optional error return indicates problem that was encountered (for instance, file system or encoding errors).
- (id)initWithContentsOfURL:(NSURL *)url encoding:(NSStringEncoding)enc error:(NSError **)error;
- (id)initWithContentsOfFile:(NSString *)path encoding:(NSStringEncoding)enc error:(NSError **)error;
+ (id)stringWithContentsOfURL:(NSURL *)url encoding:(NSStringEncoding)enc error:(NSError **)error;
+ (id)stringWithContentsOfFile:(NSString *)path encoding:(NSStringEncoding)enc error:(NSError **)error;
The following try to determine the encoding, and return the encoding which was used. Note that these methods might get "smarter" in subsequent releases of the system, and use additional techniques for recognizing encodings. If nil is returned, the optional error return indicates problem that was encountered (for instance, file system or encoding errors).
- (id)initWithContentsOfURL:(NSURL *)url usedEncoding:(NSStringEncoding *)enc error:(NSError **)error;
- (id)initWithContentsOfFile:(NSString *)path usedEncoding:(NSStringEncoding *)enc error:(NSError **)error;
+ (id)stringWithContentsOfURL:(NSURL *)url usedEncoding:(NSStringEncoding *)enc error:(NSError **)error;
+ (id)stringWithContentsOfFile:(NSString *)path usedEncoding:(NSStringEncoding *)enc error:(NSError **)error;
The following write to specified url using the specified encoding. The optional error return is to indicate file system or encoding errors.
- (BOOL)writeToURL:(NSURL *)url atomically:(BOOL)useAuxiliaryFile
encoding:(NSStringEncoding)enc error:(NSError **)error;
- (BOOL)writeToFile:(NSString *)path atomically:(BOOL)useAuxiliaryFile
encoding:(NSStringEncoding)enc error:(NSError **)error;
The following methods are deprecated and should not be used. They will be removed from the headers as soon as practical:
- (const char *)cString;
- (const char *)lossyCString;
- (unsigned)cStringLength;
- (void)getCString:(char *)bytes;
- (void)getCString:(char *)bytes maxLength:(unsigned)max;
- (void)getCString:(char *)bytes maxLength:(unsigned)max range:(NSRange)rg remainingRange:(NSRangePointer)rem;
+ (id)stringWithCString:(const char *)bytes length:(unsigned)length;
+ (id)stringWithCString:(const char *)bytes;
+ (id)stringWithContentsOfFile:(NSString *)path;
+ (id)stringWithContentsOfURL:(NSURL *)url;
- (id)initWithContentsOfFile:(NSString *)path;
- (id)initWithContentsOfURL:(NSURL *)url;
- (id)initWithCStringNoCopy:(char *)bytes length:(unsigned)length freeWhenDone:(BOOL)freeBuffer;
- (id)initWithCString:(const char *)bytes length:(unsigned)length;
- (id)initWithCString:(const char *)bytes;
- (BOOL)writeToFile:(NSString *)path atomically:(BOOL)flag;
- (BOOL)writeToURL:(NSURL *)url atomically:(BOOL)flag;
NSAttributedString
Attributed string methods such as attribute:atIndex:effectiveRange: used to raise NSInternalInconsistencyException on out-of-bounds accesses; they have now been switched to raising NSRangeException as documented.
-[NSMutableAttributedString initWithString:attributes:] could create a corrupt attributed string when initialized with a string of non-zero length. This has been fixed.
There is now a CFAttributedString, which is toll-free bridged to NSAttributedString.
NSAttributedString mutation of attributes warning (Section added since WWDC)
Once an attribute value is set in an attributed string, the attribute value should not be modified behind the attributed string. So any modification to the value should be performed by a new set operation (using any one of the attribute mutation methods in NSMutableAttributedString), with the new value.
One reason for this is that the attribute values are retained by the attributed string, and how the value propagates through an attributed string as the attributed string is further edited is not predictable. If you change the value, you might be editing more portions of the attributed string than you thought. In fact the value could appear on pieces of the attributed string in the undo stack, or might have even been copied to a totally different document. It's possible that this is not a concern in some instances.
Another reason for this limitation is that attributed strings do caching and uniquing of attributes (this actually occurs more at the AppKit level, but that is an implementation detail). The uniquing assumes attribute values aren't changing, that is, that isEqual: and hash on attribute values will not change as long as the attribute value is in an attributed string.
If you must change attribute values, two possible suggestions are:
- Use an attribute value whose isEqual: and hash do not depend on the values you are modifying. You might need to create a wrapper object for this. Or,
- Use indirection; use the attribute value as a lookup key into a table where the actual value can be changed. For instance, this might be the appropriate approach for having a "stylesheet" like attribute.
This warning has always been applicable, but it's more true in Tiger, since NSAttributedString now hashes more of the values inside an attribute dictionary when uniquing it. This has led to problems in a few applications where some attribute values were being mutated, or worse, corrupted or freed (but previously going unnoticed). As a temporary workaround to this issue, a default named NSPreTigerAttributedStringHash is available; setting this to YES for your application will cause NSAttributedString to use the same hashing algorithm as in Panther. This can help diagnose problems, and even bring an app back to life. This default should not be used as a long term solution though.
NSCocoaErrorDomain
In order to formalize the kind of errors returned by AppKit and Foundation frameworks, there is now a new error domain:
NSString *const NSCocoaErrorDomain;
This represents the domain for errors returned from most Cocoa subsystems. Errors in this domain have reasonable and localized user-readable error messages that are good enough to be displayed in alerts and other user interfaces. With a few existing exceptions, AppKit, Foundation, and CoreData APIs are expected to return NSErrors in this domain; in some cases lower level errors will be packaged as the underlying error.
NSError (Section updated since WWDC)
In order to enable presenting more reasonable user panels for various errors, NSError now has the ability to return the secondary message along with the titles of button(s) appropriate for an alert. With this, even a low level error (say, from NSData) is able to return an NSError that can be usefully presented to the user:
localizedDescription: "Could not save file 'Letter' in folder 'Documents' because the volume 'MyDisk' doesn't have enough space."
localizedRecoverySuggestion: "Remove files from the disk and try again."
localizedRecoveryOptions: nil (so, "OK")
A higher level (NSDocument or bindings, for instance), would do better by extending this, say by providing additional options (buttons) to try remedying the situation, retrying the save elsewhere, etc.
The following method returns the string that can be displayed as the "informative" (aka "secondary") message on an alert panel. Returns nil if no such string is available. Default implementation of this will pick up the value of the NSLocalizedRecoverySuggestionKey from the userInfo dictionary.
- (NSString *)localizedRecoverySuggestion;
The following method returns titles of buttons that are appropriate for displaying in an alert. These should match the string provided as a part of localizedRecoverySuggestion. The first string would be the title of the right-most and default button, the second one next to it, and so on. If used in an alert the corresponding default return values are NSAlertFirstButtonReturn + n. Default implementation of this will pick up the value of the NSLocalizedRecoveryOptionsKey from the userInfo dictionary. nil return usually implies no special suggestion, which would imply a single "OK" button.
- (NSArray *)localizedRecoveryOptions;
The following method returns just the reason for the failure, without mentioning the operation. This can be useful when the caller has a better idea of what the operation is, but still wants to leverage NSError's localized error string. Note that this may return nil, which indicates NSError had no idea why the operation failed:
- (NSArray *)localizedFailureReason;
In addition to the above, NSError now also has the ability to attempt recovery from the error. The following method returns an object that conforms to the NSErrorRecoveryAttempting informal protocol:
- (id)recoveryAttempter;
The default implementation of this method merely returns [[self userInfo] objectForKey:NSRecoveryAttempterErrorKey]:
NSString *const NSRecoveryAttempterErrorKey;
If non-nil, the recovery attempter must be an object that can correctly interpret an index into the array returned by -localizedRecoveryOptions.
The NSErrorRecoveryAttempting informal protocol has two methods:
- (void)attemptRecoveryFromError:(NSError *)error optionIndex:(unsigned int)recoveryOptionIndex
delegate:(id)delegate didRecoverSelector:(SEL)didRecoverSelector contextInfo:(void *)contextInfo;
Given that an error alert has been presented document-modally to the user, and the user has chosen one of the error's recovery options, attempt recovery from the error, and send the selected message to the specified delegate. The option index is an index into the error's array of localized recovery options. The method selected by didRecoverSelector must have the same signature as:
- (void)didPresentErrorWithRecovery:(BOOL)didRecover contextInfo:(void *)contextInfo;
The value passed for didRecover must be YES if error recovery was completely successful, NO otherwise.
- (BOOL)attemptRecoveryFromError:(NSError *)error optionIndex:(unsigned int)recoveryOptionIndex;
Given that an error alert has been presented applicaton-modally to the user, and the user has chosen one of the error's recovery options, attempt recovery from the error, and return YES if error recovery was completely successful, NO otherwise. The recovery option index is an index into the error's array of localized recovery options.
See the "NSResponder-Based Error Presentation" section in the AppKit release notes for information about how Cocoa itself uses error recovery attempters.
A change from Panther is that NSError will now pass by copy over distributed objects, unless the argument is specified to be "byref". It used to always go by reference.
Additional NSError notes (Section added since WWDC)
Cocoa's conventions for NSError returns include:
- NSError return should always be present in addition to a simpler way to indicate failure, for instance, via the return value of the function (NO, nil, NULL, or whatever's appropriate). NSErrors are typically returned via a "by-reference" argument, that is, pointer to an NSError object.
- The NSError argument is "optional." If the caller has specified NULL for the error pointer argument, then don't return it.
- If an failure is indicated in a call, and the caller has passed in a non-NULL error pointer, an NSError must be returned to indicate what went wrong. It's not acceptable to set *errorPtr to nil, say because the exact cause of the error couldn't be determined, or there was no real error.
- If a failure is not indicated, then do not use NSError as a way to communicate other state, such as warnings. On a successful return, *errorPtr is typically not modified; maybe set to NULL.
- NSErrors are not used for programming errors (such as array index out of bounds, invalid parameter value, attempt to mutate immutable object, etc). Cocoa uses exceptions for those.
Two "gotchas" worth pointing out about NSErrors:
The userInfo method might return nil in some cases, for instance if the NSError was created with nil. This means that if you are copying an NSError and adding some new keys to the userInfo dictionary, something like [[error userInfo] mutableCopy] will fail if the dictionary is nil. So, check for nil when doing this.
Another gotcha to point out is with the autoreleased return of NSErrors. If a method calls another method which returns an NSError, and then returns that NSError to its caller, you need to be careful if you happen to add an autorelease pool inside that method, since you might end up releasing the error you got from the nested call.
This of course is the same kind of problem you'd need to watch out for with normal return values; however, it's especially subtle when NSErrors are being returned. That's because NSErrors are secondary return values, so more easily missed. In addition, in most regular testing scenarios error code paths are not tested, which would mean the bug would not be encountered. In fact, you'd end up with a bug which causes a crash only when trying to report an error, which is unfortunate.
The solution of course is to extend the lifetime of the NSError around the destruction of the pool, for instance:
- (BOOL)aMethod:... error:(NSError **)errorPtr {
BOOL success;
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
...
success = [someObj anotherMethod:... error:errorPtr];
...
if (!success && errorPtr) [*errorPtr retain]; // Extend the lifetime of the error
[pool release];
if (!success && errorPtr) [*errorPtr autorelease];
return success;
}
NSData (Section added since WWDC)
The following new methods return optional NSErrors for file reading and writing. As with other NSError-returning methods, an NSError is returned in the case of failure (NO or NULL return), if errorPtr is not NULL. In many cases the returned error is good enough to be presented to the user:
enum { // Options for NSData reading methods
NSMappedRead = 1, // Hint to map the file in if possible
NSUncachedRead = 2 // Hint to get the file not to be cached in the kernel
};
enum { // Options for NSData writing methods
NSAtomicWrite = 1 // Hint to use auxiliary file when saving; equivalent to atomically:YES
};
+ (id)dataWithContentsOfFile:(NSString *)path options:(unsigned)readOptionsMask error:(NSError **)errorPtr;
+ (id)dataWithContentsOfURL:(NSURL *)url options:(unsigned)readOptionsMask error:(NSError **)errorPtr;
- (id)initWithContentsOfFile:(NSString *)path options:(unsigned)readOptionsMask error:(NSError **)errorPtr;
- (id)initWithContentsOfURL:(NSURL *)url options:(unsigned)readOptionsMask error:(NSError **)errorPtr;
- (BOOL)writeToFile:(NSString *)path options:(unsigned)writeOptionsMask error:(NSError **)errorPtr;
- (BOOL)writeToURL:(NSURL *)url options:(unsigned)writeOptionsMask error:(NSError **)errorPtr;
NSAffineTransform (Section added since WWDC)
The NSAffineTransform class implementation moved from AppKit to Foundation. -transformBezierPath:, -set, and -concat methods are now part of a category implemented in AppKit.
Using NSURLRequest for requests with large bodies
Historically, in order to use NSURLRequest and NSURLConnection to perform an HTTP transaction with a large HTTP body, the body had to first be loaded in its entirety in to memory, then the connection could be built and the HTTP transaction could take place. This unfortunately places a large memory burden on such transactions - when uploading large images or files, for instance, memory usage would mushroom for the length of the transaction to hold the entire body contents.
For Tiger, we have made it possible to set the body of an HTTP request as an NSInputStream, which then avoids the memory problem. When the connection is processed, the specified stream is opened and bytes are read a few at a time from the stream to be written to the HTTP server. The new methods both appear in NSURLRequest.h, and are -HTTPBodyStream (on the NSHTTPURLRequest category of NSURLRequest) and -setHTTPBodyStream: (on the NSMutableHTTPURLRequest category of NSMutableURLRequest). To make use of this feature, simply create an NSInputStream to wherever the body data resides (note that because NSInputStream is toll-free bridged to CFReadStream, you may pass a CFReadStreamRef if you prefer), then call -setHTTPBodyStream: on the relevant request.
There are a few caveats when using these methods. First and foremost, once a body stream has been set on a request, it becomes the property of that request and any ensuing connections made from that request. No one else should manipulate it any way. That includes anybody retrieving the stream from an extant NSURLRequest via the -HTTPBodyStream method. Second, the body stream and body data (as set by -setHTTPBody:) are mutually exclusive; setting one will clear the other.
NSUserDefaults (Section added since WWDC)
NSUserDefaults now saves preferences using the binary plist format, rather than XML. This makes preference files smaller, and speeds up read/write times.
Since the binary plist format is supported back to 10.2, this should work in home folders which are shared between systems running 10.4, 10.3, and 10.2. For cases where 10.1 compatibility is needed, there is a boolean default, CFPreferencesWritesXML, which will cause preferences to be saved using the XML format. As with most defaults, it can be set globally or on a per-app basis.
Should you need to rewrite a plist manually for some reason you can either convert it using the plutil command line tool or just open it up and edit it using the Property List Editor application.
Locale support in C library (Section added since WWDC)
In Panther, C library functions which do string manipulations (formatting, scanning, comparisons---functions such as atof(), strtod(), scanf(), printf(), etc) started paying attention to the current POSIX locale as set by setlocale(). For instance, for a European locale, strtod() treats "," as the decimal separator when converting its string argument to a floating point value. Since this change represented a potential compatibility problem for applications, any CoreFoundation (and higher) application had the locale hardwired back to the "C" locale to preserve the previous behavior for these functions.
In Tiger, this compatibility behavior holds true for AppKit-based applications that are linked on Panther or before. Other applications get the new behavior for the C library functions. However, since very few applications ever set the POSIX locale value to anything other than the default, the change in behavior is not likely to be a problem. Changing the user's language in Mac OS X does not automatically cause the POSIX locale to be changed in applications.
Where the new behavior might be more of an issue is frameworks and libraries that are loaded into arbitrary applications or executables; if an executable has called setlocale() to change the current locale in an app, any string manipulation calls from an unsuspecting library or framework might generate unexpected results.
As a solution, functions are being added to the C library in Tiger to enable the caller to explicitly specify the locale for string manipulations. Although the exact solution isn't finalized at the time of this writing, the functions are likely to take the form strtod_l(), that is, the original function name with an "_l" suffix. In addition, a new function uselocale() will likely be added, to enable changing the locale for the current thread only. This will enable clients to set and reset the locale around a bunch of calls in a thread-safe manner.
64-bit Note (Section added since WWDC)
The Foundation framework is not available for use in 64-bit processes in Mac OS X 10.4.
API Deprecations (Section added since WWDC)
The NSArchiver and NSUnarchiver classes and other APIs in NSArchiver.h are not deprecated in this release, but may be in the next release.
The NSCalendarDate class, NSDate categories, and other APIs in NSCalendarDate.h are not deprecated in this release, but may be in the next release.
The NSDecimalNumber and NSDecimalNumberHandler classes, the NSDecimalNumberBehaviors protocol, and other APIs in NSDecimalNumber.h are not deprecated in this release, but may be in the next release. The NSDecimal struct and functions in NSDecimal.h are not deprecated in this release, but may be in the next release. Native long double support in NSNumber in the next release will replace most of the need for NSDecimal and NSDecimalNumber (and be much much faster).
The date/time formatting "locale" constants in NSUserDefaults are not deprecated in this release, but may be in the next release: NSAMPMDesignation, NSDateFormatString, NSDateTimeOrdering, NSEarlierTimeDesignations, NSHourNameDesignations, NSLaterTimeDesignations, NSMonthNameArray, NSNextDayDesignations, NSNextNextDayDesignations, NSPriorDayDesignations, NSShortDateFormatString, NSShortMonthNameArray, NSShortTimeDateFormatString, NSShortWeekDayNameArray, NSThisDayDesignations, NSTimeDateFormatString, NSTimeFormatString, NSWeekDayNameArray, NSYearMonthWeekDesignations.
The number formatting "locale" constants in NSUserDefaults are not deprecated in this release, but may be in the next release:
NSCurrencySymbol, NSDecimalSeparator, NSThousandsSeparator, NSDecimalDigits, NSInternationalCurrencyString, NSPositiveCurrencyFormatString, NSNegativeCurrencyFormatString.
If deprecated, API remains (for a while at least), but does not get any bug fixes, performance enhancements, or other enhancements. Deprecated API constants may not have any values or may not be used by the framework implementation in future versions. Also, deprecated API may not be available in any future 64-bit version of the Foundation framework.
Copyright ©2005 Apple Computer, Inc.