0

さて、私はこの問題を解決するために過去 2 日間を費やしてきました。プロパティリストを制御するクラスがあります。これはシングルトンクラスとして使用されるため、一度だけインスタンス化され、値を plist に保存するために使用される別のメソッドが 1 つあります。

マルチタスクバーからアプリを削除するまで(つまり、アプリを完全に閉じるまで)、plistのすべての値がnullにリセットされるまで、何をしてもplistはうまく機能します..しかし、plistは失われません.

そのため、読み取りおよび書き込み機能のためにルート ドキュメント ディレクトリに作成した plist の値を上書きしている可能性があると考えています。私のコード例で、皆さんが私の間違いを見つけることができることを願っています...他に何を追加する必要があるのか​​ わかりません..この問題に答えるのに役立つ質問がある場合は、教えてください知る。

どんな助けでも大歓迎です、そして私の子供たちの子供たちの子供たちはあなたにデビューします.

#import "EnginePropertiesController.h"

static EnginePropertiesController *sharedMyManager = nil;

@implementation EnginePropertiesController

@synthesize pSignature;
@synthesize pVersion;
@synthesize rNumber;
@synthesize dVReturned;
@synthesize cacheValue;

@synthesize manu;
@synthesize mod;
@synthesize submod;


#pragma mark Singleton Methods
+ (id)sharedManager {
    @synchronized(self) {
        if (sharedMyManager == nil)
            sharedMyManager = [[self alloc] init];
    }
    return sharedMyManager;
}
- (id)init {
    if (self = [super init]) {

            // get paths from root direcory
            NSArray *paths = NSSearchPathForDirectoriesInDomains (NSDocumentDirectory, NSUserDomainMask, YES);
            // get documents path
            NSString *documentsPath = [paths objectAtIndex:0];
            // get the path to our Data/plist file
            NSString *plistPath = [documentsPath stringByAppendingPathComponent:@"EngineProperties.plist"];
            NSLog(@"myplist path read = %@", plistPath);

            // check to see if Data.plist exists in documents
            if (![[NSFileManager defaultManager] fileExistsAtPath:plistPath])
            {
                // if not in documents, get property list from main bundle
                plistPath = [[NSBundle mainBundle] pathForResource:@"EngineProperties" ofType:@"plist"];

            }

            // read property list into memory as an NSData object
            NSData *plistXML = [[NSFileManager defaultManager] contentsAtPath:plistPath];
            NSString *errorDesc = nil;
            NSPropertyListFormat format;
            // convert static property liost into dictionary object
            NSDictionary *tempRoot = (NSMutableDictionary *)[NSPropertyListSerialization propertyListFromData:plistXML mutabilityOption:NSPropertyListMutableContainersAndLeaves format:&format errorDescription:&errorDesc];
            manu = [cacheValue objectForKey:@"Manu"];
            mod = [cacheValue objectForKey:@"Mod"];
            submod = [cacheValue objectForKey:@"SubMod"];
            if (tempRoot && [tempRoot count]){
                // assign values
                self.pVersion = [tempRoot objectForKey:@"PSignature"];
                self.pVersion = [tempRoot objectForKey:@"PVersion"];
                self.rNumber = [tempRoot objectForKey:@"RNumber"];
                self.dVReturned = [tempRoot objectForKey:@"DVReturned"];
                cacheValue = [tempRoot objectForKey:@"Cache Value"];
        }
    }
    return self;
}

- (void) saveData:(NSString *)methodName pSignature:(NSString *)TemppSignature pVersion:(NSNumber *)TemppVersion rNumber:(NSNumber *)TemprNumber dVReturned:(NSNumber *)TempdvReturned cacheValue:(NSNumber *)cValue
{
    // get paths from root direcory
    NSArray *paths = NSSearchPathForDirectoriesInDomains (NSDocumentDirectory, NSUserDomainMask, YES);
    // get documents path
    NSString *documentsPath = [paths objectAtIndex:0];
    // get the path to our Data/plist file
    NSString *plistPath = [documentsPath stringByAppendingPathComponent:@"EngineProperties.plist"];

    // set the variables to the values in the text fields
    self.pSignature = TemppSignature;
    self.pVersion = TemppVersion;
    self.rNumber = TemprNumber;
    self.dVReturned = TempdVReturned;

    //This checks with methodName I would like to save the value from
    //The reason for this is there are 3 different cache values I get at seperate times to save This if statment just makes sure they are in the correct order.
    if ([methodName isEqualToString:@"Getmanu"]) {
        self.manu = cValue; 
    } else if ([methodName isEqualToString:@"GetMod"]) {
        self.mod = cValue;
    } else if ([methodName isEqualToString:@"GetSubMod"]) {
        self.submod = cValue;
    }        

    //Set up cacheValue Dictionary that will be added to the property list root dictionary
    self.cacheValue = [NSDictionary dictionaryWithObjectsAndKeys:
                       manu, @"Manu",
                       mod, @"Mod",
                       subMod, @"SubMod", nil];

    //Pass appropriate values into plist
    NSDictionary *plistDict = [NSDictionary dictionaryWithObjectsAndKeys:
                               protocolSignature, @"Protocol Signature",
                               pVersion, @"Protocol Version",
                               rNumber, @"Request Number",
                               dVReturned, @"Data Version returned",
                               cacheValue, @"Cache Value", nil];


    NSString *error = nil;
    // create NSData from dictionary
    NSData *plistData = [NSPropertyListSerialization dataFromPropertyList:plistDict format:NSPropertyListXMLFormat_v1_0 errorDescription:&error];

    // check is plistData exists
    if(plistData) {
        // write plistData to our Data.plist file
        [plistData writeToFile:plistPath atomically:YES];
    } else {
        NSLog(@"Error in saveData: %@", error);
    }
}


@end
4

1 に答える 1

2

問題: nil 値

ここに問題があります: pVersion は 2 回割り当てられますが、pSignature は残りnilます。

self.pVersion = [tempRoot objectForKey:@"PSignature"];
self.pVersion = [tempRoot objectForKey:@"PVersion"];

これはおそらく

self.pSignature = [tempRoot objectForKey:@"PSignature"];
self.pVersion = [tempRoot objectForKey:@"PVersion"];

これにより、時間を節約する際に問題が発生します。

NSDictionary *plistDict = [NSDictionary dictionaryWithObjectsAndKeys:
                           pSignature, @"PSignature",
                           pVersion, @"PVersion",
                           rNumber, @"RNumber",
                           dVReturned, @"DVReturned",
                           cacheValue, @"Cache Value", nil];

このコンストラクターは、引数がいくつあるかを認識していません。ヒットするまで処理を続けnilます。pSignatureが nil の場合、空の辞書が保存されます。

修正: 堅牢な NSDictionary の作成

当面の解決策はpSignature読みを修正することですが、 を使用して辞書を作成するのは常に脆弱dictionaryWithObjectsAndKeys:です。を使用して、各オブジェクトを個別に保存する方がはるかに優れていますsetObject:forKey。オブジェクトが nil の場合は例外がスローされるため、呼び出す前にテストしてください。

NSMutableDictionary *plistDict = [NSMutableDictionary dictionary];
if (pSignature) [plistDict setObject:pSignature forKey:@"PSignature"];
if (pVersion) [plistDict setObject:pVersion forKey:@"PVersion"];
// ... and so on.

代替手段: NSCoding

ストレージのもう 1 つのオプションは、シリアル化です。Archives and Serializations Programming Guideを参照してください。これにはトレードオフがあります。保存と読み込みが機能する場合は簡単ですが、結果のファイルは人間が判読しにくくなります。

デバッグ

最後に、次のような場合に役立つログ ステートメント、ブレークポイント、またはダイアログ ボックスを配置する 3 つの場所を示します。

  1. 読み込まれている辞書と保存されている辞書をログに記録します。アプリを開いてすぐに保存をトリガーした場合、辞書は同一ですか?
  2. arrayWithObjects:およびのような nil で終わるメソッドに送信される最初の引数を確認しますdictionaryWithObjectsAndKeys:
  3. シミュレーターで、保存に使用したパスをログに記録し、Finder で開きます。そこにファイルはありますか?プロパティ リストの場合は、XCode で開いて、期待する内容が含まれているかどうかを確認できます。
于 2012-04-12T04:19:30.243 に答える