0

I have a very strange bug that I've bee trying to track down for several days. I'm saving state data for a game in a file in the app's Documents directory.

Everything had been working fine until a recent iOS update (not sure exactly when, somewhere around 9.0). Suddenly, data is not being archive / unarchived correctly.

The weird part is the code works fine when I run it from Xcode with the iPad tethered to my MAC or when in the emulator. When i download the app from the iTunes using TestFlight, it no longer works. This has made it extremely difficult to debug.

I've checked and double checked everything, I'm using the URL path, added error trapping code, etc. but archiving fails to work correctly when the app is installed from iTunes via TestFlight.

As a last resort I added new code that archives my object, immediately unarchives it into another variable, then display some data in a label. The resulting object contains null data.

No exceptions are thrown.

Just to reiterate, the code doesn't work ONLY when the app in installed from iTunes.

Here is the code snippet;

NSString *documentDirectory = [[[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject] path];
    NSString* filePath =  [documentDirectory stringByAppendingPathComponent:@"playerTest.data"];
    LBYPlayerData* pd1 = [[LBYPlayerData alloc ]init];
    pd1.currentCountryID = 1;
    pd1.lsn = @"123.456";
    BOOL success = [NSKeyedArchiver archiveRootObject:pd1 toFile:filePath];
    NSAssert(success, @"archiveRootObject failed");
    LBYPlayerData* pd2 = nil;
    @try {
        pd2 = [NSKeyedUnarchiver unarchiveObjectWithFile:filePath];
    } @catch (NSException *exception) {
        playerDataLabel.text = [NSString stringWithFormat:@"%@",exception.name];
        playerUndoDataLabel.text = [NSString stringWithFormat:@"%@",exception.description];
    } @finally {
        NSAssert((pd2 != nil), @"archivePlayerDataUndo failed to unarchive");
        playerDataLabel.text = [NSString stringWithFormat:@"path: %@",filePath];
        playerUndoDataLabel.text = [NSString stringWithFormat:@"Undo Country:%li LSN:%@",(long)pd2.currentCountryID,pd2.lsn];
    }

Here is the data model

//
//  LBYPlayerData.h

#import <Foundation/Foundation.h>

@interface LBYPlayerData : NSObject

@property (nonatomic,readonly) BOOL isNewGame;
@property (nonatomic) NSInteger playerID;
@property (nonatomic) NSInteger usCardIdx;
@property (nonatomic) NSInteger drawDeckIdx;
@property (nonatomic) NSInteger discardDeckIdx;
@property (nonatomic) NSInteger removeDeckIdx;
@property (nonatomic) NSInteger currentCountryID;
@property (nonatomic) NSString* lsn;
@property (nonatomic) NSString* build;

@end

//
//  LBYPlayerData.m

#import "LBYPlayerData.h"

@implementation LBYPlayerData

-(id)init
{
    self = [super init];
    _isNewGame = YES;
    return self;
}

-(void)encodeWithCoder:(NSCoder *)aCoder

{
//    NSLog(@"Saving Player Data");
    _isNewGame = NO;
    [aCoder encodeBool:_isNewGame         forKey: NSStringFromSelector(@selector(isNewGame))];
    [aCoder encodeInt64:_playerID         forKey: NSStringFromSelector(@selector(playerID))];
    [aCoder encodeInt64:_usCardIdx        forKey: NSStringFromSelector(@selector(usCardIdx))];
    [aCoder encodeInt64:_drawDeckIdx      forKey: NSStringFromSelector(@selector(drawDeckIdx))];
    [aCoder encodeInt64:_discardDeckIdx   forKey: NSStringFromSelector(@selector(discardDeckIdx))];
    [aCoder encodeInt64:_removeDeckIdx    forKey: NSStringFromSelector(@selector(removeDeckIdx))];
    [aCoder encodeInt64:_currentCountryID forKey: NSStringFromSelector(@selector(currentCountryID))];
    [aCoder encodeObject:_lsn             forKey: NSStringFromSelector(@selector(lsn))];
    [aCoder encodeObject:_build           forKey: NSStringFromSelector(@selector(build))];
//    NSLog(@"Current Counry: %li",(long)_currentCountryID);
}

-(id)initWithCoder:(NSCoder *)aDecoder
{
//    NSLog(@"Loading Player Data");
    self = [self init];
    if (self) {
        _isNewGame               =[aDecoder decodeBoolForKey:NSStringFromSelector(@selector(isNewGame))];
        [self setPlayerID        :[aDecoder decodeIntegerForKey:NSStringFromSelector(@selector(playerID))]];
        [self setUsCardIdx       :[aDecoder decodeIntegerForKey:NSStringFromSelector(@selector(usCardIdx))]];
        [self setDrawDeckIdx     :[aDecoder decodeIntegerForKey:NSStringFromSelector(@selector(drawDeckIdx))]];
        [self setDiscardDeckIdx  :[aDecoder decodeIntegerForKey:NSStringFromSelector(@selector(discardDeckIdx))]];
        [self setRemoveDeckIdx   :[aDecoder decodeIntegerForKey:NSStringFromSelector(@selector(removeDeckIdx))]];
        [self setCurrentCountryID:[aDecoder decodeIntegerForKey:NSStringFromSelector(@selector(currentCountryID))]];
        [self setLsn             :[aDecoder decodeObjectForKey :NSStringFromSelector(@selector(lsn))]];
        [self setBuild           :[aDecoder decodeObjectForKey :NSStringFromSelector(@selector(build))]];
   }
    return self;
}

@end
4

1 回答 1

0

The problem was with NSAssert. I found code that was calling the function to archive the object within an NSAssert statement.

于 2016-05-28T23:18:18.683 回答