Memory Leak from removeAsset?

I am wondering why the employee from which I remove an asset using my newly implemented ‘removeAsset’ method is not deallocated when employees is set to nil? Every other employee is deallocated, and their corresponding assets are deallocated. However, the employee from which I removed an asset is only deallocated (along with its remaining assets) before ending with exit code: 0.

Here is my output:

Employees: (
<“Employee 0: $0 in assets>”,
<“Employee 1: $503 in assets>”,
<“Employee 2: $469 in assets>”,
<“Employee 3: $768 in assets>”,
<“Employee 4: $0 in assets>”,
<“Employee 5: $836 in assets>”,
<“Employee 6: $819 in assets>”,
<“Employee 7: $384 in assets>”,
<“Employee 8: $0 in assets>”,
<“Employee 9: $486 in assets>”
)
Removing asset from employee 3

deallocating <Laptop 0: $350>
employees count: 10
Giving up ownership of arrays

deallocating <Employee 0: $0 in assets>
deallocating <Employee 1: $503 in assets>
deallocating <Laptop 9: $503>
deallocating <Employee 2: $469 in assets>
deallocating <Laptop 7: $469>
deallocating <Employee 4: $0 in assets>
deallocating <Employee 5: $836 in assets>
deallocating <Laptop 3: $401>
deallocating <Laptop 5: $435>
deallocating <Employee 6: $819 in assets>
deallocating <Laptop 1: $367>
deallocating <Laptop 6: $452>
deallocating <Employee 7: $384 in assets>
deallocating <Laptop 2: $384>
deallocating <Employee 8: $0 in assets>
deallocating <Employee 9: $486 in assets>
deallocating <Laptop 8: $486>
employees count: 0
deallocating <Employee 3: $418 in assets>
deallocating <Laptop 4: $418>
Program ended with exit code: 0`

main.m:

#import <Foundation/Foundation.h>
#import "BNREmployee.h"
#import "BNRAsset.h"

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        
        // Create an array of BNREmployee objects
        NSMutableArray *employees = [[NSMutableArray alloc] init];
        
        for (int i = 0; i < 10; i++) {
            // Create an instance of BNREmployee
            BNREmployee *mikey = [[BNREmployee alloc] init];
            
            // Give the instance variables interesting values
            mikey.weightInKilos = 90 + i;
            mikey.heightInMeters = 1.8 - i/10.0;
            mikey.employeeID = i;
            
            // Put the emloyee in the employees array
            [employees addObject:mikey];
        }
        
        // Create 10 assets
        for (int i = 0; i < 10; i++) {
            // Create an asset
            BNRAsset *asset = [[BNRAsset alloc] init];
            
            // Give it an interesting label
            NSString *currentLabel = [NSString stringWithFormat:@"Laptop %d", i];
            asset.label = currentLabel;
            asset.resaleValue = 350 + i * 17;
            
            // Get a random number between 0 and 9 inclusive
            NSUInteger randomIndex = random() % [employees count];

            // Find that employee
            BNREmployee *randomEmployee = [employees objectAtIndex:randomIndex];
            
            // Assign the asset to the employee
            [randomEmployee addAsset:asset];
        }
        
        NSLog(@"Employees: %@", employees);
        
        NSLog(@"Removing asset from employee 3\n");

        BNREmployee *employeeNumberThree = [employees objectAtIndex:3];
        [employeeNumberThree removeAsset:employeeNumberThree.assets[0]];
        
        NSLog(@"employees count: %lu\n", (unsigned long)[employees count]);
        
        
        NSLog(@"Giving up ownership of arrays\n");
        
        employees = nil;

        NSLog(@"employees count: %lu\n", (unsigned long)[employees count]);
    }
    return 0;
}

BNREmployee.h

#import <Foundation/Foundation.h>
#import "BNRPerson.h"
@class BNRAsset;

@interface BNREmployee : BNRPerson
{
    NSMutableArray *_assets;
}

@property (nonatomic) unsigned int employeeID;
@property (nonatomic) unsigned int officeAlarmCode;
@property (nonatomic) NSDate *hireDate;
@property (nonatomic, copy) NSArray *assets;
- (double)yearsOfEmployment;
- (void)addAsset:(BNRAsset *)a;
- (void)removeAsset:(BNRAsset *)a;
- (unsigned int)valueOfAssets;

@end

BNREmployee.m

#import "BNREmployee.h"
#import "BNRAsset.h"

@implementation BNREmployee

// Accessors for assets properties
- (void)setAssets:(NSArray *)a
{
    _assets = [a mutableCopy];
}

- (NSArray *)assets
{
    return [_assets copy];
}

- (void)addAsset:(BNRAsset *)a
{
    // Is assets nil?
    if (!_assets) {
        
        // Create the array
        _assets = [[NSMutableArray alloc] init];
    }
    [_assets addObject:a];
}

- (void)removeAsset:(BNRAsset *)a
{
    if (_assets) {
    [_assets removeObject:a];
    }
}

- (unsigned int)valueOfAssets
{
    // Sum up the resale value of the assets
    unsigned int sum = 0;
    for (BNRAsset *a in _assets) {
        sum += [a resaleValue];
    }
    return sum;
}

- (NSString *)description
{
    return [NSString stringWithFormat:@"<Employee %u: $%u in assets>", self.employeeID, self.valueOfAssets];
}

- (void)dealloc
{
    NSLog(@"deallocating %@", self);
}

@end

That’s probably because the following statement is keeping number 3 alive (by keeping a strong reference to it) until the end of the current scope.

BNREmployee * employeeNumberThree = [employees objectAtIndex:3];

Set it to nil and see what happens:

NSLog(@"Giving up ownership of arrays\n");
employeeNumberThree = nil
employees = nil;

Thank you, @ibex10! That was exactly right. I set employeeNumberThree to nil, and everything worked perfectly.

First, I tried using
__weak BNREmployee *employeeNumberThree = [employees objectAtIndex:3];
instead. But while this allowed the employee object to be deallocated when employees was set to nil, it appears that the asset objects were not deallocated until the autorelease pool was drained…