1. Trang chủ
  2. » Công Nghệ Thông Tin

iPhone SDK Programming A Beginner’s Guide phần 9 ppsx

48 510 0

Đang tải... (xem toàn văn)

Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống

THÔNG TIN TÀI LIỆU

Chapter 15: Property Lists and Archiving 369 NSKeyedArchiver and NSKeyedUnarchiver The NSKeyedArchiver class archives objects, while the NSKeyedUnarchiver class unarchives objects. NSKeyedArchiver NSKeyedArchiver stores one or more objects to an archive using the initForWritingWith MutableData method. To be archived, an object must implement the NSCoding protocol. - (id)initForWritingWithMutableData:(NSMutableData *)data This method takes a writable data object and returns the archived object as an id. You can then write the archive to disk. The steps for creating and writing an archive to disk are as follows. First, create an NSMutableData object. NSMutableData * theData = [NSMutableData data]; After creating the data object, create an NSKeyedArchiver, passing the newly created data object as a parameter. NSKeyedArchiver * archiver = [[NSKeyedArchiver alloc] initForWritingWithMutableData:theData]; After initializing the NSKeyedArchiver, encode the objects to archive. If you wish, you can encode multiple objects using the same archiver, provided all archived objects adopt the NSCoding protocol. The following code snippet illustrates. [archiver encodeObject:objectA forKey:@"a"]; [archiver encodeObject:objectB forKey:@"b"]; [archiver encodeObject:objectC forKey:@"c"]; [archiver finishEncoding]; After archiving, write the data object, which now contains the archived objects, to a file. [theData writeToFile:”myfile.archive” atomically:YES] NSKeyedUnarchiver You use NSKeyedUnarchiver to unarchive an archive. NSKeyedUnarchiver reconstitutes one or more objects from a data object that was initialized with an archive. To be unarchived, an object must implement the NSCoding protocol. When programming for the iPhone, you use the initForReadingWithData: method. - (id)initForReadingWithData:(NSData *)data 370 iPhone SDK Programming: A Beginner’s Guide Try This The steps to unarchive are similar to archiving. First, create an NSData object from the previously archived file. NSData * theData =[NSData dataWithContentsOfFile:"myfile.archive"]; After creating the data object, create and initialize an NSKeyedUnarchiver instance. NSKeyedUnarchiver * uarchiver = [[NSKeyedUnarchiver alloc] initForReadingWithData:theData]; After initializing the NSKeyedUnarchiver, unarchive the objects previously archived. A * objA = [[unarchiver decodeObjectForKey:@"a"] retain]; B * objB = [[unarchiver decodeObjectForKey:@”b”] retain]; C * objC = [[unarchiver decodeObjectForKey:@”c”] retain]; [unarchiver finishDecoding]; [unarchiver release]; Archiving and Unarchiving an Object 1. Create a new View-based Application called Encoding. 2. Create a new Objective-C class called Foo. 3. Add two properties to Foo. Make one property an NSString and name it “name” and make the other property an NSNumber and name it “age.” 4. Have Foo adopt the NSCopying and NSCoding protocols (Listings 15-7 and 15-8). Remember, Foo must get deep copies of name and age. 5. Modify Foo so it implements the encodeWithCoder:, initWithCoder:, and copyWithZone: methods. 6. Add Foo as a property to EncodingAppDelegate (Listings 15-9 and 15-10). 7. Implement the applicationWillTerminate: method and modify the applicationDidFinish Launching: methods to decode and encode Foo. 8. Click Build And Go. Listing 15-7 Foo.h #import <Foundation/Foundation.h> @interface Foo : NSObject <NSCoding, NSCopying> { Chapter 15: Property Lists and Archiving 371 NSString * name; NSNumber * age; } @property (nonatomic, retain) NSString * name; @property (nonatomic, retain) NSNumber * age; @end Listing 15-8 Foo.m #import "Foo.h" @implementation Foo @synthesize name; @synthesize age; - (id) copyWithZone: (NSZone *) zone { Foo * aFoo = [[Foo allocWithZone:zone] init]; aFoo.name = [NSString stringWithString: self.name]; aFoo.age = [NSNumber numberWithInt:[self.age intValue]]; return aFoo; } - (void) encodeWithCoder: (NSCoder *) coder { [coder encodeObject: name forKey: @"name"]; [coder encodeObject:age forKey: @"age"]; } - (id) initWithCoder: (NSCoder *) coder { self = [super init]; name = [[coder decodeObjectForKey:@"name"] retain]; age = [[coder decodeObjectForKey:@"age"] retain]; return self; } - (void) dealloc { [name release]; [age release]; [super dealloc]; } @end Listing 15-9 EncodingAppDelegate.h #import <UIKit/UIKit.h> @class Foo; @class EncodingViewController; (continued) 372 iPhone SDK Programming: A Beginner’s Guide @interface EncodingAppDelegate : NSObject <UIApplicationDelegate> { UIWindow *window; EncodingViewController *viewController; Foo * myFoo; } @property (nonatomic, retain) Foo * myFoo; @property (nonatomic, retain) IBOutlet UIWindow *window; @property (nonatomic, retain) IBOutlet EncodingViewController *viewController; @end Listing 15-10 EncodingAppDelegate.m #import "EncodingAppDelegate.h" #import "EncodingViewController.h" #import "Foo.h" @implementation EncodingAppDelegate @synthesize window; @synthesize viewController; @synthesize myFoo; - (void)applicationDidFinishLaunching:(UIApplication *)application { NSString *pathToFile = [[NSSearchPathForDirectoriesInDomains( NSDocumentDirectory, NSUserDomainMask,YES) objectAtIndex:0] stringByAppendingPathComponent:@"foo.archive"]; NSLog(pathToFile); NSData * theData =[NSData dataWithContentsOfFile:pathToFile]; if([theData length] > 0) { NSKeyedUnarchiver * archiver = [[[NSKeyedUnarchiver alloc] initForReadingWithData:theData] autorelease]; myFoo = [archiver decodeObjectForKey:@"myfoo"]; [archiver finishDecoding]; NSLog(@"nth run - name: %@ age: %i", myFoo.name, [myFoo.age intValue]); } else { NSLog(@"first run: no name or age"); myFoo =[[Foo alloc] init]; myFoo.name = @"James"; myFoo.age = [NSNumber numberWithInt:40]; } [window addSubview:viewController.view]; [window makeKeyAndVisible]; } - (void) applicationWillTerminate: (UIApplication *) application { NSString *pathToFile = [[NSSearchPathForDirectoriesInDomains( Chapter 15: Property Lists and Archiving 373 Try This NSDocumentDirectory, NSUserDomainMask,YES) objectAtIndex:0] stringByAppendingPathComponent:@"foo.archive"]; NSMutableData * theData = [NSMutableData data]; NSKeyedArchiver * archiver = [[[NSKeyedArchiver alloc] initForWritingWithMutableData:theData] autorelease]; [archiver encodeObject:self.myFoo forKey:@"myfoo"]; [archiver finishEncoding]; if( [theData writeToFile:pathToFile atomically:YES] == NO) NSLog(@"writing failed "); } - (void)dealloc { [myFoo release]; [viewController release]; [window release]; [super dealloc]; } @end Archiving and Unarchiving an Object Hierarchy 1. Open the previous application, Encoding, in Xcode. 2. Create a new Objective-C class and name it Bar. Have it adopt the NSCoding and NSCopying protocols (Listings 15-11 and 15-12). 3. Add an NSMutableArray as a property in Bar. 4. Override init to add a couple of Foo objects to the array (Listing 15-13). 5. Implement the initWithCoder:, encodeWithCoder:, and copyWithZone: methods (Listing 15-14). 6. Add Bar as a property to EncodingAppDelegate. Remember, you must import the class, add it as a property to the header, and synthesize the property in the implementation. 7. Modify EncodingAppDelegate’s applicationDidFinishLaunching: and applicationWill Terminate: methods to include the newly created Bar property. 8. Navigate to the application’s Documents directory and delete the previous foo.archive file. 9. Click Build And Go. (continued) 374 iPhone SDK Programming: A Beginner’s Guide Listing 15-11 Bar.h #import <Foundation/Foundation.h> #import "Foo.h" @interface Bar : NSObject <NSCoding, NSCopying> { NSMutableArray * foos; } @property (nonatomic, retain) NSMutableArray * foos; @end Listing 15-12 Bar.m #import "Bar.h" @implementation Bar @synthesize foos; - (id) init { if([super init] == nil) return nil; Foo * foo1 = [[Foo alloc] init]; foo1.name = @"Juliana"; foo1.age = [NSNumber numberWithInt:7]; Foo * foo2 = [[Foo alloc] init]; foo2.name = @"Nicolas"; foo2.age = [NSNumber numberWithInt:3]; foos = [[NSMutableArray alloc] initWithObjects:foo1, foo2, nil]; return self; } - (void) encodeWithCoder: (NSCoder *) coder { [coder encodeObject: foos forKey:@"foos"]; } - (id) initWithCoder: (NSCoder *) coder { self = [super init]; foos = [[coder decodeObjectForKey:@"foos"] retain]; return self; } - (id) copyWithZone: (NSZone *) zone { Bar * aBar = [[Bar allocWithZone:zone] init]; NSMutableArray *newArray = [[[NSMutableArray alloc] initWithArray: self.foos copyItems:YES] autorelease]; aBar.foos = newArray; return aBar; } – (void) dealloc { [foos release]; [super dealloc]; } @end Chapter 15: Property Lists and Archiving 375 Listing 15-13 EncodingAppDelegate.h #import <UIKit/UIKit.h> #import "Bar.h" @class Foo; @class EncodingViewController; @interface EncodingAppDelegate : NSObject <UIApplicationDelegate> { UIWindow *window; EncodingViewController *viewController; Foo * myFoo; Bar * myBar; } @property (nonatomic, retain) Foo * myFoo; @property (nonatomic, retain) Bar * myBar; @property (nonatomic, retain) IBOutlet UIWindow *window; @property (nonatomic, retain) IBOutlet EncodingViewController *viewController; @end Listing 15-14 EncodingAppDelegate.m #import "EncodingAppDelegate.h" #import "EncodingViewController.h" #import "Foo.h" @implementation EncodingAppDelegate @synthesize window; @synthesize viewController; @synthesize myFoo; @synthesize myBar; - (void)applicationDidFinishLaunching:(UIApplication *)application { NSString *pathToFile = [[NSSearchPathForDirectoriesInDomains( NSDocumentDirectory, NSUserDomainMask,YES) objectAtIndex:0] stringByAppendingPathComponent:@"foo.archive"]; NSLog(pathToFile); NSData * theData =[NSData dataWithContentsOfFile:pathToFile]; if([theData length] > 0) { NSKeyedUnarchiver * archiver = [[[NSKeyedUnarchiver alloc] initForReadingWithData:theData] autorelease]; myFoo = [archiver decodeObjectForKey:@"myfoo"]; myBar = [archiver decodeObjectForKey:@"mybar"]; [archiver finishDecoding]; NSLog(@"nth run - name: %@ age: %i", myFoo.name, [myFoo.age intValue]); (continued) 376 iPhone SDK Programming: A Beginner’s Guide NSArray * array = myBar.foos; for(Foo * aFoo in array) { NSLog(@"Foo: name: %@, age: %i", aFoo.name, [aFoo.age intValue]); } } else { NSLog(@"first run: no name or age"); myFoo =[[Foo alloc] init]; myFoo.name = @"James"; myFoo.age = [NSNumber numberWithInt:40]; myBar = [[Bar alloc] init]; } [window addSubview:viewController.view]; [window makeKeyAndVisible]; } - (void) applicationWillTerminate: (UIApplication *) application { NSString *pathToFile = [[NSSearchPathForDirectoriesInDomains( NSDocumentDirectory, NSUserDomainMask,YES) objectAtIndex:0] stringByAppendingPathComponent:@"foo.archive"]; NSMutableData * theData = [NSMutableData data]; NSKeyedArchiver * archiver = [[[NSKeyedArchiver alloc] initForWritingWithMutableData:theData] autorelease]; [archiver encodeObject:myFoo forKey:@"myfoo"]; [archiver encodeObject:myBar forKey:@"mybar"]; [archiver finishEncoding]; if( [theData writeToFile:pathToFile atomically:YES] == NO) NSLog(@"writing failed "); } - (void)dealloc { [myFoo release]; [myBar release]; [viewController release]; [window release]; [super dealloc]; } @end When the application starts, it loads the archive file into a data object. If the data object is null, the file doesn’t exist. If the file does exist, the data is unarchived. When the application terminates, it archives Foo. Because Bar contains constituent Foo objects in an array, it also archives those objects. The key for the archived Foo is “myfoo,” and “mybar” for the archived Bar object. Both Foo and Bar implement the NSCoding protocol. This allows them to be archived. Notice that Bar contains an NSMutableArray of Foo objects. Because NSMutableArray adopts the NSCoding protocol, NSMutableArray can be encoded and decoded. Moreover, the NSMutableArray knows to encode or decode its constituent elements. Chapter 15: Property Lists and Archiving 377 Now examine Bar’s copyWithZone method. Because Bar contains an NSMutableArray of Foo objects, when copying a Bar you must also copy the Bar’s Foo array. But you cannot just set the new Bar’s array to the old Bar’s array, as the new Bar’s array will simply be a pointer to the old Bar’s array. Instead you must create a new NSMutableArray and initialize the new array with the old array, being certain to specify copyItems as YES. By taking this step, the new Bar obtains a deep copy of the old Bar’s array of Foo objects. NOTE For more information on archiving, refer to “Apple’s Archives and Serializations Programming Guide for Cocoa.” Summary In this chapter, you learned how to persist an application’s data using property lists and archiving. Personally, I do not advocate using these techniques to persist more than a few objects to a file. Large object hierarchies are much better persisted using SQLite or the Core Data framework. But for small data amounts, persisting to a property list or archiving is fine. In this chapter, you learned methods for doing both. As a rule of thumb, if persisting variables not tied to particular objects, simply place them in a collection and persist the collection as a property list. But if persisting variables that are object properties, have the objects adopt the NSCoding protocol and archive the objects. If persisting a moderate to large amount of data, use SQLite or use the Core Data framework. If you wish using the data outside of an iPhone or Cocoa application, you should use SQLite. This page intentionally left blank [...]...Chapter 16 Data Persistence Using SQLite 3 79 380 iPhone SDK Programming: A Beginner’s Guide Key Skills & Concepts ● Creating a database and adding data to it ● Including the database in Xcode ● Reading from a database ● Making a database writable ● Inserting a record ● Updating a record ● Deleting a record T he SQLite database is a popular open-source database written in C The database is small and... and size variables NSData *data = [NSData dataWithBytes:rawData length:rawDataLength]; As you already know the database blob is an image, you initialize the PhotoDAO’s photo property using the UIImage’s initWithData method aPhoto.photo = [[UIImage alloc] initWithData:data]; This same technique works for other binary data as well (replacing UIImage with the appropriate class) Closing the Database When... icon (the blank paper graphic), and create a new database named myDatabase Note SQLite Manager automatically adds the sqlite extension 6 Click Create Table and create a new table named photos 7 Add three columns: id, name, and photo Make id an INTEGER and check Primary Key and Autoinc check boxes 8 Make name a VARCHAR and check only Allow Null 9 Make photo a BLOB and check only Allow Null 10 Your screen... in an application Unlike a database such as Oracle, SQLite is a C library included when compiling a program SQLite is part of the standard open-source Linux/BSD server stack, and as OS X is essentially FreeBSD, it was only natural Apple chose SQLite as the iPhone s embedded database Adding a SQLite Database Adding a SQLite database to your project involves two steps First, you must create the database... All this separation makes debugging and maintaining the program easier It also makes reading and understanding this chapter’s example code easier Opening the Database To keep the task’s length manageable and focused, rather than creating several data access methods in PhotosDAO, you only created one - (NSMutableArray *) getAllPhotos; This method returns an array of PhotoDAO objects The getAllPhotos method... NSData *data = [NSData dataWithBytes:rawData length: rawDataLength]; aPhoto.photo = [[UIImage alloc] initWithData:data]; [photosArray addObject:aPhoto]; [aPhoto release]; } if(sqlite3_finalize(statement) != SQLITE_OK){ NSLog(@"Failed to finalize data statement, normally error handling here."); } if (sqlite3_close(database) != SQLITE_OK) { NSLog(@"Failed to close database, normally error handling here.");... sqlite3_column_int(statement, 0); aPhoto.name = [NSString stringWithUTF8String:(char *) sqlite3_column_text(statement, 1)]; const char * rawData = sqlite3_column_blob(statement, 2); int rawDataLength = sqlite3_column_bytes(statement, 2); NSData *data = [NSData dataWithBytes:rawData length: rawDataLength]; aPhoto.photo = [[UIImage alloc] initWithData:data]; [photosArray addObject:aPhoto]; } if(sqlite3_finalize(statement)... Programming: A Beginner’s Guide Basic SQLite Database Manipulation If you have ever used a database from within a programming language, SQLite database manipulation using C should seem intuitive You open the database You create a prepared statement containing an SQL string That statement might have one or more parameters you bind values to After binding, you execute the statement If the statement returns results,... [fileManager copyItemAtPath:theDBPath toPath:newPath error: &error]; if (!success) { NSLog(@"Failed to copy database error handling here %@.", [error localizedDescription]); } } - (NSMutableArray *) getAllPhotos { NSMutableArray * photosArray = [[NSMutableArray alloc] init]; @try { NSFileManager *fileManager = [NSFileManager defaultManager]; NSArray * paths = NSSearchPathForDirectoriesInDomains (NSDocumentDirectory,... "PhotosDAO.h" @implementation PhotosDAO - (NSMutableArray *) getAllPhotos { NSMutableArray * photosArray = [[NSMutableArray alloc] init]; @try { NSFileManager *fileManager = [NSFileManager defaultManager]; NSString *theDBPath = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:@"myDatabase.sqlite"]; BOOL success = [fileManager fileExistsAtPath:theDBPath]; if (!success) { NSLog(@"Failed . SQLite Manager 384 iPhone SDK Programming: A Beginner’s Guide Basic SQLite Database Manipulation If you have ever used a database from within a programming language, SQLite database manipulation. writing an archive to disk are as follows. First, create an NSMutableData object. NSMutableData * theData = [NSMutableData data]; After creating the data object, create an NSKeyedArchiver, passing. SQLite Manager. Chapter 16: Data Persistence Using SQLite 381 5. Select the New icon (the blank paper graphic), and create a new database named myDatabase. Note SQLite Manager automatically adds

Ngày đăng: 13/08/2014, 18:20

Xem thêm: iPhone SDK Programming A Beginner’s Guide phần 9 ppsx

TỪ KHÓA LIÊN QUAN

Mục lục

    15 Property Lists and Archiving

    Try This: Archiving and Unarchiving an Object

    Try This: Archiving and Unarchiving an Object Hierarchy

    16 Data Persistence Using SQLite

    Adding a SQLite Database

    Try This: Creating a Simple Database Using FireFox SQLite Manager

    Basic SQLite Database Manipulation

    Statements, Preparing Statements, and Executing Statements

    Try This: Opening and Querying a Database

    SQLite Binding, Inserting, Updating, and Deleting

TÀI LIỆU CÙNG NGƯỜI DÙNG

  • Đang cập nhật ...

TÀI LIỆU LIÊN QUAN