Inherits From:
NSObject
Conforms To:
NSObject (NSObject)
Declared In:
Foundation/NSPPL.h
The four classes used in property lists give you the means to produce data that is meaningfully structured, transportable, storable, and accessible, but still as lightweight as possible. You represent basic data types (such as integers and text) with NSString, and binary data with NSData. You use NSDictionary and NSArray to build complex data structures. In an NSDictionary, data is structured as key-value pairs, where the key is a string, and the value can be an NSString, an NSArray, an NSData, or another NSDictionary. In an NSArray, data is structured as a collection of objects that can be accessed by index. An NSArray in an NSPPL can contain NSStrings, NSDatas, NSDictionaries, and other NSArrays.
For example, this code excerpt creates an NSPPL, PersonalInfo.ppl
, that stores a person's name, address, and children's names. The example uses combinations of NSString, NSArray, and NSDictionary objects. All data is accessed through a root NSDictionary in which the person's name is an NSString, the children's names are stored in an NSArray, and the address is stored in an NSDictionary containing NSStrings.
NSPPL *ppl;
NSString *pplPath;
NSMutableDictionary *root;
NSString *name = @"Chris Smith";
NSArray *childArray;
NSMutableDictionary *addressDict;
childArray = [NSArray arrayWithObjects:@"Sam", @"Bettina", @"Eloise", nil];
addressDict = [NSMutableDictionary dictionaryWithCapacity:4];
/* Add data to addressDict. */
[addressDict setObject:@"955 Elm Street" forKey:@"street"];
[addressDict setObject:@"Midland" forKey:@"city"];
[addressDict setObject:@"Kansas" forKey:@"state"];
[addressDict setObject:@"19067" forKey:@"zipcode"];
pplPath = @"PersonalInfo.ppl";
/* Read the NSPPL; if it doesn't exist, create it. */
ppl = [NSPPL pplWithPath:pplPath create:YES readOnly:NO];
if (!ppl) {
NSLog(@"Couldn't open or create %@", pplPath);
exit(1);
}
/* Get ppl's root dictionary. */
root = [ppl rootDictionary];
/* Through the root dictionary, add data to ppl. */
[root setObject:name forKey:@"name"];
[root setObject:addressDict forKey:@"address"];
[root setObject:childArray forKey:@"children"];
/* Save ppl. */
[ppl save];
store
and log
. store
and log
work in conjunction to ensure that any changes you make to your NSPPL can be rolled back in the case of a failure. While you're modifying a persistent property list, the changes are recorded in store
and added to log
. log
maintains the property list's old state so that if a failure occurs, the changes made in store
can be rolled back.
Persistent property lists are atomic, meaning that if a save operation fails, the NSPPL reverts to its previously saved state. An NSPPL is never left in an intermediate state. Changes to an NSPPL are applied incrementally (in memory, but not to disk) as you make them and are reflected in the store
and log
files. A save
operation has the effect of committing the changes you've made to disk.
If an NSPPL becomes damaged (for example, if there's a bad bit on the disk), attempting to access it raises the exception NSInternalInconsistencyException. If this happens, you can retrieve the NSPPL by catching the exception and using the NSException userInfo
method to get the userInfo NSDictionary. The userInfo NSDictionary usually has the NSPPL available under the key "NSPPL", which you can use to rebuild your persistent property list (when possible).
Like serialization, a persistent property list stores data in a binary format, provides fast access, and is lazy. It also allows you to make incremental changes to an NSPPL (even one that contains tens of megabytes of data), while still ensuring that your data is never corrupted. In this sense, an NSPPL is analogous to a database. Because of their ability to incrementally store and retrieve data, NSPPLs are particularly well-suited for working with large amounts of data (that is, data that has several elements, that occupies a large number of bytes, or both).
pplWithPath:create:readOnly:
, initWithPath:create:readOnly:
, rootDictionary
, and save
. These are the methods you use the majority of the time.
The PPLData methods provide read-only snapshots of an entire NSPPL as an NSData object. This allows you to pass NSPPLs across processes; passing NSPPLs as binary data is very fast. Wherever a method has the keyword ...PPLData
(for example, pplWithPath:fromPPLData:readOnly:
), you use the contentsAsData
method to return the contents of an NSPPL as an NSData object. For example:
NSPPL *originalPPL; /* Assume this exists. */
NSString *aPath; /* Assume this exists. */
NSPPL *newPPL = [NSPPL pplWithPath:aPath
fromPPLData:[originalPPL contentsAsData] readOnly:NO];
The PPLData methods include pplWithPath:fromPPLData:readOnly:
, initWithPath:fromPPLData:readOnly:
, and propertyListWithPPLData:
. These methods provide a fast mechanism for reading and passing read-only copies of an NSPPL. For example, you can have one process continually updating the contents of an NSPPL as multiple read-only copies of the NSPPL are distributed.
The performance tuning methods, flush
, pushChangesToDisk
, detachFromFile
and setCacheHalfLife:
, let you exercise finer-grained control over the behavior of an NSPPL. You can use flush
and pushChangesToDisk
in conjunction with save
to speed up save operations. detachFromFile
ensures that no more changes are written to disk; this is useful if certain error conditions occur such as running out of disk space or if an NSPPL becomes damaged. setCacheHalfLife:
lets you fine-tune the trade-offs between memory usage and speed.
pplWithPath:
(NSString *)path create:
(BOOL)createFlag readOnly:
(BOOL)readOnlyFlag
Given a path, reads the NSPPL stored in it or creates a new one, where readOnlyFlag indicates whether the NSPPL can be changed, and createFlag indicates whether the NSPPL should be created if it doesn't already exist. Returns the new NSPPL object or nil
if the file can't be read.
See also:
+ pplWithPath:fromPPLData:readOnly:
, + propertyListWithPPLData:
pplWithPath:
(NSString *)path fromPPLData:
(NSData *)pplData readOnly:
(BOOL)readOnlyFlag
Given a path, reads or creates an NSPPL that is identical in every way, except for mutability, to the NSPPL represented by pplData. readOnlyFlag indicates whether the new NSPPL can be modified; the new NSPPL doesn't have to have the same mutability or immutability as the NSPPL specified in the pplData argument. Returns the new NSPPL object or nil
if the file can't be read.
An NSPPL is saved when it's created; you don't need to explicitly save it. You can use this method to make local back ups of a remote NSPPL.
When you use this method or any of the other NSPPL methods that take NSData arguments, you use contentsAsData
to return a read-only snapshot of an NSPPL as an NSData object, for example:
NSPPL *originalPPL; /* Assume this exists. */
NSString *aPath; /* Assume this exists. */
NSPPL *pplCopy = [NSPPL pplWithPath:aPath
fromPPLData:[originalPPL contentsAsData] readOnly:NO];
See also:
+ pplWithPath:create:readOnly:
, + propertyListWithPPLData:
propertyListWithPPLData:
(NSData *)pplData
Returns an immutable root dictionary that gives you access to a snapshot of the NSPPL specified in the pplData argument.
This method is similar to rootDictionary
, in that both methods return a root dictionary object that gives you access to an NSPPL. However, while rootDictionary
returns an NSMutableDictionary that allows you to modify the associated NSPPL (so long as the NSPPL itself is mutable), propertyListWithPPLData:
always returns an immutable NSDictionary whose associated NSPPL can't be modified. This method is a very fast way of getting a read-only snapshot of an NSPPL.
See also:
+ pplWithPath:fromPPLData:readOnly:
, + pplWithPath:create:readOnly:
,
- rootDictionary
contentsAsData
Returns an NSData object containing a read-only snapshot of an entire NSPPL, that can then be passed to another process. Passing NSPPLs as binary data is very fast; see the section "Overview of Methods" in the class description for more information.
See also:
- rootDictionary
, + propertyListWithPPLData:
, - initWithPath:fromPPLData:readOnly:
detachFromFile
Guarantees that no more changes will be written to disk. After this method is invoked, proxies can be released but not accessed. This method is invoked by dealloc
. You can use this method to intervene in certain error conditions: For example, if your NSPPL becomes damaged, you can use this method to disable writing to disk. You can then delete the damaged NSPPL and regenerate it (when possible). You should only use this method if you're sure where proxies are when the file is being detached.
flush
Flushes changes to disk. You can use flush
and save
in combination to achieve maximum performance. save
is a costly operation that writes the current state of the NSPPL to disk and makes the necessary adjustments to the log
and store
files; flush
is faster and it accomplishes much of the work that would otherwise have to be performed by save
. If you use flush
at regular intervals and save only as needed, your save
operations will be faster since flush
does much of the work.
The primary difference between flush
and save
is that if your program fails, your NSPPL is guaranteed only to revert to the previous save
, not to the previous flush
.
Like save
, flush
guarantees that nothing is done if no change was made to your NSPPL. All mutable container objects from the NSPPL that you have not retained are invalid after this method is invoked.
See also:
- pushChangesToDisk
initWithPath:
(NSString *)path create:
(BOOL)createFlag readOnly:
(BOOL)readOnlyFlag
Given a path, reads the NSPPL stored in it or creates a new one, where readOnlyFlag indicates whether the NSPPL can be changed, and createFlag indicates whether the NSPPL should be created if it doesn't already exist. Returns the new NSPPL or nil
if the file can't be read.
See also:
- initWithPath:fromPPLData:readOnly:
initWithPath:
(NSString *)path fromPPLData:
(NSData *)pplData readOnly:
(BOOL)readOnlyFlag
Given a path, reads or creates an NSPPL that is identical in every way except for mutability to the NSPPL represented by pplData. readOnlyFlag indicates whether the new NSPPL can be modified; the new NSPPL doesn't have to have the same mutability or immutability as the NSPPL specified in the pplData argument. Returns nil
if the file can't be read. An NSPPL is saved when it's created; you don't need to explicitly save it.
See also:
- initWithPath:create:readOnly:
pushChangesToDisk
Ensures that the disk image reflects the current state of the NSPPL. Unlike flush
and save
this method has no effect on non-retained objects, and no notification is posted.
rootDictionary
Returns an NSPPL's root dictionary, through which you can modify the NSPPL (so long as the NSPPL itself is mutable; if it isn't, this method returns an immutable NSDictionary). You interact with an NSPPL through its root dictionary, which provides access to all of the NSPPL's other data structures.
Whenever the root dictionary is first modified after a flush
or a save
operation, this method posts the NSPPLBecameDirty notification with the NSPPL that was modified to the default notification center.
NSMutableDictionaries returned from this method have the same validity as if the dictionary were in memory, except that they do not survive beyond a save
or flush
operation unless they have been retained or copied.
If you store an NSMutableDictionary, release all references to it, and retrieve it, a proxy is returned rather than the original dictionary. However, if an NSMutableDictionary is stored and retained, you don't get a proxy when you retrieve it-you get the actual object.
See also:
- contentsAsData
save
Saves any changes you made to the NSPPL to disk and makes the necessary adjustments to the log
and store
files. If save
returns, it means that the changes have been reflected in the NSPPL. This method guarantees that nothing is done if no change was made. If a save
operation succeeds, this method posts the NSPPLSaved notification with the NSPPL that was saved to the default notification center.
You can use save
in combination with flush
to achieve maximum performance. Use flush
at regular intervals and save
as needed. flush
is a faster and less comprehensive operation than save
, and it also makes subsequent save
operations faster since flush
does much of the work that would otherwise have to be performed by save
. The primary difference between flush
and save
is that if your program fails, your NSPPL is guaranteed only to revert to the previous save
, not to the previous flush
.
As with flush
, all mutable objects that you have not retained are invalid after this operation.
See also:
- flush
, - pushChangesToDisk
setCacheHalfLife:
(NSTimeInterval)halfLife
Sets the time interval after which cached items are written to disk. Cached items have a 50% chance of being written out after halfLife seconds. If halfLife is zero, cached items are always flushed when the cache is refreshed. If halfLife is less than zero, caching is disabled and can't be re-enabled. This method allows you to fine-tune the trade-offs between memory usage and speed.