iOS Developer Library Developer
Search
Document Generated: 2015-06-02 19:19:12 -0700
OS X Release Notes Copyright © 2015 Apple Inc. All Rights Reserved.


OS X 10.11 Release Notes for WWDC Seed
Cocoa Foundation Framework



The Foundation Framework is a library of Objective-C classes that provide the infrastructure for object-based applications with or without graphical user interfaces. It is available on OS X and iOS.

You can find release notes for the Application Kit as well as some notes on general backward compatibility issues, version handling, etc, here.

Some of the major topics covered in this document:



Note that even though some APIs and descriptions refer to the APIs in Objective-C, and some others in Swift, in general all Foundation APIs are available in both Objective-C and Swift.




Variable Width Presentation Strings

Framework level support for variable width strings. To exemplify the problem, imagine an iOS app meant to run on different screen sizes and/or different orientations. Now, say there was some text, “Welcome to the Apple Store.” At times, that text may fit perfectly well in the available space. For others, it may be too long and it’d be desirable to shorten it to something like “Welcome."

Our solution is to allow developers/localizers to provide different width-variations for a string in a stringsdict file, the same file meant for different cardinalities (“1 file is selected” vs. “2 files are selected”). The -[NSBundle localizedStringForKey:value:table:] method reads the stringsdict file and creates an NSString that knows about the different variations.

We have a single method, variantFittingPresentationWidth: on NSString. It selects the appropriate variation for the given width. The width is just an integer identifying one of the variations. The strings are sorted such that if the width does not exist, the string at the next smaller width is returned or the smallest available if none are smaller. The application can decide on their own contexts, but iOS uses em’s; the number of ‘M' characters for the current system-font that will fit the width of the window.

After obtaining a string from variantFittingPresentationWidth:, the application can invoke the method again on the returned string object for a different width. It effectively “preserves the magic.”

NSString API exposed in NSBundle:
- (NSString *)variantFittingPresentationWidth:(NSInteger)width;
For strings with width variations, such as from a stringsdict file, this method returns the variant at the given width. If there is no variant at the given width, the one for the next smaller width is returned. And if there are none smaller, the smallest available is returned. For strings without variations, this method returns self. The unit that width is expressed in and what width is a measurement of is decided by the application or framework. But it is intended to be some measurement indicative of the context a string would fit best to avoid truncation and wasted space.


The format of the stringsdict file looks like this. We’re also introducing NSStringVariableWidthRuleType.

<key>Welcome</key>
<dict>
    <key>NSStringVariableWidthRuleType</key>
    <dict>
        <key>100</key>
        <string>Hi</string>
        <key>200</key>
        <string>Welcome</string>
        <key>300</key>
        <string>Welcome to the store!</string>
    </dict>
</dict>



NSNotificationCenter

In OS X 10.11 and iOS 9.0 NSNotificationCenter and NSDistributedNotificationCenter will no longer send notifications to registered observers that may be deallocated. If the observer is able to be stored as a zeroing-weak reference the underlying storage will store the observer as a zeroing weak reference, alternatively if the object cannot be stored weakly (i.e. it has a custom retain/release mechanism that would prevent the runtime from being able to store the object weakly) it will store the object as a non-weak zeroing reference. This means that observers are not required to un-register in their deallocation method. The next notification that would be routed to that observer will detect the zeroed reference and automatically un-register the observer. If an object can be weakly referenced notifications will no longer be sent to the observer during deallocation; the previous behavior of receiving notifications during dealloc is still present in the case of non-weakly zeroing reference observers. Block based observers via the -[NSNotificationCenter addObserverForName:object:queue:usingBlock] method still need to be un-registered when no longer in use since the system still holds a strong reference to these observers. Removing observers (either weakly referenced or zeroing referenced) prematurely is still supported. CFNotificationCenterAddObserver does not conform to this behavior since the observer may not be an object.

NSNotificationCenter and NSDistributedNotificationCenter will now provide a debug description when printing from the debugger that will list all registered observers including references that have been zeroed out for aiding in debugging notification registrations. This data is only valid per the duration of the breakpoint since the underlying store must account for multithreaded environments. Wildcard registrations for notifications where the name or object that was passed to the addObserver method family was null will be printed in the debug description as *.

NSNumber

In OS X 10.11 and iOS 9 integral floating point and double numbers will now be created as tagged pointers when possible. This only applies to 64 bit architectures and integral values that can be stored in 56 bits of storage.
NSNumber *tagged = [NSNumber numberWithDouble:5.0];
NSNumber *notTagged = [NSNumber numberWithDouble:4.2];

NSString

Starting with iOS 9 certain strings (ones with a suitable length and encoding) on 64 bit architectures will now be tagged pointers. This matches similar behavior of OS X. Similarly to the OS X targets, passing a tagged NSString to CFStringGetCStringPtr or CFStringGetPascalStringPtr or CFStringGetCharactersPtr will always return NULL. As before it is important to check for the NULL return value and use the corresponding buffer fetching function.
char buffer[BUFSIZE];
const char *ptr = CFStringGetCStringPtr(str, encoding);
if (ptr == NULL) {
if (CFStringGetCString(str, buffer, BUFSIZE, encoding)) ptr = buffer;
}


NSProgress

NSProgress now has a -resume method, which parallels the behavior of the existing -pause method.

NSProgress now supports composition of progress objects into trees both implicitly and explicitly. The implicit approach uses the existing API, such as -becomeCurrentWithPendingUnitCount: and -resignCurrent. The explicit approach uses these new methods:
/* Directly add a child progress to the receiver, assigning it a portion of the receiver's total unit count.
*/
- (void)addChild:(NSProgress *)child withPendingUnitCount:(int64_t)inUnitCount;
/* Return an instance of NSProgress that has been attached to a parent progress with the given pending unit count.
*/
+ (NSProgress *)progressWithTotalUnitCount:(int64_t)unitCount parent:(NSProgress *)parent
pendingUnitCount:(int64_t)portionOfParentTotalUnitCount;
/* Return an instance of NSProgress that has been initialized with -initWithParent:userInfo:. The initializer is passed nil for the parent,
resulting in a progress object that is not part of an existing progress tree. The value of the totalUnitCount property is also set.
*/
+ (NSProgress *)discreteProgressWithTotalUnitCount:(int64_t)unitCount;
This additional API makes it appropriate to expose a progress object as a property of a class, because the progress object can now be retrieved and directly added as a child of another progress object. A new protocol has also been added, NSProgressReporting, which can be adopted to mark a class which reports progress in this way. When creating a progress object that will be vended from your class, you most likely want to use the new +discreteProgressWithTotalUnitCount: method to ensure you are creating a progress object which does not get implicitly attached to the current progress.

The rules about unit counts remain the same: completed and total unit count are in the units of the receiver NSProgress object. When adding a child, the pending unit count given to that child is also in the units of the receiver NSProgress object. NSProgress objects should either have no children and update their completedUnitCount directly (“leafy”), or they should have children and hand out all of their totalUnitCount as pendingUnitCount to those children.

In general, use the explicit addChild methods to compose trees when it is possible to get a progress object as the result of a method or a property of a class. Use the implicit methods to compose trees when the progress object is not directly accessible, for example calling through a proxy object (as NSProgress support over NSXPCConnection works today), or through an existing method which cannot gain an NSProgress return value (eg -[NSData dataWithContentsOfFile:]).

Starting in 10.11 and iOS 9.0, implicitly composed progress objects will no longer split pending unit count amongst themselves. This change was made to ensure that progress did not unintentionally move backwards, due to unanticipated child NSProgress objects being attached to the parent. Instead, the first child will consume the entire pending unit count. This means it is important for a method which supports implicitly attaching NSProgress objects by using +[NSProgress progressWithTotalUnitCount:] should make this call at the very first opportunity inside the implementation of the method. If other methods are invoked first, and they also use implicit progress, then there is the possibility that they will instead consume the pending unit count of the current progress. For example:


/* This method supports implicitly-created progress, and -becomeCurrentWithPendingUnitCount: was called right before this method. */
- (void)myMethod {
[object doSomething];
[object doSomethingElse];
NSProgress *p = [NSProgress progressWithTotalUnitCount:10]; // WRONG - doSomething or doSomethingElse may have already created a progress object
// and attached it to the currentProgress. This progress object will now have no effect.
// work, where p.completedUnitCount is updated
}
- (void)myMethod {
NSProgress *p = [NSProgress progressWithTotalUnitCount:10]; // RIGHT - by creating this first, we ensure that ‘p’ is attached to the currentProgress,
// regardless of what the following two methods do.
[object doSomething];
[object doSomethingElse];
// work, where p.completedUnitCount is updated
}

NSURL New API

Several new file system resource property keys have been added for OSX and/or iOS.

Several new methods have been added:
    -initFileURLWithPath:isDirectory:relativeToURL:
    -initFileURLWithPath:relativeToURL:
    +fileURLWithPath:isDirectory:relativeToURL:
    +fileURLWithPath:relativeToURL:
    -initWithDataRepresentation:relativeToURL:
    +URLWithDataRepresentation:relativeToURL:
    -initAbsoluteURLWithDataRepresentation:relativeToURL:
    +absoluteURLWithDataRepresentation:relativeToURL:
    -dataRepresentation
    -hasDirectoryPath

NSURL Deprecations

In OSX 10.9 and iOS 7.0, we introduced replacement API for the NSURL methods and CFURL functions:
    -stringByAddingPercentEscapesUsingEncoding:
    -stringByReplacingPercentEscapesUsingEncoding:
    CFURLCreateStringByAddingPercentEscapes();
    CFURLCreateStringByReplacingPercentEscapesUsingEncoding();
The old "PercentEscapes" API was deficient and needed to be replaced for four reasons:

1 - Text encoding in URLs should be UTF8 because that is the text encoding the internet standards organizations have standardized on (see ). When the "PercentEscapes" methods and functions were introduced over a decade ago, that wasn't always the case. Because the text encoding is not embedded in the URL strings, using a non-standard text encoding will likely cause interoperability problems unless you know all code using the URL is using the same non-standard text encoding.

2 - With the older APIs, text encodings that are not a superset of ASCII encoding don't always work correctly (a text encoding that is a superset of ASCII encoding is where all 7-bit ASCII characters can be stored in a single 8-bit byte -- those text encodings include MacRoman, WindowsLatin1, ISOLatin1, NextStepLatin, ASCII, and UTF8) -- if you use one of those text encodings to percent-encode a string and then percent-decode the encoded string with the same text encoding, you won't always get the original string.

3 - The "AddingPercentEscapes" methods and functions were originally documented in a way which made it seem you could pass an unpercent-encoded URL string in and get a correctly percent-encoded URL string out. That is not the case because each URL component has it's own rules about what unencoded characters are legal, and which illegal characters must be percent-encoded. The old "AddingPercentEscapes" code has these problems:
    The characters '/', ':', '?' and '@' in the user, password, and host sub-components are not being percent-encoded.
    The characters '[' and ']' in an IPv6 host address in the host sub-component are being percent-encoded.
    The characters ':', ';' and '?' in the path components are not being percent-encoded.
    The characters '"' and '#' are being percent-encoded everywhere in the string.

4 - It's never been documented what characters the "AddingPercentEscapes" methods and functions by default consider legal. That makes it hard to determine what they actually do, and in the case of CFURLCreateStringByAddingPercentEscapes(), how to correctly use the charactersToLeaveUnescaped and legalURLCharactersToBeEscaped arguments.The only ways to find out are to either look at the source code in CFURL.c (which is available open source), or to test by feeding all 7-bit ASCII characters through the API to see what characters are not percent-encode. FWIW: Here are the characters considered legal by default:
    !$&'()*+,-./0123456789:;=?@ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz~
Those characters are not the correct set for any URL component.

The replacement API for those two methods and two functions are:
    -stringByAddingPercentEncodingWithAllowedCharacters:
    -stringByRemovingPercentEncoding
With the predefined character sets:
    +URLUserAllowedCharacterSet
    +URLPasswordAllowedCharacterSet
    +URLHostAllowedCharacterSet
    +URLPathAllowedCharacterSet
    +URLQueryAllowedCharacterSet
    +URLFragmentAllowedCharacterSet
So, we're deprecating the old API. Because the old API has existed since OSX 10.3 and has always existed in iOS, there is a lot of code using it. What follows is a short guide to replacing the old API with the new API.

• "I was using a text encoding other than kCFStringEncodingUTF8 or NSUTF8StringEncoding."

 If the input string only contained 7-bit ASCII characters and the text encoding was a superset of ASCII encoding, the deprecated API using one of those text encodings didn't do anything wrong and switching to kCFStringEncodingUTF8 or NSUTF8StringEncoding will work the same (only it'll be faster); otherwise, you should ask yourself why you thought that text encoding was the correct text encoding to use.

• "I was percent-encoding an entire URL string."

If you thought -stringByAddingPercentEscapesUsingEncoding: or CFURLCreateStringByAddingPercentEscapes() were working for you, they might have been working only by accident.  If you are creating an URL from separate component values, you should use NSURLComponents to construct the URL. NSURLComponents knows now to correctly percent-encode the individual URL component and sub-components. If you need to percent-encode a single URL component or sub-component string (i.e., you aren't going to create a URL or URL string), you should use -stringByAddingPercentEncodingWithAllowedCharacters:. If you need to percent-encode an entire URL string, you can use this code to encode a NSString intended to be a URL (in urlStringToEncode):
        NSString *percentEncodedURLString =
[[NSURL URLWithDataRepresentation:[urlStringToEncode dataUsingEncoding:NSUTF8StringEncoding] relativeToURL:nil] relativeString];
(The CoreFoundation equivalent to URLWithDataRepresentation: is CFURLCreateWithBytes() using the encoding kCFStringEncodingUTF8 with a fall back to kCFStringEncodingISOLatin1 if kCFStringEncodingUTF8 fails.)

• "I wasn't using the percent-escaping functions/methods for anything having to do with URLs -- they just looked like a good way to encode my data as ASCII so I used them."

-stringByAddingPercentEncodingWithAllowedCharacters: will also work for your purposes. You can easily create your own NSCharacterSet and then you'll know exactly what characters are being encoded and what characters are not being encoded. Or if one of the predefined URL character sets works for your purposes, you can use them.

• "My code cannot link with Foundation so it cannot use the new Foundation replacement API."

Unfortunately, you're going to have to keep using the old deprecated API. You will have to be careful to not trip over the problems which made a replacement API necessary. You should always use kCFStringEncodingUTF8. You should never use a text encoding that isn't a superset of ASCII encoding. You must not encode an entire URL string. You must make sure the characters you want percent-encoded are encoded and those you do not want percent-encoded are not (you may have to pass in strings in the charactersToLeaveUnescaped and legalURLCharactersToBeEscaped arguments to get the results you expect). You can disable deprecation warnings around your use of deprecated functions by using these #pragmas:
    #pragma GCC diagnostic push
    #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
        // use deprecated functions
    #pragma GCC diagnostic pop
Other deprecations:
    -initWithScheme:host:path:

NSURLComponents New API

The following properties were added to NSURLComponents to return the character range of a component in the URL string returned by -[NSURLComponents string].
    rangeOfScheme
    rangeOfUser
    rangeOfPassword
    rangeOfHost
    rangeOfPort
    rangeOfPath
    rangeOfQuery
    rangeOfFragment

NSFileManager New API

NSFileManager now provides a method for unmounting and optionally ejecting file system volumes.
    -unmountVolumeAtURL:options:completionHandler:
The options for unmountVolumeAtURL:options:completionHandler are:
    NSFileManagerUnmountAllPartitionsAndEjectDisk
NSFileManagerUnmountWithoutUI
If unmountVolumeAtURL:options:completionHandler: fails, the process identifier of the dissenter can be found in the NSError's userInfo dictionary with the NSFileManagerUnmountDissentingProcessIdentifierErrorKey.


NSAffineTransform now conforms to NSSecureCoding

In OS X 10.11 and iOS 9, NSAffineTransform now conforms to NSSecureCoding. Invalid archives of NSAffineTransform will now raise an NSGenericException if they do not strictly match the expected layout.

Dictionaries created with dictionaryWithSharedKeySet now fully supports NSSecureCoding

Dictionaries created via NSSharedKey dictionary can now survive unarchive even if the the underlying hash implementation of the contained objects changes between archival/unarchival.

NSCache deadlock

On iOS 8 it was possible for NSCache to cause an application to deadlock if managed to retain itself during an UIApplicationDidEnterBackgroundNotification notification. This no longer occurs in iOS 9.


NSPropertyListSerialization now populates error on validation failures

On OS X 10.10 and iOS 8 and earlier, invalid property lists passed to -[NSPropertyListSerialization dataWithPropertyList:format:options:error] could return nil, but not populate the error (it would log instead). Beginning in OS X 10.11 and iOS 9, this API will now populate the error appropriately if provided.


NSCoder gains support for expressing decode failures via NSError

In OS X 10.10 and iOS 8 and earlier, instances of NSCoder communicated errors primarily through NSException, even if the underlying problem was not a programmer error (i.e.. corrupt archive). New to OS X 10.11 and iOS 9, all NSCoder implementations gain support for error notification through NSError out-parameters. These APIs should make it much easier to unarchive data in Swift.

You can opt-in to this behavior by calling any of these new top-level decode methods:
- (id)decodeObjectForKey:(NSString *)key error:(NSError **)error;
- (id)decodeObjectOfClass:(Class)aClass forKey:(NSString *)key error:(NSError **)error;
- (id)decodeObjectAndReturnError:(NSError **)error;
+ (id)unarchiveObjectWithData:(NSData *)data error:(NSError **)error;
The top-level distinction is important, as NSCoder implementations still use exceptions internally to communicate failure. Any other decode-related API on NSCoder can still throw.

Though we define the method
- (void)failWithError:(NSError *)error;
It is still under development and should not be used at this time (the WWDC seed release).

To differentiate between missing values and invalid archives, the following NSError code can be examined: NSCoderValueNotFoundError when the decode method returns nil. Note that this error will not be encountered in Swift, where the decode methods do return an optional.


NSUndoManager Now Supports Block Undo Operations

In the interest of providing an easier way to use implement undo operations in Swift, NSUndoManager gains the following API:
/*! @abstract records single undo operation for the specified target
@param target non-nil target of the undo operation
@param undoHandler non-nil block to be executed for the undo operation
@discussion
As with other undo operations, this does not strongly retain target. Care should be taken to avoid
introducing retain cycles by other references captured by the block.
*/
- (void)registerUndoWithTarget:(id)target handler:(void (^)(id target))undoHandler;
Additionally, like the other undo operations (target/selector and invocation), the target can be used with the -removeAllActionsWithTarget:.


NSString's +stringEncodingForData: API Enhancements

In OS X 10.11 and iOS 9, if you called +[NSString (NSStringEncoding)stringEncodingForData:(NSData *)data encodingOptions:(NSDictionary *)opts convertedString:(NSString **)string usedLossyConversion:(BOOL *)usedLossyConversion] with a suggested encoding via NSStringEncodingDetectionSuggestedEncodingsKey and allowed lossy detection via NSStringEncodingDetectionAllowLossyKey you will always get a result. Previously in OS X 10.0 and iOS 8, the API could fail to find an encoding in such circumstances.


Single Object NSSet Performance Improvements

Changes have were made to dramatically increase the performance of single-object immutable sets.


Various Performance Improvements in our collections

Improved immutable NSArray performance across the board, especially around access, creation and deletion.

NSDictionary -isEqual is now faster, along with numerous other dictionary related operations.

Safer Buffer API for NSDictionary

In OS X 10.11 and iOS 9, NSDictionary gains the following method:
- (void)getObjects:(ObjectType __unsafe_unretained [])objects
andKeys:(KeyType __unsafe_unretained [])keys
count:(NSUInteger)count;
It is intended to replace the following method, which is soft-deprecated this release, and will be officially deprecated in the future.
- (void)getObjects:(ObjectType __unsafe_unretained [])objects
andKeys:(KeyType __unsafe_unretained [])keys;

Safer Buffer API for NSIndexPath

Similarly, NSIndexPath gains the following method:
- (void)getIndexes:(NSUInteger *)indexes range:(NSRange)positionRange;
Replacing the older, less safe variant (which is now soft-deprecated):
- (void)getIndexes:(NSUInteger *)indexes;


NSFileVersion hasLocalContents Bug Fix

In OS X 10.10 and iOS 8, NSFileVersion exposed the "hasLocalContents" property to indicate whether a particular NSFileVersion originated locally, or from some non-local source, like iCloud. Unfortunately, the property returned the opposite value than intended. This is has been fixed in OS X 10.11 and iOS 9.


NSMutableDictionary subscript syntax change

In OS X 10.11 and iOS 9, NSMutableDictionary now allows you to use its subscript syntax to assign nil for a key. Like Swift's Dictionary type, doing so will remove an existing object for that key from the dictionary. In effect, the following lines of code are now equivalent:
[dictionary removeObjectForKey:@"Key"];
dictionary[@"Key"] = nil;
These new semantics exist only when building with the OS X 10.11 or iOS 9 SDKs. If your application's deployment target is earlier operating system, then runtime support will be implicitly linked into your binary by Xcode to ensure the behavior works on any targeted operation system.



NSURLConnection

NSURLConnection is deprecated as of OS X 10.11 and iOS 9. Please use NSURLSession.

Application Transport Security

Application Transport Security is a new security feature whose goal is to protect customer data. If your app is linked on or after OS X 10.11 or iOS 9, all NSURLSession and NSURLConnection based cleartext HTTP loads (http://) will be denied by default. Encrypted HTTPS (https://) connections will also require "best practice" TLS behaviors, such as TLS version and cipher suite requirements. Temporary exceptions can be configured via your app's Info.plist file. For more information, see the WWDC sessions covering Application Transport Security.

WatchOS

The symbols NSURLSessionTaskPriorityDefault, NSURLSessionTaskPriorityHigh and NSURLSessionTaskPriorityLow are missing from the WatchOS SDK.


NSString

NSString now exposes API for transliteration. This was available in CFString previously.
- (nullable NSString *)stringByApplyingTransform:(NSString *)transform
reverse:(BOOL)reverse;
The indicated transformation is applied to the receiver (see below for the predefined set of transforms provided in NSString). reverse indicates that the inverse transform should be used instead, if it exists. Attempting to use an invalid transform identifier or reverse an irreversible transform will return nil; otherwise the transformed string value is returned (even if no characters are actually transformed). In addition to the predefined transforms, you can pass in any valid ICU transform ID as defined in the ICU User Guide. Arbitrary ICU transform rules are not supported.

There’s also API on NSMutableString for the same thing:
- (BOOL)applyTransform:(NSString *)transform
reverse:(BOOL)reverse
range:(NSRange)range
updatedRange:(nullable NSRangePointer)resultingRange;
Similar to the NSString API, except that only the specified range will be modified (however the transform may look at portions of the string outside that range for context). If supplied, resultingRange is modified to reflect the new range corresponding to the original range.

The following transforms are provided:
NSString * const NSStringTransformLatinToKatakana;
NSString * const NSStringTransformLatinToHiragana;
NSString * const NSStringTransformLatinToHangul;
NSString * const NSStringTransformLatinToArabic;
NSString * const NSStringTransformLatinToHebrew;
NSString * const NSStringTransformLatinToThai;
NSString * const NSStringTransformLatinToCyrillic;
NSString * const NSStringTransformLatinToGreek;
NSString * const NSStringTransformToLatin;
NSString * const NSStringTransformMandarinToLatin;
NSString * const NSStringTransformHiraganaToKatakana;
NSString * const NSStringTransformFullwidthToHalfwidth;
NSString * const NSStringTransformToXMLHex;
NSString * const NSStringTransformToUnicodeName;
NSString * const NSStringTransformStripCombiningMarks;
NSString * const NSStringTransformStripDiacritics;

The following two new methods are the most appropriate methods for doing user-level string searches, similar to how searches are done generally in the system. The search is locale-aware, case and diacritic insensitive. As with other APIs, "standard" in the name implies "system default behavior," so the exact list of search options applied may change over time. If you need more control over the search options, please use the rangeOfString:options:range:locale: method. You can pass [NSLocale currentLocale] for searches in user's locale.
- (BOOL)localizedStandardContainsString:(NSString *)str;
- (NSRange)localizedStandardRangeOfString:(NSString *)str;

The following are new convenience methods that do the case mappings in a locale-aware fashion.
- (NSString *)localizedUppercaseString;
- (NSString *)localizedLowercaseString;
- (NSString *)localizedCapitalizedString;

NSError

We recommend that NSErrors are as rich as possible, with localized description, failure reason, recovery attempter, etc.  This in turn may make the creation of NSErrors more expensive, and tight loops where expected errors are being encountered could be an issue. To help with this, NSError now allows you to specify a block as the userInfoValueProvider for a domain. This provider can provide some of the info needed to create great NSErrors lazily, on-demand:
+ (void)setUserInfoValueProviderForDomain:(NSString *)errorDomain
provider:(nullable id (^)(NSError *err, NSString *userInfoKey))provider;
+ (nullable id (^)(NSError *err, NSString *userInfoKey))userInfoValueProviderForDomain:(NSString *)errorDomain;
Specify a block which will be called from the implementations of localizedDescription, localizedFailureReason, localizedRecoverySuggestion, localizedRecoveryOptions, recoveryAttempter, and helpAnchor, when the underlying value for these is not present in the userInfo dictionary of NSError instances with the specified domain. The provider will be called with the userInfo key corresponding to the queried property: For instance, NSLocalizedDescriptionKey for localizedDescription. The provider should return nil for any keys it is not able to provide and, very importantly, any keys it does not recognize (since we may extend the list of keys in future releases).

The specified block will be called synchronously at the time when the above properties are queried. The results are not cached.

This provider is optional. It enables localization and formatting of error messages to be done lazily; rather than populating the userInfo at NSError creation time, these keys will be fetched on-demand when asked for.

It is expected that only the “owner” of an NSError domain specifies the provider for the domain, and this is done once. This facility is not meant for consumers of errors to customize the userInfo entries. This facility should not be used to customize the behaviors of error domains provided by the system.