2011-06-24 81 views
0

我的程序的基本结构是用户从UITableView中选择一个项目,该项目与存储的文本文件相对应。然后将文件读入数组和字典中,其中数组有键(我知道我只能从字典本身获取键,这不是我的问题)。从应用程序中读取文件时,iPad应用程序崩溃且没有崩溃日志

然后,该视图将更改为UISplitView,其中主视图具有键,并且详细视图中包含词典中归因于该键的项目。在这种情况下,这是用户选择答案的一系列“是/否”问题。

我的问题是这样的:当我点击UITableView(第一个屏幕)中的单元格时,它工作正常,数据完全读取,等等。当我回到UITableView并再次单击相同的单元格时,程序崩溃。这里是读入,从文件的方法:

-(NSArray *)readFromFile:(NSString *)filePath{ 
    // NSLog(@"Path was: %@", filePath); 
    NSString *file = [[NSString alloc] initWithContentsOfFile:filePath]; 

    // NSLog(@"File was: %@", file); 
    NSScanner *fileScanner = [[NSScanner alloc] initWithString:file]; 

    NSString *held; 
    NSString *key; 
    NSMutableArray *detailStrings; 
    NSMutableArray *keys = [[NSMutableArray alloc] init]; 
    NSMutableDictionary *details = [[NSMutableDictionary alloc] init]; 
    /** 
    This is where the fun stuff happens! 
    **/ 
    while(![fileScanner isAtEnd]){ 
     //Scan the string into held 
     [fileScanner scanUpToString:@"\r" intoString:&held]; 
     NSLog(@"Inside the while loop"); 
     // If it is a character, it's one of the Key points, so we do the management necessary 
     if ([[NSCharacterSet lowercaseLetterCharacterSet] characterIsMember:[[held lowercaseString] characterAtIndex: 0]]){ 
      NSArray *checkers = [[NSArray alloc] initWithArray:[held componentsSeparatedByString:@"\t"]]; 
      NSLog(@"Word at index 2: %@", [checkers objectAtIndex:2]); 

      if(detailStrings != nil){ 
       [details setObject:detailStrings forKey:key]; 
       [detailStrings release]; 
      } 
      NSLog(@"After if statement"); 
      key = [checkers objectAtIndex:2]; 
      [keys addObject:(NSString *) key]; 
      detailStrings = [[NSMutableArray alloc] init]; 
     } 
     else if ([[NSCharacterSet decimalDigitCharacterSet] characterIsMember:[[held lowercaseString] characterAtIndex: 0]]){ 

      NSArray *checkers = [[NSArray alloc] initWithArray:[held componentsSeparatedByString:@"\t"]]; 
      NSLog(@"Word at index 1: %@", [checkers objectAtIndex:1]); 
      [detailStrings addObject:[checkers objectAtIndex:1]]; 
     } 
    } 
    NSLog(@"File has been read in"); 
    [details setObject:detailStrings forKey:key]; 
    NSArray *contents = [[NSArray alloc] initWithObjects:(NSMutableArray *) keys, (NSMutableDictionary *) details, nil]; 

    [detailStrings release]; 
    return contents; 
} 

我已经确定

if(detailStrings != nil) 

语句中的程序崩溃。我认为这是因为我错过了一些我应该做的内存管理,但没有知道错在哪里。关于这个问题的任何想法,或为什么它没有给我一个日志崩溃?

+0

为什么你检查是否'detailStrings'是'nil' ?它显然是:你在if语句之前从来没有给它赋值。或者我错过了什么? –

+0

调用堆栈或者崩溃的原因是什么? –

+0

经过进一步的思考,我想你有一个释放的指针,'detailStrings'。重新定义它并不会使它成为'零'。 –

回答

3

detailStrings在您输入while循环时未初始化。当您在方法内声明NSMutableArray *detailStrings;时,detailStrings不会自动设置为nil。所以,当你做

if (detailStrings != nil) { .. } 

进入if语句和,因为它没有初始化,当您访问detailStrings它会崩溃。

另一件事是,如果detailStrings首先进入else部分,它将不会被初始化。这也会导致崩溃。因此,根据您的需要,无论是做

NSMutableArray *detailStrings = nil; 

或您输入的while循环之前进行初始化。

+0

我很确定每个新定义的变量都会自动为零。您可以通过在定义后面放置一个断点来测试它,然后获取变量的值。它将等于0x0(零)。除非变量已经在其他地方使用 - 这就是为什么在不再需要时删除值不是一个坏主意(当代码中出现竞争条件时)。 –

+0

只有当变量已经定义时才会出现问题 - 这可能就是这种情况。有人可能会说一个免费的指针。解决方案的确在分配'nil'。 –

+1

@Randy Marsh:我知道一个事实,即Objective-C中新定义的变量不会自动为零。如果它们是类成员变量,它们是,因为'alloc'清除了它分配的内存,但是其他内存分配,比如像'detailStrings'这样的栈变量只是获得堆栈中发生的任何值。 – benzado

2

迪帕克说的是真话。你应该首先用nil初始化detailStrings。

但是还有第二个可能的问题:

我建议还发布后设置为零,因为在接下来的循环中,您可以测试与无记忆不存在的部分。

if(detailStrings != nil){ 
      [details setObject:detailStrings forKey:key]; 
      [detailStrings release]; 
      detailStrings = nil; 
} 

而第三种可能的问题:从传入的数据可能会去的IF语句第一次,第二部分,并尝试ADDOBJECT成非初始化数组根据。

第四个(最后的希望):你有“跳棋”阵列

1

这里是我所看到的内存泄漏:

//read in the file 
NSString *file = [[NSString alloc] initWithContentsOfFile:filePath]; 
//create the scanner 
NSScanner *fileScanner = [[NSScanner alloc] initWithString:file]; 

//declare some uninitialized stuff 
NSString *held; 
NSString *key; 
NSMutableArray *detailStrings; 

//initialize some stuff 
NSMutableArray *keys = [[NSMutableArray alloc] init]; 
NSMutableDictionary *details = [[NSMutableDictionary alloc] init]; 

//begin loop 
while(![fileScanner isAtEnd]){ 
    //scan up to a newline 
    [fileScanner scanUpToString:@"\r" intoString:&held]; 
    //see if you scanned a lowercase string 
    if ([[NSCharacterSet lowercaseLetterCharacterSet] characterIsMember:[[held lowercaseString] characterAtIndex: 0]]){ 
     //make an array 
     NSArray *checkers = [[NSArray alloc] initWithArray:[held componentsSeparatedByString:@"\t"]]; 

     //do a check... against an uninitialized value 
     if(detailStrings != nil){ 
      //set a potentially uninitialized value into an array with an uninitialized key 
      [details setObject:detailStrings forKey:key]; 

在这一点上,你几乎大清洗。

的修复:

  • 正确初始化变量
  • 运行静态分析
  • 读取内存管理编程指南
+0

现在阅读指南。感谢您的关注! – Althane