0

I have a for loop where at the beginning an NSObject "value" is declared and then a switch statement within "value" is actually created. "value" then can be an NSNumber, an NSDate, an NSData, an NSString or nil. This is the code:

for (int i = 0; i < self.columnCount; i++) {
  NSObject *value;
  switch (mysql_fields[i].type) {
    case ...
      ...
    case MYSQL_TYPE_LONG:
      value = [[NSNumber alloc] initWithInt:atoi(row[i])];
      /* [value autorelease]; */  // 2)
      break;
    case MYSQL_TYPE_DECIMAL:
      NSString *decimal = [[NSString alloc] initWithCString:(char *)row[i] encoding:NSUTF8StringEncoding];
      value = [[NSDecimalNumber alloc] initWithString:decimal];
      /* [value autorelease]; */  // 2)
      [decimal release];
      break;
    case ...
      ...
  } // end of switch
} end of for
Field *field = [[[Field alloc] initWithRecord:record] autorelease];
/* [value autorelease]; */  // 3)
[field setValue:value forKey:@"value"];
/* [value release]; */  // 4)

Now I don't know how to release "value". This is what I tried and the corresponding Xcode 4 "Analyzer" messages:

  1. no release -> "potential leak"
  2. [value autorelease] after alloc/init within each case statement -> "object sent autorelease too many times"
  3. [value autorelease] directly before the last use -> "object sent autorelease too many times"
  4. [value release] after the last use -> "Incorrect decrement of the reference count of an object not owned by the caller at this point"

2 Answers2

1

Add autorelease only where allocating the object, remove the rest:

value = [[[NSNumber alloc] initWithInt:atoi(row[i])] autorelease];
// ....
value = [[[NSDecimalNumber alloc] initWithString:decimal] autorelease];
MByD
  • 135,866
  • 28
  • 264
  • 277
  • This is the same as case 2), giving me the "object sent autorelease too many times" in "Analyzer". –  May 14 '12 at 09:14
0

You are declaring value inside the for loop, so you have to release it AFTER the switch but INSIDE the for loop.

for (int i = 0; i < self.columnCount; i++)
{
    NSObject *value;
    switch (mysql_fields[i].type)
    {
        case ...
            ...
        case MYSQL_TYPE_LONG:
            value = [[NSNumber alloc] initWithInt:atoi(row[i])];
            break;
        case MYSQL_TYPE_DECIMAL:
            NSString *decimal = [[NSString alloc] initWithCString:(char *)row[i] encoding:NSUTF8StringEncoding];
            value = [[NSDecimalNumber alloc] initWithString:decimal];
            [decimal release];
            break;
        case ...
            ...
    }
    Field *field = [[[Field alloc] initWithRecord:record] autorelease];
    [field setValue:value forKey:@"value"];
    [value release];
}
Christoph Winkler
  • 6,278
  • 1
  • 18
  • 18
  • 1
    This is case 4), giving me the "Incorrect decrement of the reference count of an object not owned by the caller at this point" message in "Analyzer" –  May 14 '12 at 09:15
  • In your example case 4 is outside the for loop. This is a huge difference. – Christoph Winkler May 14 '12 at 09:34
  • This is true - but the mistake sneaked in while simplifying the code for this question. Sorry for that. –  May 14 '12 at 09:46
  • Solved: in one of the case statements I created "value" from an NSString class method instead of using alloc/init as in all other case statements. Objects created by class methods are "autoreleased". –  May 14 '12 at 10:18