如何在 Objective-C 中保存另一个类正在使用的类对象?

Posted

技术标签:

【中文标题】如何在 Objective-C 中保存另一个类正在使用的类对象?【英文标题】:How you save a class object being used by another class in Objective-C? 【发布时间】:2012-12-20 18:23:30 【问题描述】:

我正在为 iPad 和 iPod 制作一个 Cookbook 应用程序,并且我的 Cookbook 类中有一组我的 Recipe 类。

@interface Cookbook : NSObject<NSCoding>
NSMutableArray* recipes;

这是在我的食谱课上,在我的食谱课上我有这个:

@interface Recipe : NSObject<NSCoding>
NSString* name;
NSMutableArray* ingredients; //List of ingredients for the recipe
UIImage* recipePicture;
NSMutableArray* instructions;
unsigned int prepTime;//in seconds
NSDate* dateAdded;

(实际上我这里有更多变量,但我不想过多地淹没它)

我的问题基本上在于保存/加载功能。我之前在这里问过一个类似的问题: How can I save an Objective-C object that's not a property list object or is there a better way for this than a property list?

这让我决定最好使用 NSCoding,而且我也已经按照 NSCoding 建议的方式为它实现了一个方法。

我的主要问题是我无法存储和成功检索食谱。

我也无法将目录添加到我的 RecipeList.plist 文件中以存储食谱。

任何帮助将不胜感激,因为这是我无法继续申请的原因。

在我的 Cookbook.m 中,我有:

-(id) initWithCoder:(NSCoder *)aDecoder
NSLog(@"Init With Coder - Cookbook");
if(self = [super init])
    recipes = [aDecoder decodeObjectForKey:@"recipes"];

return self;

在我的 Recipe.m 中:

-(id) initWithCoder:(NSCoder *)aDecoder
if(self = [super init])
    name = [aDecoder decodeObjectForKey:@"name"];
    ingredients = [aDecoder decodeObjectForKey:@"ingreds"];
    recipePicture = [aDecoder decodeObjectForKey:@"recipePict"];

return self;

再一次,我有更多的变量,这只是为了简单起见。 此外,这是我尝试获取 RecipeList.plist 的文件路径:

+(NSString*) filePath
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,     NSUserDomainMask, YES);
NSString *path = [paths objectAtIndex:0];
path = [path stringByAppendingPathComponent:@"RecipeList.plist"];

NSLog(@"%@",path);
return path;

我在 AppDelegate.m 中尝试保存方法:

-(void) save:(NSString *)path cookbook:(Cookbook *)cookbook
BOOL b = [[NSFileManager defaultManager] fileExistsAtPath:path];
NSLog(@"File exists: %i",b); //1 = exists, 0 = doesn't

NSMutableData* data = [[NSMutableData alloc] init];
if(data) //If the data object was successfully initialized
    NSKeyedArchiver* archiver = [[NSKeyedArchiver alloc] initForWritingWithMutableData:data];
    if(archiver)
        //Encode the recipe using the coder method defined in recipe.
        [archiver encodeInt:1 forKey:@"Version"];
        [archiver encodeObject:cookbook forKey:@"Cookbook"];
        [archiver finishEncoding];

        [data writeToFile:path atomically:YES];
    


还有我的加载方法:

-(Cookbook *) loadCookbook:(NSString *)path
BOOL b = [[NSFileManager defaultManager] fileExistsAtPath:path];
NSLog(@"File exists: %i",b);

Cookbook* ret = nil;
NSData* data = [NSData dataWithContentsOfFile:path];
if(data)
    NSKeyedUnarchiver* unarchiver = [[NSKeyedUnarchiver alloc] initForReadingWithData:data];
    int version = [unarchiver decodeIntForKey:@"Version"];
    if(version == 1)
        ret = (Cookbook*) [unarchiver decodeObjectForKey:@"Cookbook"];
    
    [unarchiver finishDecoding];

return ret;

我的 Recipe 类也有一个与此非常相似的保存和加载方法。

再次感谢您提供任何帮助,感谢您抽出宝贵时间阅读本文。

编辑:这是 Recipe.m 中的 encodeWithCoder 方法,为简洁起见省略了一些变量:

-(void) encodeWithCoder:(NSCoder *)aCoder
NSLog(@"Encoding Recipe.");
[aCoder encodeObject:name forKey:@"name"];
[aCoder encodeObject:ingredients forKey:@"ingreds"];
[aCoder encodeObject:recipePicture forKey:@"recipePict"];
[aCoder encodeObject:instructions forKey:@"instructs"];
[aCoder encodeObject:category forKey:@"categ"];
[aCoder encodeObject:dateAdded forKey:@"dateAdd"];
[aCoder encodeInt:prepTime forKey:@"prepTime"];


在 Cookbook.m 中:

-(void) encodeWithCoder:(NSCoder *)aCoder
NSLog(@"Encoding cookbook.");
[aCoder encodeObject:recipes forKey:@"recipes"];

【问题讨论】:

无论有多少类正在访问它,您都可以从保存按钮中保存它,从打开按钮操作中检索它。如果你想要线程安全,那么你可以选择 atomic,但是 atomic 并不是完全线程安全的。 也许题外话,但我会使用核心数据。这将是一个简单的馅饼:) 你的encodeWithCoder: 实现中有什么? 抱歉,代码好长,我还没看完,你是问怎么做还是有一部分代码不起作用? 我还想说,我认为仅仅为了使用 Core Data 实现它而拆除你所做的一切是没有意义的。正如一些人可能推断的那样,Core Data 并不是万能的。 【参考方案1】:

我已经“几乎”复制粘贴了您的代码,经过一些小的调整后,我已经启动并运行了它。

在食谱中,我添加了:

- (id)init 
    if (self = [super init]) 
        recipes = [NSMutableArray array];
    
    return self;

- (void)addRecipe:(Recipe *)recipe 
    [recipes addObject:recipe];

你可能已经有了这些?我假设您正在某处实例化数组?

然后使用这个测试例程,完美地创建、使用和保存食谱:

NSString *path = [self filePath];
Cookbook *cookbook = [self loadCookbook:path];

if (cookbook) 
    NSLog(@"Loaded cookbook: %@", cookbook);

else 
    cookbook = [[Cookbook alloc] init];


Recipe *recipe = [[Recipe alloc] init];
recipe->name = @"The name";
[cookbook addRecipe:recipe];

[self save:path cookbook:cookbook];
NSLog(@"Saved cookbook: %@", cookbook);

fyi:为简洁起见,我将配方的实例变量设为@public;希望您正在使用访问器 (@property)。

您使用自动或手动引用计数?

【讨论】:

很抱歉回复晚了,但我目前正在使用自动引用计数。明天我会尽快尝试你的建议,并告诉你进展如何。我非常感谢您的帮助(我已经被这个问题困扰了很长一段时间,发现如果不首先完善这个功能——到目前为止最重要的功能,我真的无法取得更大的成就)。 我已经试过了,由于某种原因,我的 loadCookbook 中的 NSLog(@"file exists: %i",b) 语句:方法总是说文件 RecipeList.plist 没有存在。在这一点上,这似乎是我问题的核心;但是,我可能是错的。 我建议编写一小段代码,在您指定的位置创建一个文件。看看是否可行...您可以在 ~/Library/Application Support/iPhone Simulator//Applications// 检查模拟器文件系统的内容

以上是关于如何在 Objective-C 中保存另一个类正在使用的类对象?的主要内容,如果未能解决你的问题,请参考以下文章

在 Objective-C 中,如何设置属性的属性,即设置为另一个类属性的类?

来自另一个类的 Objective-C 设置属性返回 Null

iOS Objective-C:如何从另一个类调用 Push Segue

如何在 Objective-C 中将对象类型转换为另一个类

如何从 .m 函数获取结果到 .mm 类 Objective-C 与 Qt 混合

iOS - 如何使用 JSON 和 Objective-C 提取和存储数据