2015-05-15 4 views
0

У меня есть следующий фрагмент кода: (это долго)EXC_BAD_ACCESS с 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), которые будут соответственно размещены по xCode на batteryRawDict = (__bridge NSDictionary*)batProps; или в строке @implementation.

Любая идея о том, почему это происходит? Спасибо!

ответ

2

Это похоже на плохое управление памятью.

Вы звоните CFRelease по телефону batProps после того, как указатель переместился на NSDictionary. Это оставляет batteryRawDict, указывая на мусор.

Я предлагаю вам изменить эти две строки:

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

к:

batteryRawDict = (__bridge_transfer NSDictionary *)batProps; 

Если вы используете ARC, то вы сделали. Если вы используете MRC, тогда добавьте вызов в [batteryRawDict release]; в соответствующей точке.

У вас также есть второй звонок CGRelease(batProps); в конце заявления case. Это тоже проблема. Не перегружайте указатели.

Запустите анализатор кода. Это должно указывать на эти проблемы.

+0

Первое, спасибо! Я помету ваш ответ, как только запустит анализатор. Кроме того, в чем смысл __bridge_transfer? – Perceval

+0

'__bridge_transfer' делает то, что подразумевает название. Он переносит владение памятью объекта из старой переменной в новую переменную. Поэтому вместо необходимости выпускать «batProps» вам нужно освободить «batteryRawDict». И это будет обработано для вас ARC. – rmaddy

+0

Хорошо, спасибо, ваши советы решили EXC_xxx! Однако это не исправляет цикл кода ... поэтому мой код все равно выполняется дважды (перед операцией '' 'break'''). – Perceval