Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Found an NSZombie in my app... now what?

I have a subclass of NSManagedObject with a few "integer 32" attributes that are really enums. These enums are defined in my model's .h file like this:

typedef enum {
    AMOwningCompanyACME,
    AMOwningCompanyABC,
    AMOwningCompanyOther
} AMOwningCompany;

I need to show a table view that displays the value of each attribute of this custom object, so for each enum I have a method that looks like this to return string values:

-(NSArray*)stringsForAMOwningCompany
{
    return [NSArray arrayWithObjects:@"ACME Co.", @"ABC Co.", @"Other", nil];
}

In my table view, I iterate through the attributes of my NSManagedObject (using NSEntityDescription's attributesByName and for each attribute I call a helper method that calls the appropriate "stringsFor" method to return the strings for that particular attribute:

-(NSArray*)getStringsArrayForAttribute:(NSString*)attributeName
{
    SEL methodSelector = NSSelectorFromString([self methodNameForAttributeNamed:attributeName]);
    NSInvocation* invocation = [NSInvocation invocationWithMethodSignature:[[AMProperty class] instanceMethodSignatureForSelector:methodSelector]];
    [invocation setSelector:methodSelector];
    [invocation setTarget:self.editingPole];
    [invocation invoke];

    NSArray* returnValue = nil;
    [invocation getReturnValue:&returnValue];

    return returnValue;
}

My table view's cellForRowAtIndexPath looks like this:

...
NSString* itemName = self.tableData[indexPath.row];
NSAttributeDescription* desc = itemAttributes[itemName];

NSString* cellIdentifier = [self cellIdentifierForAttribute:desc]; // checks the attribute type and returns a different custom cell identifier accordingly
if ([cellIdentifier isEqualToString:@"enumCell"])
{
    // dequeue cell, customize it
    UITableViewCell* enumCell = ...
    ...
    NSArray* stringValues = [[NSArray alloc] initWithArray:[self getStringArrayForAttribute:itemName]];
    int currentValue = [(NSNumber*)[self.editingPole valueForKey:itemName] intValue];
    enumCell.detailTextLabel.text = (NSString*)stringValues[currentValue];
    return enumCell;
}
...

For only one of the attributes, I keep getting a crash on the NSInvocation's return array:

-[__NSArrayI release]: message sent to deallocated instance 0x856a4b0

Using the Zombies Profiler, I see:

Instruments Screenshot

I am using ARC. How can I debug this further?

like image 439
Shinigami Avatar asked Feb 16 '23 13:02

Shinigami


1 Answers

I ran into a very similar problem myself recently and it took me a while to figure out what I was doing wrong. An extra release is being issued here -- because your pointer returnValue is __strong (the default), ARC believes that the object is owned via that pointer, but that's not the case.

-[NSInvocation getReturnValue:] doesn't take ownership of it, and the "assignment" via the pointer's address bypasses the objc_storeStrong() that ARC would normally use.

The solution is simple: mark the pointer as __unsafe_unretained. This is the truth; the object is not retained via this pointer (as it would if it were __strong), and ARC must not release it here.

like image 118
jscs Avatar answered Feb 23 '23 14:02

jscs