You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Xcode更新后NSDictionary因对象数与键数不匹配导致应用崩溃的排查求助

问题分析与解决方案

首先咱们来定位崩溃的核心原因:

你遇到的报错-[NSDictionary initWithObjects:forKeys:]: count of objects (0) differs from count of keys (1),直接指向这行代码:

NSDictionary *outerDict = [NSDictionary dictionaryWithObjects: [NSArray arrayWithObjects: notes, nil] forKeys:[NSArray arrayWithObjects:@"Questions", nil]];

当notes是nil的时候,[NSArray arrayWithObjects: notes, nil]会创建一个空数组(因为这个方法遇到第一个nil就会终止元素添加),但对应的keys数组有1个元素(@"Questions"),字典初始化要求对象和键的数量必须完全一致,所以直接触发崩溃。

那notes为什么会是nil?主要有两个场景:

  • 第一次运行时,manuallyData33.plist文件还不存在,[[NSMutableDictionary alloc]initWithContentsOfFile:plistPath]返回nil,后续[plistdictionary objectForKey:@"Questions"]自然也是nil。
  • 如果plist文件存在,但里面没有@"Questions"这个键,同样会导致notes为nil。

另外你的代码还有几个潜在隐患:每次循环都重复读写plist文件(效率极低)、没有处理文本分割后可能出现的数组越界情况(比如文本末尾的空行导致listArray出现空元素,进而items数组长度不足5)。


修复方案

我们分步骤解决这些问题,下面是修改后的完整代码:

-(void)editTextFile {
    NSError *error = nil;
    NSString *filepath = [[NSBundle mainBundle] pathForResource:@"JOSHUASTUDY" ofType:@"txt"];
    NSString *fileContents = [NSString stringWithContentsOfFile:filepath encoding:NSUTF8StringEncoding error:&error];
    if (error) {
        NSLog(@"Error reading file: %@", error.localizedDescription);
        return; // 文件读取失败直接返回,避免后续无效操作
    }
    
    NSArray *listArray = [fileContents componentsSeparatedByString:@"\n\n"];
    
    // 先处理plist文件的初始化逻辑,放在循环外只执行一次
    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    NSString *documentsPath = [paths firstObject];
    NSString *plistPath = [documentsPath stringByAppendingPathComponent:@"manuallyData33.plist"];
    
    NSMutableDictionary *plistDictionary = [[NSMutableDictionary alloc] initWithContentsOfFile:plistPath];
    if (!plistDictionary) {
        // 如果plist不存在,初始化一个空字典
        plistDictionary = [NSMutableDictionary dictionary];
    }
    
    NSMutableArray *notes = [plistDictionary objectForKey:@"Questions"];
    if (!notes) {
        // 如果Questions数组不存在,初始化一个空的可变数组
        notes = [NSMutableArray array];
        [plistDictionary setObject:notes forKey:@"Questions"];
    }
    
    // 遍历处理每个问题
    for (NSString *listItem in listArray) {
        // 跳过空的元素(比如文本末尾的空行分割出来的内容)
        NSString *trimmedItem = [listItem stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
        if (trimmedItem.length == 0) {
            continue;
        }
        
        NSArray *items = [listItem componentsSeparatedByString:@"\n"];
        // 检查items数组长度是否足够,避免数组越界崩溃
        if (items.count < 5) {
            NSLog(@"Invalid question format, skipping: %@", trimmedItem);
            continue;
        }
        
        NSString *theQuestion = items[0];
        NSString *answerA = items[1];
        NSString *answerB = items[2];
        NSString *answerC = items[3];
        NSString *answerD = items[4];
        
        // 用现代字面量语法组装内部字典,更简洁且自动校验元素匹配
        NSDictionary *innerDict = @{
            @"Answer": @"0",
            @"duration_in_seconds": @"30",
            @"negative_points": @"5",
            @"options": @[answerA, answerB, answerC, answerD],
            @"points": @"20",
            @"question": theQuestion,
            @"question_type": @"1"
        };
        
        [notes addObject:innerDict];
    }
    
    // 最后统一写入plist文件,避免循环内反复读写
    BOOL writeSuccess = [plistDictionary writeToFile:plistPath atomically:YES];
    if (!writeSuccess) {
        NSLog(@"Failed to write plist file to path: %@", plistPath);
    }
}

关键修改点说明

  • plist初始化逻辑:当文件不存在或字典为空时,主动创建空字典和Questions数组,确保notes永远不会是nil,从根源解决崩溃问题。
  • 循环外读写文件:只在开始时读取一次plist,循环结束后统一写入,大幅提升执行效率。
  • 空元素过滤:跳过文本分割后产生的空内容,避免无效处理。
  • 数组越界检查:每次分割后检查items的长度,防止因为格式错误导致的越界崩溃。
  • 现代语法替换:用字面量语法@{}和@[]替代旧的dictionaryWithObjects:forKeys:,代码更简洁且编译器会自动检查元素数量匹配,减少人为失误。

这样修改后,不仅能解决你当前的崩溃问题,还能修复潜在的其他bug,让代码更稳定可靠。

内容的提问来源于stack exchange,提问作者user717452

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.30 14:13:16