NSMutable Array - objectAtIndex:超出边界的索引

时间:2009-11-02 04:33:04

标签: objective-c cocoa nsmutablearray nsmutabledictionary

我正在尝试查看一个加载了NSMutableArray的NSMutableDictionary,我搞砸了,我不知道怎么做。我正在尝试加载更大的游戏问题,如果它们不是正确的级别,则删除它们。在我尝试删除之前,我没有收到错误。谁能看到这段代码中的缺陷?我非常感激!

谢谢,

〜ģ

{
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];   
}
}

3 个答案:

答案 0 :(得分: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:,因为你试图同时遍历数组。

如果您只是想跳过某个特定对象,则可以在到达该对象时调用“continue”。如果您真的想要将其从数组中删除,请致电[QuestionsByLevel removeObject:GameLevel]。或者对你的情况有意义的事情。但是在之前迭代遍历数组。

答案 1 :(得分:9)

这不是答案。这是对你的代码的批评。

  1. 神圣的记忆泄漏,蝙蝠侠!您分配/ init:GameLevelComponentslevel,但从不发布任何内容。
  2. GameLevel根本不需要alloc / init'd。您可以从[settings objectForKey:kLevelKey];中提取值,将其分配到GameLevel字符串中,然后使用它。然后你甚至不必释放它。
  3. 你的循环是......奇怪的。您正在遍历循环,但每次迭代时,都会将self.QDetailsByLevel属性设置为新值。你确定那是你想要的吗?
  4. 这:if (level != GameLevel)没有按照您的想法行事。那是比较指针(即内存中两个对象的ADDRESSES)。在当前状态下,levelGameLevel都已分配/初始化,这意味着它们永远不会成为同一个对象。你可能想要if ([level isEqualToString:GameLevel] == NO)代替。
  5. [self.QuestionsByLevel count]中减去一个以获得QuestionCount int,这似乎是for()循环的上限。然而,for循环的条件(@Michael显示你的问题)从QuestionCount中减去另一个 1,这意味着你的for()循环永远不会到达最后一个元素阵列。你确定那是你想要的吗?
  6. 记住这一点:http://www.cocoadevcentral.com/articles/000082.php(或this

答案 2 :(得分:3)

如果我没有弄错的话,问题就出现了,因为你在迭代它的内容时正在修改对象。从列表中删除对象时,终止条件将变为无效。尝试将其作为while循环实现,并且每当从列表中删除元素时都要小心更新终止条件。您还可以使用调试器找出您的界限。