ts archiving
DESCRIPTION
TRANSCRIPT
Boutique product development company It is amazing what you can accomplish when you have a client-centric team to deliver outstanding products.
Archiving
Sajid Hussain | Software Evangelist
Archiving Topics covered in the presentation
• Archiving With XML Property Lists
• Archiving With NS Keyed Archiver
• Writing Encoding and Decoding Methods
• Encoding and Decoding Basic Data Types in Keyed Archives
• Using NS Data to Create Custom Archives
• Using Archiver to Copy Objects
• Final Wrods
Sajid Hussain | Software Evangelist
Archiving
Archiving
Sajid Hussain | Software Evangelist
Objective-C terms, archiving is the process of saving one or
more objects in a format so that they can later be restored.
Often this involves writing the object(s) to a file so it can
subsequently be read back in.
Archiving
Archiving with XML Property Lists
Sajid Hussain | Software Evangelist
If your objects are of type NSString, NSDictionary, NSArray, NSDate, NSData, or NSNumber, you can use
the writeToFile:atomically: method implemented in these classes to write your data to a file.
Program # 1
intmain (intargc, char *argv[]) {
NSAutoreleasePool* pool = [[NSAutoreleasePoolalloc] init];
NSDictionary*glossary = [NSDictionarydictionaryWithObjectsAndKeys:@”A class defined so other
classes can inherit from it.”, @”abstract class”, @”To implement all the methods defined in a
protocol”, @”adopt”, @”Storing an object for later use. “, @”archiving”, nil];
if ([glossary writeToFile: @”glossary”atomically: YES] == NO)
NSLog(@”Save to file failed!”);
[pool drain];
return 0;
}
The writeToFile:atomically: message is sent to your dictionary object glossary, causing the dictionary to be
written to the file glossary in the form of a property list. The atomically parameter is set to YES, meaning
that you want the write operation to be done to a temporary backup file first; once successful, the final data
is to be moved to the specified file named glossary.
Archiving
Archiving with XML Property Lists Cont..
Sajid Hussain | Software Evangelist
If you examine the contents of the glossary file created by Program # 1, it looks
like this:
<?xml version=”1.0” encoding=”UTF-8”?>
<!DOCTYPE plist PUBLIC “-//Apple Computer//DTD PLIST 1.0//EN”“http://
www.apple.com/DTDs/PropertyList-1.0.dtd”>
<plist version=”1.0”>
<dict>
<key>abstract class</key>
<string>A class defined so other classes can inherit from it.</string>
<key>adopt</key>
<string>To implement all the methods defined in a
protocol</string><key>archiving</key>
<string>Storing an object for later use. </string>
</dict>
</plist>
Archiving
Archiving with XML Property Lists Cont..
Sajid Hussain | Software Evangelist
Program # 2
intmain (intargc, char *argv[]) {
NSAutoreleasePool* pool = [[NSAutoreleasePoolalloc] init];
NSDictionary*glossary;glossary = [NSDictionarydictionaryWithContentsOfFile:
@”glossary”];
for ( NSString *key in glossary )
NSLog(@”%@: %@”, key, [glossary objectForKey: key]);
[pool drain];
return 0;
}
Program # 2 Output
archiving: Storing an object for later use.
abstract class: A class defined so other classes can inherit from it.
adopt: To implement all the methods defined in a protocol
Archiving
Archiving with NS Keyed Archiver
Sajid Hussain | Software Evangelist
Program # 3
intmain (intargc, char *argv[]) {
NSAutoreleasePool* pool = [[NSAutoreleasePoolalloc] init];
NSDictionary*glossary = [NSDictionarydictionaryWithObjectsAndKeys: @”A class defined so other
classes can inherit from it”, @”abstract class”, @”To implement all the methods defined in a
protocol”, @”adopt”, @”Storing an object for later use”, @”archiving”, nil];
[NSKeyedArchiverarchiveRootObject: glossary toFile: @”glossary.archive”]; [pool release];
return 0;
}
Program # 4
intmain (intargc, char *argv[]) {
NSAutoreleasePool* pool = [[NSAutoreleasePoolalloc] init];
NSDictionary*glossary;
glossary = [NSKeyedUnarchiverunarchiveObjectWithFile: @”glossary.archive”];
for ( NSString *key in glossary )
NSLog(@”%@: %@”, key, [glossary objectForKey: key]);
[pool drain];
return 0;
}
Program # 4 Output
abstract class: A class defined so other classes can inherit from it.
adopt: To implement all the methods defined in a protocol
archiving: Storing an object for later use.
Archiving
Writing Encoding and Decoding Method
Sajid Hussain | Software Evangelist
Basic Objective-C class objects such as NSString, NSArray, NSDictionary, NSSet, NSDate,NSNumber, and NSData
can be archived and restored in the manner just described. That includes nested objects as well, such as an array
containing a string or even other array objects. To archive objects other than those listed, you must tell the system how
to archive, or encode, your objects, and also how to unarchive, or decode, them. This is done by adding
encodeWithCoder: and initWithCoder: methods to your class definitions, according to the <NSCoding> protocol.
@interface Foo: NSObject<NSCoding>{
NSString*strVal; intintVal; float floatVal;
}
@property (copy, nonatomic) NSString *strVal;
@property intintVal;
@property float floatVal;
@end
// Definition for our Fooclass
@implementation Foo
@synthesize strVal, intVal, floatVal;
-(void) encodeWithCoder: (NSCoder *) encoder {
[encoder encodeObject: strValforKey: @”FoostrVal”];
[encoder encodeInt: intValforKey: @”FoointVal”];
[encoder encodeFloat: floatValforKey: @”FoofloatVal”];
}
-(id) initWithCoder: (NSCoder *) decoder {
strVal= [[decoder decodeObjectForKey: @”FoostrVal”] retain];
intVal= [decoder decodeIntForKey: @”FoointVal”];
floatVal= [decoder decodeFloatForKey: @”FoofloatVal”];
return self;
Archiving
Writing Encoding and Decoding Method Cont..
Sajid Hussain | Software Evangelist
Program # 5Test Program
intmain (intargc, char *argv[]) {
NSAutoreleasePool* pool = [[NSAutoreleasePoolalloc] init];
Foo*myFoo1 = [[Fooalloc] init];
Foo*myFoo2;[myFoo1 setStrVal: @”This is the string”];
[myFoo1 setIntVal: 12345];
[myFoo1 setFloatVal: 98.6];
[NSKeyedArchiver archiveRootObject: myFoo1 toFile: @”foo.arch”];
myFoo2 = [NSKeyedUnarchiverunarchiveObjectWithFile: @”foo.arch”];
NSLog(@”%@\n%i\n%g”, [myFoo2 strVal], [myFoo2 intVal], [myFoo2 floatVal]);
[myFoo1 release];
[pool drain];
return 0;
}
Program # 5 Output
This is the string
12345
98.6
The encodeWithCoder: method is invoked each time the archiver wants to encode an object from the specified class,
and the method tells it how to do so. In a similar manner, the initWithCoder: method is invoked each time an object from
the specified class is to be decoded. if you knew the super- class of your class conformed to the NSCoding protocol,
you should start your encoding method with a statement like the following to make sure your inherited instance
variables are encoded: [super encodeWithCoder: encoder]; The only time a conflict might arise is if the same key is
used for a subclass of an object being encoded. To prevent this from happening, you can insert the class name in front
of the instance variable name when composing the key for the archive.
Archiving
Encoding and Decoding Basic Data Types in Keyed Archives
Sajid Hussain | Software Evangelist
Encoder Decoder
encodeBool:forKey: decodeBool:forKey:
encodeInt:forKey: decodeInt:forKey:
encodeInt32:forKey: decodeInt32:forKey:
encodeInt64: forKey: decodeInt64:forKey:
encodeFloat:forKey: decodeFloat:forKey:
encodeDouble:forKey: decodeDouble:forKey:
For basic underlying C data types (such as integers and floats), you use one of the methods listed in the following
Table. The decoder method, initWithCoder: works in reverse: You use decodeObject:forKey: to decode basic Objective-
C classes and the appropriate decoder method shown in following Table for the basic data types.
Some of the basic data types, such as char, short, long, and long long, are not listed in the Table; you must determine
the size of your data object and use the appropriate routine. For example, a short int is normally 16 bits, an int and long
can be 32 or 64 bits, and a long long is 64 bits. (You can use the sizeof operator to determine the size of any data type.)
So to archive a short int, store it in an int first and then archive it with encodeInt:forKey:. Reverse the process to get it
back: Use decodeInt:forKey: and then assign it to your short int variable.
Archiving
Using NSData to Create Custom Archives
Sajid Hussain | Software Evangelist
Perhaps you want to collect some or all of your objects and store them in a single archive file.
Program # 6
intmain (intargc, char *argv[]) {
NSAutoreleasePool* pool = [[NSAutoreleasePoolalloc] init];
Foo*myFoo1 = [[Fooalloc] init];
NSMutableData*dataArea;NSKeyedArchiver *archiver;
[myFoo1 setStrVal: @”This is the string”];
[myFoo1 setIntVal: 12345];
[myFoo1 setFloatVal: 98.6];
// Set up a data area and connect it to an NSKeyedArchiver object
dataArea= [NSMutableData data];
archiver= [[NSKeyedArchiveralloc] initForWritingWithMutableData: dataArea];
// Now we can begin to archive objects
[archiverencodeObject: myFoo1 forKey: @”myfoo1”];
[archiverfinishEncoding];
// Write the archived data are to a file
if ( [dataAreawriteToFile: @”myArchive” atomically: YES] == NO)
NSLog(@”Archiving failed!”);
[archiver release];
[myFoo1 release];
[pool drain];
return 0;
Archiving
Using NSData to Create Custom Archives Cont..
Sajid Hussain | Software Evangelist
Program # 7
intmain (intargc, char *argv[]) {
NSAutoreleasePool* pool = [[NSAutoreleasePoolalloc] init];
NSData*dataArea;
NSKeyedUnarchiver*unarchiver;
Foo*myFoo1;
// Read in the archive and connect an NSKeyedUnarchiver object to it
dataArea= [NSDatadataWithContentsOfFile: @”myArchive”];
if (! dataArea) {
NSLog(@“Can’t read back archive file!”);
Return (1);
}
unarchiver= [[NSKeyedUnarchiveralloc] initForReadingWithData: dataArea];
// Decode the objects we previously stored in the archive
myFoo1 = [unarchiverdecodeObjectForKey: @”myfoo1”];
[unarchiver finishDecoding];
[unarchiver release];
// Verify that the restore was successful
} NSLog(“%@\n%i\n%g”, [myFoo1 strVal], [myFoo1 intVal], [myFoo1 floatVal]);
[pool release];
return 0;
Archiving
Using Archiver to Copy Objects
Sajid Hussain | Software Evangelist
Program # 8
intmain (intargc, char *argv[]) {
NSAutoreleasePool*pool = [[NSAutoreleasePoolalloc] init];
NSData*data;
NSMutableArray*dataArray = [NSMutableArrayarrayWithObjects:[NSMutableStringstringWithString: @”one”],
[NSMutableStringstringWithString: @”two”], [NSMutableStringstringWithString: @”three”], nil];
NSMutableArray*dataArray2;
NSMutableString*mStr;
// Make a deep copy using the archiver
data = [NSKeyedArchiverarchivedDataWithRootObject: dataArray];
dataArray2 = [NSKeyedUnarchiverunarchiveObjectWithData: data];
mStr= [dataArray2 objectAtIndex: 0];
[mStrappendString: @”ONE”];
NSLog(@”dataArray: “);
for ( NSString *elem in dataArray)
NSLog(“%@”, elem);
NSLog(@”\ndataArray2: “);
for ( NSString *elem in dataArray2 )
NSLog(“%@”, elem);
[pool drsin];
return 0;
}
Program # 8 Output
dataArray:
one
two
Three
dataArray2:
oneONE
two
three
Archiving
Final Words
Sajid Hussain | Software Evangelist
• If you want to store simple values, serialization (using an
NSDictionary, for example) is a fine way to go. If you want to store
an object graph of arbitrary types, with uniqueness and mutability
preserved, using archives (with NSCoder, for example) is your best
bet.
• NSCodingis a powerful way to serialize objects so that you can
pass them between processes or save it to a file. Implement the
NSCoding protocol on your custom objects that you want to
serialize, then use NSKeyedArchiver to serialize them and
NSKeyedUnarchiver to deserialize them.