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

2 cocoa objective-c nsmutablearray nsmutabledictionary

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

谢谢,

〜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];   
}
}
Run Code Online (Sandbox Code Playgroud)

BJ *_*mer 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];       
}
Run Code Online (Sandbox Code Playgroud)

让我们看看在这段代码的几次迭代之后会发生什么.

第一次迭代:

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]
Run Code Online (Sandbox Code Playgroud)

第二次迭代:

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

// The following happens because you call removeObjectAtIndex:1
QuestionsByLevel = [Q2, Q4, Q5]
Run Code Online (Sandbox Code Playgroud)

第三次迭代:

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

// The following happens because you call removeObjectAtIndex:2
QuestionsByLevel = [Q2, Q4]
Run Code Online (Sandbox Code Playgroud)

第四次迭代:

j == 3
self.QuestionsByLevel == [Q2, Q4]
SelectedQuestion = QuestionsByLevel[3] // CRASH!!!! 
Run Code Online (Sandbox Code Playgroud)

你能看到问题吗?你的for循环假设你将通过它们的索引访问对象,但是在每次迭代之后,你将删除数组之外的东西,这会在该点之后移动所有索引.你不应该打电话removeObjectAtIndex:,因为你正试图同时走过阵列.

如果您只是想跳过特定对象,则可以在到达该对象时调用"继续".如果您真的想要将其从阵列中删除,请致电[QuestionsByLevel removeObject:GameLevel].或者对你的情况有意义的事情.但是迭代数组之前这样做.


Dav*_*ong 9

这不是答案.这是对您的代码的批评.

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