【问题标题】:Invalid Selector sent to instance - objectForKey:发送到实例的无效选择器 - objectForKey:
【发布时间】:2011-08-17 23:53:33
【问题描述】:

运行代码时出现错误。罪魁祸首是我从下面的 plist 中访问了一个字符串:

    NSString *sImageFile = [dictionary objectForKey:@"answerCorrect"];
    NSLog(@"%@",sImageFile);

我的 cocos2d Init 中有这个:

-(id) init
{
    // always call "super" init
    // Apple recommends to re-assign "self" with the "super" return value
    if( (self=[super init])) {

        NSUserDefaults *sud = [NSUserDefaults standardUserDefaults];
        NSString *ctlLang = [sud valueForKey:@"ctlLang"];
        NSNumber *questionState = [sud valueForKey:@"questionState"];
        NSNumber *scoreState = [sud valueForKey:@"scoreState"];
        gameArray = (NSMutableArray *)[sud valueForKey:@"gameArray"];
        for (NSString *element in gameArray) {
            NSLog(@"\nQL gameArray value=%d\n", [element intValue]);
        }
        NSString *path = [[NSBundle mainBundle] bundlePath];
        NSString *finalPath = [path stringByAppendingPathComponent:ctlLang];
        dictionary = [NSDictionary dictionaryWithContentsOfFile:finalPath];

        NSString *sImageFile = [dictionary objectForKey:@"answerCorrect"];
        NSLog(@"%@",sImageFile);
    }
}

字符串的打印在场景的 init 部分可以正常工作。问题出现在我稍后定义的方法中。由于某种原因,它没有在此处显示的方法中返回字符串:

-(void) checkAnswer: (id) sender {

    CGSize size = [[CCDirector sharedDirector] winSize];
    CCMenuItemSprite *sAnswer = (CCMenuItemSprite *)sender;
    NSLog(@"Checking Answer Tag is ---> %d",sAnswer.tag);
    NSString *sImageFile = [dictionary objectForKey:@"answerCorrect"];
    NSLog(@"%@",sImageFile);
    if ([question.answer integerValue] == sAnswer.tag) {
        //...
    }
}

我在这里缺少什么?程序在 NSLog 语句处炸弹。

【问题讨论】:

  • 通过valueForKey,你的意思是objectForKey吗?无论如何,也许你没有保留你需要的东西?
  • 是的,它的 objectForKey 与代码中一样。这是我在界面中定义它的方式:@property (nonatomic, retain, readonly) NSDictionary *dictionary;

标签: iphone objective-c ios nsstring nsdictionary


【解决方案1】:

您将dictionaryWithContentsOfFile: 返回的对象分配给dictionary ivar,但您不会通过向其发送retain 消息来声明其所有权:

dictionary = [NSDictionary dictionaryWithContentsOfFile:finalPath];

dictionaryWithContentsOfFile: 方法返回一个您不拥有的对象。可能在执行checkAnswer: 时,对象已经被释放。你需要保留它:

dictionary = [[NSDictionary dictionaryWithContentsOfFile:finalPath] retain];

或者改用alloc-initWithContentsOfFile:,它会返回一个你拥有的对象

dictionary = [[NSDictionary alloc] initWithContentsOfFile:finalPath];

gameplay ivar 也是如此。您不拥有valueForKey: 返回的对象,您需要保留它。所以这一行:

gameArray = (NSMutableArray *)[sud valueForKey:@"gameArray"];

应该是:

gameArray = [[sud valueForKey:@"gameArray"] retain];

【讨论】:

  • 或者如果属性不是只读的,你可以使用self.dictionary = [NSDictionary dictionaryWithContentsOfFile:finalPath];
  • @SSteve 我没有提到,因为在init和dealloc方法中使用属性访问器是discouraged by Apple
  • 糟糕。我不知道。感谢您的信息。
  • 非常感谢。我刚刚在我的字典语句中添加了一个保留,它起作用了。我认为通过在接口中定义一个保留属性是我所需要的,但我知道实例变量也需要一个保留。
  • 在 init 中移除 readonly 并不能解决问题。我在尝试保留它之前尝试过。
【解决方案2】:

我认为您不会保留在您的 init 方法中创建的自动释放字典。您设置了字典 ivar 但不保留它。当您稍后访问它时,它可能不再有效

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-04-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-14
    相关资源
    最近更新 更多