简体   繁体   中英

How to unarchive BOOL property with NSKeyedUnarchiver?

I have class for playing sound in app.
I implemented on/off switch(on GUI), for disabling and enablining sound play. I am using BOOL property for that and this is working.
Now I am trying to implement saving that BOOL (is sound on/off) in file so that next time when app is started state is automatically restored.
For that I am using NSCoding protocol, archiving is working but I have problem with unarchiving.
My app will not start it will just show black screen.

This is my code, only part that I think it is important.

GTN_Sound.h

#import <Foundation/Foundation.h>
#import <AudioToolbox/AudioToolbox.h> // for playing sound

@interface GTN_Sound : NSObject <NSCoding>

@property(nonatomic, readwrite, unsafe_unretained) BOOL isSoundOn;

+ (id)sharedManager;
- (void)playWinSound;
- (void)playLoseSound;

@end

GTN_Sound.m

#pragma mark - NSCoding Methods

- (void)encodeWithCoder:(NSCoder *)aCoder
{
    [aCoder encodeBool:self.isSoundOn forKey:@"isSoundOn"];
}

- (instancetype)initWithCoder:(NSCoder *)aDecoder
{
    self = [GTN_Sound sharedManager];

    if (self) {
        _isSoundOn = [aDecoder decodeBoolForKey:@"isSoundOn"];
    }

    return self;

}

I think that code is so far so good ?
Continuation of GTN_Sound.m

#pragma mark - itemArchivePath Method

- (NSString *)itemArchivePath
{
    // Make sure that the first argument is NSDocumentDirectory
    // and not NSDocumentationDirectory
    NSArray *documentDirectories =
    NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,
                                        NSUserDomainMask, YES);
    // Get the one document directory from that list
    NSString *documentDirectory = [documentDirectories firstObject];

    return [documentDirectory stringByAppendingPathComponent:@"sound.archive"];
}

#pragma mark - custom seter Method

- (void)setIsSoundOn:(BOOL)theBoolean {

    NSLog(@"My custom setter\n");
    if(_isSoundOn != theBoolean){
       _isSoundOn = theBoolean;

       NSString *path = [self itemArchivePath];

       [NSKeyedArchiver archiveRootObject:self toFile:path]; // this is doing save
}

}

It is done that for every time when switch on GUI is changed I do the savings.
This look fine from my side, because I am not expecting that user will change this many times.
Now the unarchiving comes and I thin that here are some problems.

#pragma mark - Singleton Methods

+ (id)sharedManager {
    static GTN_Sound *sharedMyManager = nil;

    // to be thread safe
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        sharedMyManager = [[self alloc] initPrivate];
    });

    return sharedMyManager;
}

- (instancetype)init
{
    @throw [NSException exceptionWithName:@"Singleton"
                                   reason:@"Use +[GTN_Sound sharedManager]"
                                 userInfo:nil];
    return nil;
}

// Here is the real (secret) initializer
- (instancetype)initPrivate
{
    self = [super init];

    if (self) {
        NSString *path = [self itemArchivePath]; // do as iVar, for futture
        self = [NSKeyedUnarchiver unarchiveObjectWithFile:path];
        //_isSoundOn = [NSKeyedUnarchiver unarchiveObjectWithFile:path];

    }

    return self;
}

I think that problem is in this line

self = [NSKeyedUnarchiver unarchiveObjectWithFile:path];

But have no idea how to fix it.

I have read that when I am doing archiving, that I need to archive all properties of object.
Does this apply to private ivars also ?

Any help is appreciated.

Thanks

You can only archive NSObject inheriting objects. ie. NSNumber

[NSKeyedArchiver archiveRootObject:@YES toFile:path]; //to save
_isSoundOn = [[NSKeyedUnarchiver unarchiveObjectWithFile:path] boolValue]; //to load

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM