我在将自定义对象(WSWCMPost)放入NSMutableArray然后稍后访问存储在其中的数据时遇到问题。以下是相关代码。
这是" WSWCMPost.h"
#import <Foundation/Foundation.h>
@interface WSWCMPost : NSObject
{
NSString *postBody;
NSString *postTitle;
NSString *postID;
}
@property (nonatomic, retain) NSString *postBody, *postTitle, *postID;
- init;
- (id)initWithID: (NSString*)ID AndBody: (NSString*)body AndTitle: (NSString*)title;
- (NSString*)postBody;
- (NSString*)postTitle;
- (NSString*)postID;
这是&#34; WSWCMPost.m&#34;
#import "WSWCMPost.h"
@implementation WSWCMPost
@synthesize postBody, postTitle, postID;
- (id)init {
self = [super init];
if(self) {
postID = @"none";
postBody = @"none";
postTitle = @"none";
}
}
- (id)initWithID: (NSString*)ID AndBody: (NSString*)body AndTitle: (NSString*)title {
postTitle = title;
postID = ID;
postBody = body;
}
@end
这是&#34; viewDidLoad&#34;导致我的问题的方法
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
self.detailViewController = (WSWCMDetailViewController *)[[self.splitViewController.viewControllers lastObject] topViewController];
// getting an NSString
NSLog(@"Pulling saved blogs...");
NSUserDefaults *currentDefaults = [NSUserDefaults standardUserDefaults];
NSData *dataRepresentingSavedArray = [currentDefaults objectForKey:@"wswcmt1"];
if (dataRepresentingSavedArray != nil)
{
NSArray *oldSavedArray = [NSKeyedUnarchiver unarchiveObjectWithData:dataRepresentingSavedArray];
if (oldSavedArray != nil)
_objects = [[NSMutableArray alloc] initWithArray:oldSavedArray];
else
_objects = [[NSMutableArray alloc] init];
}
NSLog(@"Pulled saved blogs...");
NSLog(!_objects ? @"Yes" : @"No");
@try {
NSLog(@"_objects description: %@",[_objects description]);
NSLog(@"_objects[0] postID: %@",[[_objects objectAtIndex:0] postID]);
}
@catch (NSException *exception) {
NSLog(@"Caught exception %@", exception);
NSLog(@"Objects doesnt exist, allocating memory...");
_objects = [[NSMutableArray alloc] init];
WSWCMPost *testPost = [[WSWCMPost alloc] initWithID:@"noID" AndBody:@"noBody" AndTitle:@"noTitle"];
[_objects insertObject:testPost atIndex:0];
[[NSUserDefaults standardUserDefaults] setObject:[NSKeyedArchiver archivedDataWithRootObject:_objects] forKey:@"wswcmt1"];
}
if (!_objects ) {
NSLog(@"Objects doesnt exist...");
_objects = [[NSMutableArray alloc] init];
WSWCMPost *testPost = [[WSWCMPost alloc] initWithID:@"dne" AndBody:@"Dne" AndTitle:@"DNe"];
[_objects insertObject:testPost atIndex:0];
[[NSUserDefaults standardUserDefaults] setObject:[NSKeyedArchiver archivedDataWithRootObject:_objects] forKey:@"wswcmt"];
}
[self refreshButton:nil];
}
最后,这是输出
2012-06-25 22:39:49.345 WSWCM[4406:907] Pulling saved blogs...
2012-06-25 22:39:49.352 WSWCM[4406:907] Pulled saved blogs...
2012-06-25 22:39:49.355 WSWCM[4406:907] Yes
2012-06-25 22:39:49.356 WSWCM[4406:907] _objects description: (null)
2012-06-25 22:39:49.358 WSWCM[4406:907] _objects[0] postID: (null)
2012-06-25 22:39:49.360 WSWCM[4406:907] Objects doesnt exist...
2012-06-25 22:39:49.363 WSWCM[4406:907] Refresh Triggered...
我认为这是所有相关的代码。如果我忘了什么,请告诉我。这个问题困扰了我好几个小时......
答案 0 :(得分:1)
虽然我不肯定为什么它会给你NSStrings
而不是正常爆炸,但问题似乎源于你的自定义类WSWCMPost
不符合{ {3}}协议。如果要将自定义对象存储在NSUserDefaults
中,请确保自定义对象实现此协议,因为它不知道如何序列化数据。
更确切地说,您必须将这些方法添加到您的类实现中:
- (id)initWithCoder:(NSCoder *)coder {
self = [self initWithID:[coder decodeObjectForKey:@"id"] AndBody:[coder decodeObjectForKey:@"body"] AndTitle:[coder decodeObjectForKey:@"title"]];
return self;
}
- (void)encodeWithCoder:(NSCoder *)coder {
[encoder encodeObject:postID forKey:@"id"];
[encoder encodeObject:postBody forKey:@"body"];
[encoder encodeObject:postTitle forKey:@"title"];
}
这将允许NSCoder
序列化数据。完成此操作后,您应该清除NSUserDefaults
当前存储的所有信息,以确保它不再包含NSString
,但一切都应该正常运行。当然,如果更改WSWCMPost
对象存储的数据,则必须更新这两种方法。
答案 1 :(得分:0)
您的输出肯定会显示代码中的错误。
2012-06-25 21:51:07.691 WSWCM[4049:907] -[__NSCFString postID]: unrecognized selector sent to instance 0x1d003e80
2012-06-25 21:51:07.696 WSWCM[4049:907] Caught exception -[__NSCFString postID]: unrecognized selector sent to instance 0x1d003e80
这两行告诉您NSString对象无法识别选择器postID。这个提示应该足以找出你需要深入了解的地方。
有关详细信息,请参阅此Storing custom objects in an NSMutableArray in NSUserDefaults。
答案 2 :(得分:0)
另外需要提及的是,您与getter / setter及其各自的实例变量发生冲突。所以你的实现是:
<强>接口强>
@interface WSWCMPost : NSObject
{
NSString *postBody; // don't need to do these anymore for properties
NSString *postTitle;
NSString *postID;
}
@property (nonatomic, retain) NSString *postBody, *postTitle, *postID;
<强>实施强>
@implementation WSWCMPost
@synthesize postBody, postTitle, postID;
- (id)init {
self = [super init];
if(self) {
postID = @"none"; // not prefixing your variables with 'self' so they are not getting retained
postBody = @"none";
postTitle = @"none";
}
}
@end
以下是你应该如何写出来的:
<强>接口强>
/** NOTE: No need to specify your instance variables here anymore, just the properties */
@interface WSWCMPost : NSObject
@property (nonatomic, retain) NSString *postID;
@property (nonatomic, retain) NSString *postTitle;
@property (nonatomic, retain) NSString *postBody;
<强>实施强>
@implementation WSWCMPost
/** Now you specify the corresponding instance variable name alongside the property name */
@synthesize postBody=_postBody, postTitle=_postTitle, postID=_postID;
- (id)init {
self = [super init];
if(self) {
self.postID = @"none"; //getting retained
self.postBody = @"none";
self.postTitle = @"none";
}
}
这肯定会导致数据过早发布。
所以你以前的方式可以输入 self.postID 或 postID ,编译器也不会抱怨。不同之处在于当您输入 postID 时,它实际上是设置成员变量而不是保留它......其中 self.postID 将释放当前设置的内容并保留新价值,如果它不同。
通过以新方式声明属性,您必须将setter称为 self.postID ,或将基础实例变量设置为 _postID 。许多早期的iPhone书籍都让你以这种方式敲打了属性,它最终导致了各种各样的内存问题。
希望这有帮助!
<强> UPDATE !!! 强>
你忘了在你的构造函数中返回self;)我打赌那就是它
- (id)init {
self = [super init];
if(self) {
self.postID = @"none"; //getting retained
self.postBody = @"none";
self.postTitle = @"none";
}
return self; // THIS IS WHY, you're constructor doesn't return an instance of the class... add this please
}
- (id)initWithID: (NSString*)ID AndBody: (NSString*)body AndTitle: (NSString*)title {
if(( self = [super init] ))
{
self.postTitle = title;
self.postID = ID;
self.postBody = body;
}
return self;
}