如何在 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/以上是关于如何在 Objective-C 中保存另一个类正在使用的类对象?的主要内容,如果未能解决你的问题,请参考以下文章
在 Objective-C 中,如何设置属性的属性,即设置为另一个类属性的类?
来自另一个类的 Objective-C 设置属性返回 Null
iOS Objective-C:如何从另一个类调用 Push Segue