EXC_BAD_ACCESS 和 NSDictionary/CFDictionaryRef

EXC_BAD_ACCESS with NSDictionary/CFDictionaryRef

我得到了以下代码:(很长)

//declarations (in the header) :
NSDictionary* batteryRawDict;
@property (strong, atomic, readonly) NSDictionary* batteryReport; //this dictionary is, obviously, @synthesize'd


case PFSKGroupBattery: { //to get more informations or to subscribe for events about power sources, use the IOPowerSources API
        if (!firstRunDoneForBattery) {
            batEntry = IOServiceGetMatchingService(masterPort, IOServiceMatching("IOPMPowerSource"));
            if (batEntry == 0) {
                _error = PFSKReturnComponentUnavailable;
                return false;
            }
        }
        CFMutableDictionaryRef  batProps = NULL;
        result = IORegistryEntryCreateCFProperties(batEntry, &batProps, NULL, 0);
        if (result!=kIOReturnSuccess) {
            _error = PFSKReturnIOKitCFFailure;
            _extError = result;
            return false;
        } else {
            batteryRawDict = (__bridge NSDictionary*)batProps;
            CFRelease(batProps);
            NSMutableDictionary* temp = [NSMutableDictionary.alloc init];
            if (!firstRunDoneForBattery) { //static keys
                //[temp setObject:[batteryRawDict objectForKey:@"DesignCapacity"] forKey:@"DesignedCapacity"];
                [temp setObject:[batteryRawDict objectForKey:@"DesignCycleCount9C"] forKey:@"DesignedCycleCount"];
                [temp setObject:[batteryRawDict objectForKey:@"BatterySerialNumber"] forKey:@"Serial"];
                [temp setObject:[batteryRawDict objectForKey:@"DeviceName"] forKey:@"Model"];
                [temp setObject:[batteryRawDict objectForKey:@"Manufacturer"] forKey:@"Manufacturer"];
                unsigned int manufactureDateAsInt = [[batteryRawDict objectForKey:@"ManufactureDate"] intValue];
                NSDateComponents* manufactureDateComponents = [[NSDateComponents alloc]init];
                manufactureDateComponents.year = (manufactureDateAsInt >> 9) + 1980;
                manufactureDateComponents.month = (manufactureDateAsInt >> 5) & 0xF;
                manufactureDateComponents.day = manufactureDateAsInt & 0x1F;
                [temp setObject:[[NSCalendar currentCalendar] dateFromComponents:manufactureDateComponents] forKey:@"ManufactureDate"];
                firstRunDoneForBattery = 1;
            }
            [temp setObject:[batteryRawDict objectForKey:@"BatteryInstalled"] forKey:@"isPresent"];
            [temp setObject:[batteryRawDict objectForKey:@"FullyCharged"] forKey:@"isFull"];
            [temp setObject:[batteryRawDict objectForKey:@"IsCharging"] forKey:@"isCharging"];
            [temp setObject:[batteryRawDict objectForKey:@"ExternalConnected"] forKey:@"isACConnected"];
            [temp setObject:[batteryRawDict objectForKey:@"Amperage"] forKey:@"Amperage"];
            [temp setObject:[batteryRawDict objectForKey:@"CurrentCapacity"] forKey:@"CurrentCapacity"];
            [temp setObject:[batteryRawDict objectForKey:@"MaxCapacity"] forKey:@"MaxCapacity"];
            [temp setObject:[batteryRawDict objectForKey:@"Voltage"] forKey:@"Voltage"];
            [temp setObject:[batteryRawDict objectForKey:@"CycleCount"] forKey:@"CycleCount"];
            [temp setObject:@(([[batteryRawDict objectForKey:@"MaxCapacity"] intValue] / [[batteryRawDict objectForKey:@"DesignCapacity"] intValue])*100) forKey:@"Health"]; //percentage
            [temp setObject:@([[batteryRawDict objectForKey:@"Temperature"] doubleValue] / 100) forKey:@"Temperature"];
            /*to be checked*/[temp setObject:@([[batteryRawDict objectForKey:@"Amperage"] doubleValue] / 1000 * [[batteryRawDict objectForKey:@"Voltage"] doubleValue] / 1000) forKey:@"Power"];
            NSDateComponents* differenceDate = [[NSCalendar currentCalendar] components:NSCalendarUnitDay
                                            fromDate:[temp objectForKey:@"ManufactureDate"]
                                              toDate:[NSDate date]
                                             options:0];
            [temp setObject:@([differenceDate day]) forKey:@"Age"];
            batteryReport = [temp copy];
            NSLog(@"-----------------------awesome debugging code-----------");
        }
        CFRelease(batProps);
        break;
    }

随机(=不是每次),当控制到这种情况时,会发生错误(EXC_BAD_ACCESS或EXC_I386_GPFLT),分别由[=22=定位] 在 batteryRawDict = (__bridge NSDictionary*)batProps; 或@implementation 行上。

知道为什么会这样吗? 谢谢!

看起来内存管理不好。

在将指针桥接到 NSDictionary 之后,您在 batProps 上调用了 CFRelease。这使得 batteryRawDict 指向垃圾。

我建议您更改这两行:

batteryRawDict = (__bridge NSDictionary*)batProps;
CFRelease(batProps);

至:

batteryRawDict = (__bridge_transfer NSDictionary *)batProps;

如果您使用的是 ARC,那么您就完成了。如果您使用的是 MRC,则在适当的位置添加对 [batteryRawDict release]; 的调用。

您还可以在 case 语句的末尾对 CGRelease(batProps); 进行第二次调用。这也是一个问题。不要过度释放指针。

运行 分析器上的代码太多了。那应该指出这些问题。