进入NSMutableArray后,自定义对象变为_NSCFString

时间:2012-06-26 01:53:18

标签: objective-c

我在将自定义对象(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...

我认为这是所有相关的代码。如果我忘了什么,请告诉我。这个问题困扰了我好几个小时......

3 个答案:

答案 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;
}