iPhoneOS : Arkivera egna objekt
by trouf on 12/03/2010Låt oss anta att vi vill designa en applikation som innehåller ett antal egendefinierade objekt.
Dessa behöver vi spara på något sätt, t.ex. när användaren stänger av applikationen eller om användaren skulle få ett telefonsamtal under tiden som applikationen körs. Utifall att detta händer vill vi att applikationens variabler ska bevaras, och att även våra egendefinierade objekt ska sparas på samma sätt som andra inställningar sparas.
Att spara användardata är en återkommande punkt i de flesta iPhone-applikationer, och jag brukar använda NSUserDefaults för att på ett enkelt sätt spara och hämta data.
Data sparas på följande sätt
NSInteger intToSave = 23; NSUserDefaults *preferences = [NSUserDefaults standardUserDefaults]; [preferences setInteger:intToSave forKey:@"keyToSavedInt"];
Och hämtas på följande sätt…
NSInteger intToRetrieve; NSUserDefaults *preferences = [NSUserDefaults standardUserDefaults]; intToRetrieve = [preferences integerForKey:@"keyToSavedInt"];
I min mening det absolut smidigaste sättet att hantera användardata på… det vill säga sålänge som man bara sparar Obj-C datatyper. Men om man däremot vill spara en array av egendefinierade typer, ja då blir det lite mindre smidigt.
Extra smidigt blir det om det dessutom är en hierarki av objekt.
Säg att vi har en applikation som ska hålla koll på lastbilar och deras last.
Låt oss använda en NSMutableArray för att hålla koll på alla lastbilar, och sedan definiera en klass för lastbilar, och en klass för last.
En näst intill pinsamt förenklad implementation av klassen Lastbil följer här.
Lastbil.h
#import <Foundation/Foundation.h>
#import "Last.h"
@interface Lastbil : NSObject {
Last *last;
}
@property(nonatomic,retain) Last *last;
@end
Lastbil.m
#import "Lastbil.h"
@implementation Lastbil
@synthesize last
-(id)init
{
if (self = [super init])
{
//Init
}
return self;
}
- (void)dealloc
{
[self.last release];
[super dealloc];
}
@end
Och så lasten…
Last.h
#import <Foundation/Foundation.h>
@interface Last : NSObject {
NSString *beskrivning;
}
@property(nonatomic,copy) NSString *beskrivning;
@end
Last.m
#import "Last.h"
@implementation Last
@synthesize beskrivning;
- (id)initWithBeskrivning: (NSString*)b
{
self.beskrivning = b;
return self;
}
- (void)dealloc
{
[self.beskrivning release];
[super dealloc];
}
@end
Ja nåt i den stilen. Blind kod och en knapphändig implementation, precis som det ska va.
Då är själva objekten deklarerade, det som återstår är att.. ja.. använda dem.
NSMutableArray *lastbilar = [[NSMutableArray alloc] init]; Lastbil *lastbil1 = [[Lastbil alloc] init]; Lastbil *lastbil2 = [[Lastbil alloc] init]; lastbil1.last = [[Last alloc] initWithBeskrivning:@"Fisk"]; lastbil2.last = [[Last alloc] initWithBeskrivning:@"Kött"]; [lastbilar addObject:lastbil1]; [lastbilar addObject:lastbil2]; [lastbilar release];
Då har vi en datastruktur som innehåller två lastbilar, den ena med fisk i lasten och den andra med gott, mört kött i lasten.
Om vi nu vill spara denna datastruktur till NSUserDefaults så skulle vi kunna göra det genom att först arkivera den till ett NSData-objekt med NSKeyedArchiver..
NSData *lastbilData = [NSKeyedArchiver archivedDataWithRootObject:lastbilar];
MEN detta är inte rumba, och kommer inte att fungera då våra egendefinierade objekt (Lastbil, Last) inte implementerar NSCoding protokollet. Alla objekt måste, om de ska kunna arkiveras, implementera metoder för hur de ska arkiveras och hur de ska avarkiveras. Enligt NSCoding måste alltså våra objekt implementera följande metoder.
- (void)encodeWithCoder:(NSCoder *)encoder - (id)initWithCoder:(NSCoder *)decoder
Så låt oss implementera dessa metoder först i Lastbil.m. Det vi vill göra är att specifiera vilka av objektets egenskaper som ska arkiveras, och under vilka nycklas värdena ska arkiveras, detsamma för avarkivering.
- (void)encodeWithCoder:(NSCoder *)coder;
{
[coder encodeObject:self.last forKey:@"last"];
}
- (id)initWithCoder:(NSCoder *)coder;
{
if (self = [super init])
{
self.last = [coder decodeObjectForKey:@"last"];
}
return self;
}
…och sedan i Last.m
- (void)encodeWithCoder:(NSCoder *)coder;
{
[coder encodeObject:self.beskrivning forKey:@"beskrivning"];
}
- (id)initWithCoder:(NSCoder *)coder;
{
if (self = [super init])
{
self.beskrivning = [coder decodeObjectForKey:@"beskrivning"];
}
return self;
}
That’s pretty much it.
Nu går det bra att arkivera hela objekthierarkin, eftersom alla objekt i hierarkin kan arkiveras (NSCoder).
NSData *lastbilData = [NSKeyedArchiver archivedDataWithRootObject:lastbilar];
Och ett objekt av typen NSData går givetvis att spara till NSUserDefaults precis som motsvarande enkla datatyper.
NSUserDefaults *preferences = [NSUserDefaults standardUserDefaults]; NSData *lastbilData = [NSKeyedArchiver archivedDataWithRootObject:lastbilar]; [preferences setObject:lastbilData forKey:@"Lastbilar"];
Och går att läsa tillbaka, med minimal ansträngning.
NSUserDefaults *preferences = [NSUserDefaults standardUserDefaults];
NSData *lastbilData = [preferences objectForKey:@"Lastbilar"];
if (lastbilData != nil)
{
NSArray *gamlaLastbilar = [NSKeyedUnarchiver unarchiveObjectWithData:lastbilData];
if (gamlaLastbilar != nil)
{
//Presentera information
}
}
Och så gör man alltså för att arkivera sina egna objekt!
Andra bloggar om: iphone, apple, programmering, xcode
stefan.pataky@gmail.com
There is 1 comment in this article: