2

我正在尝试查看加载了 NSMutableArray 的 NSMutableDictionary 并且我把它搞砸了,我不知道怎么做。我正在尝试加载更大的游戏问题列表,如果它们不是正确的级别,则将其删除。在我尝试删除之前,我没有收到错误消息。任何人都可以看到这段代码中的缺陷吗?我会非常感激的!

谢谢,

〜G

{
NSUserDefaults *settings = [NSUserDefaults standardUserDefaults];
NSString *GameLevel = [[NSString alloc] initWithFormat: [settings objectForKey:kLevelKey]];

NSBundle *Bundle = [NSBundle mainBundle];
NSString *PListPath = [Bundle pathForResource:@"questions" ofType:@"plist"];

NSMutableDictionary *Dictionary = [[NSMutableDictionary alloc] initWithContentsOfFile:PListPath]; 

self.QuestionDetailsByLevel = Dictionary;
[Dictionary release];

NSMutableArray *Components = [[NSMutableArray alloc] initWithArray:[QuestionDetailsByLevel allKeys]];
self.QuestionsByLevel = Components;

int QuestionCount = [self.QuestionsByLevel count] - 1;

for (int j = 0; j < QuestionCount - 1; j++)
{

    NSString *SelectedQuestion = [self.QuestionsByLevel objectAtIndex:j];
    NSMutableArray *Array = [QuestionDetailsByLevel objectForKey:SelectedQuestion];
    self.QDetailsByLevel = Array;

    NSString *level = [[NSString alloc] initWithFormat:[self.QDetailsByLevel objectAtIndex:Level]];

    if (level != GameLevel)
        [QuestionsByLevel removeObjectAtIndex:j];   
}
}
4

3 回答 3

10

除了其他人提到的其他问题,让我们关注为什么你会出现越界错误。

这是相关的代码。

for (int j = 0; j < QuestionCount - 1; j++)
{

    NSString *SelectedQuestion = [self.QuestionsByLevel objectAtIndex:j];
    // ... snip ...
    if (level != GameLevel) //Always happening in your current code
        [QuestionsByLevel removeObjectAtIndex:j];       
}

让我们看看这段代码经过几次迭代后会发生什么。

第一次迭代:

j == 0
self.QuestionsByLevel == [Q1, Q2, Q3, Q4, Q5]

SelectedQuestion = QuestionsByLevel[0] // Q1

// The following happens because you call removeObjectAtIndex:0
QuestionsByLevel = [Q2, Q3, Q4, Q5]

第二次迭代:

j == 1
self.QuestionsByLevel == [Q2, Q3, Q4, Q5]
SelectedQuestion = QuestionsByLevel[1] // Q3

// The following happens because you call removeObjectAtIndex:1
QuestionsByLevel = [Q2, Q4, Q5]

第三次迭代:

j == 2
self.QuestionsByLevel == [Q2, Q4, Q5]
SelectedQuestion = QuestionsByLevel[2] // Q5

// The following happens because you call removeObjectAtIndex:2
QuestionsByLevel = [Q2, Q4]

第四次迭代:

j == 3
self.QuestionsByLevel == [Q2, Q4]
SelectedQuestion = QuestionsByLevel[3] // CRASH!!!! 

你能看出问题吗?您的 for 循环假定您将通过索引访问对象,但是在每次迭代之后,您将从数组中删除一些内容,这会在该点之后移动所有索引。你不应该打电话removeObjectAtIndex:,因为你正试图同时穿过数组。

如果您只是想跳过特定对象,则可以在到达该对象时调用“继续”。如果您真的想将其从数组中删除,只需调用[QuestionsByLevel removeObject:GameLevel]. 或者任何对你的情况有意义的东西。但是在遍历数组之前先这样做。

于 2009-11-02T06:05:04.780 回答
9

这不是一个答案。这是对您的代码的批评。

  1. 神圣的内存泄漏,蝙蝠侠!你 alloc/init: GameLevelComponentslevel,但从不释放它们中的任何一个。
  2. GameLevel根本不需要分配/初始化。您可以将值拉出[settings objectForKey:kLevelKey];,将其分配到您的GameLevel字符串中,然后使用它。然后你甚至不必释放它。
  3. 你的循环是......奇怪。您正在遍历循环,但每次迭代时,您都将self.QDetailsByLevel属性设置为一个新值。你确定那是你想要的吗?
  4. 这:if (level != GameLevel)不做你认为它做的事。这是比较指针(即内存中两个对象的地址)。在您当前的状态下,两者level都已GameLevel分配/初始化,这意味着它们永远不会是同一个对象。你可能想要if ([level isEqualToString:GameLevel] == NO)
  5. 你减去一个[self.QuestionsByLevel count]来得到你的QuestionCountint,这似乎是 for() 循环的上限。然而 for 循环的条件(@Michael 表明这是你的问题)从1 中减去另一个QuestionCount,这意味着你的 for() 循环永远不会到达数组中的最后一个元素。你确定那是你想要的吗?
  6. 记住这个: http: //www.cocoadevcentral.com/articles/000082.php(或这个
于 2009-11-02T05:02:12.407 回答
3

如果我没记错的话,问题正在发生,因为您在迭代对象的内容时正在修改对象。当您从列表中删除对象时,您的终止条件将变为无效。尝试将其实现为 while 循环,并在从列表中删除元素时小心更新终止条件。您还可以使用调试器找出您越界的地方。

于 2009-11-02T04:42:36.053 回答