All assets are unassigned


#1

After modifying the child relationship to being a weak one, and the objects now are deallocated correctly, all assets seems as being unassigned.

I have tried breaking the code during the addAssetsObject method, where the relationship is made, and everything shows up fine there. When I break during the description method it also seems like the Asset’s holder object is fine, but whenever I try to get at it with a [self holder] it turns up null.

What gives?

EDIT: Can it be because, the time where description is called is from dealloc where the instance is being collected, and when it comes to running the description method the weak reference might be collected?


#2

Check that you have the line

[a setHolder:self];

in your addAssetsObject: method.


#3

This is my method:

- (void)addAssetsObject:(Asset *)a
{
    // Is assets nil?
    if (!assets)
    {
        // Create the array
        assets = [[NSMutableSet alloc] init];
    }
    
    [assets addObject:a];
    [a setHolder:self];
}

#4

I have the same issue, the addAssetsObject method appears to be correct:

- (void)addAssetsObject:(Asset *)a { if (!assets) { assets = [[NSMutableArray alloc] init]; } [assets addObject:a]; [a setHolder:self]; }
Stepping through the application, it clearly allocates the holder to the Asset. However when the deallocation process is executed it seems that the test condition is returning false in the description method in the Asset instance is call.

- (NSString *)description { if ([self holder]) { return [NSString stringWithFormat:@"<Asset %@: $%d, assigned to %@>", [self label], [self resaleValue], [self holder]]; } else { return [NSString stringWithFormat:@"<Asset %@: $%d unassigned>", [self label], [self resaleValue]]; } }

So although the holder has a reference value, the if ([self holder]) returns false, so the second return is performed.

Any ideas or suggestions for this would be really helpful.


#5

Could you post the full code for your class so everyone can take a look?


#6

Not sure what part you want to see, so I include the *.h and *.m files for Person, Employee and Asset

[code]//
// Person.h
// BMITime
//
#import <Foundation/Foundation.h>
@interface Person : NSObject
{
float heightInMeters;
int weightInKilos;
}
@property float heightInMeters;
@property int weightInKilos;

  • (float)bodyMassIndex;
    @end[/code]

[code]//
// Person.m
// BMITime
//
#import “Person.h”
@implementation Person
@synthesize heightInMeters, weightInKilos;

  • (float)bodyMassIndex
    {
    return [self weightInKilos] / ([self heightInMeters] * [self heightInMeters]);
    }
    @end[/code]

[code]//
// Employee.h
// BMITime
//
#import “Person.h”
@class Asset;
@interface Employee : Person
{
int employeeID;
NSMutableArray *assets;
}
@property int employeeID;

  • (void)addAssetsObject:(Asset *)a;
  • (unsigned int)valueOfAssets;
    @end
    [/code]

[code]//
// Employee.m
// BMITime
//
#import “Employee.h”
#import “Asset.h”
@implementation Employee
@synthesize employeeID;

  • (void)addAssetsObject:(Asset *)a
    {
    if (!assets) {
    assets = [[NSMutableArray alloc] init];
    }
    [assets addObject:a];
    [a setHolder:self];
    }

  • (unsigned int)valueOfAssets
    {
    unsigned int sum=0;
    for (Asset *a in assets) {
    sum += [a resaleValue];
    }

    return sum;
    }

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

  • (float)bodyMassIndex
    {
    return [super bodyMassIndex] * 0.9;
    }

  • (void)dealloc
    {
    NSLog(@“deallocating %@”, self);
    }
    @end
    [/code]

// // Asset.h // BMITime // #import <Foundation/Foundation.h> @class Employee; @interface Asset : NSObject { NSString *label; __weak Employee *holder; unsigned int resaleValue; } @property (strong) NSString *label; @property (weak) Employee *holder; @property unsigned int resaleValue; @end

[code]//
// Asset.m
// BMITime
//
#import “Asset.h”
#import “Employee.h”
@implementation Asset
@synthesize label, resaleValue, holder;

  • (NSString *)description
    {
    if ([self holder]) {
    return [NSString stringWithFormat:@"<Asset %@: %d, assigned to %@>", [self label], [self resaleValue], [self holder]]; } else { return [NSString stringWithFormat:@"<Asset %@: %d unassigned>", [self label], [self resaleValue]];
    }
    }

  • (void)dealloc
    {
    NSLog(@“deallocating %@”, self);
    }
    @end
    [/code]

I’ve removed some of the white space, but otherwise these are a straight cut-and-paste. The project is also configured to using ARC and when running the application the following is the output:

GNU gdb 6.3.50-20050815 (Apple version gdb-1708) (Mon Aug 8 20:32:45 UTC 2011)
Copyright 2004 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
Type “show copying” to see the conditions.
There is absolutely no warranty for GDB. Type “show warranty” for details.
This GDB was configured as “x86_64-apple-darwin”.tty /dev/ttys001
sharedlibrary apply-load-rules all
[Switching to process 9482 thread 0x0]
2011-11-19 22:22:09.727 BMITime[9482:707] Employees: (
"<Employee 0 has $0 in assets>",
"<Employee 1 has $153 in assets>",
"<Employee 2 has $119 in assets>",
"<Employee 3 has $68 in assets>",
"<Employee 4 has $0 in assets>",
"<Employee 5 has $136 in assets>",
"<Employee 6 has $119 in assets>",
"<Employee 7 has $34 in assets>",
"<Employee 8 has $0 in assets>",
"<Employee 9 has $136 in assets>"
)
2011-11-19 22:22:09.729 BMITime[9482:707] Giving up ownership of one employee
2011-11-19 22:22:09.729 BMITime[9482:707] deallocating <Employee 5 has $136 in assets>
2011-11-19 22:22:22.800 BMITime[9482:707] deallocating <Asset Laptop 3: $51 unassigned>
2011-11-19 22:22:24.430 BMITime[9482:707] deallocating <Asset Laptop 5: $85 unassigned>
2011-11-19 22:22:24.430 BMITime[9482:707] Giving up ownership of array
2011-11-19 22:22:24.431 BMITime[9482:707] deallocating <Employee 0 has $0 in assets>
2011-11-19 22:22:24.431 BMITime[9482:707] deallocating <Employee 1 has $153 in assets>
2011-11-19 22:22:28.619 BMITime[9482:707] deallocating <Asset Laptop 9: $153 unassigned>
2011-11-19 22:22:28.620 BMITime[9482:707] deallocating <Employee 2 has $119 in assets>
2011-11-19 22:22:28.620 BMITime[9482:707] deallocating <Asset Laptop 7: $119 unassigned>
2011-11-19 22:22:28.620 BMITime[9482:707] deallocating <Employee 3 has $68 in assets>
2011-11-19 22:22:28.621 BMITime[9482:707] deallocating <Asset Laptop 0: $0 unassigned>
2011-11-19 22:22:28.621 BMITime[9482:707] deallocating <Asset Laptop 4: $68 unassigned>
2011-11-19 22:22:28.621 BMITime[9482:707] deallocating <Employee 4 has $0 in assets>
2011-11-19 22:22:28.621 BMITime[9482:707] deallocating <Employee 6 has $119 in assets>
2011-11-19 22:22:28.622 BMITime[9482:707] deallocating <Asset Laptop 1: $17 unassigned>
2011-11-19 22:22:28.622 BMITime[9482:707] deallocating <Asset Laptop 6: $102 unassigned>
2011-11-19 22:22:28.622 BMITime[9482:707] deallocating <Employee 7 has $34 in assets>
2011-11-19 22:22:28.623 BMITime[9482:707] deallocating <Asset Laptop 2: $34 unassigned>
2011-11-19 22:22:28.623 BMITime[9482:707] deallocating <Employee 8 has $0 in assets>
2011-11-19 22:22:28.635 BMITime[9482:707] deallocating <Employee 9 has $136 in assets>
2011-11-19 22:22:28.635 BMITime[9482:707] deallocating <Asset Laptop 8: $136 unassigned>
Program ended with exit code: 0


#7

That is expected behavior. When an employee is deallocated, its assets become “unassigned”

If you want to see the assets before they are unassigned, log the allAssets array as shown on page 131:


#8

Thanks, that was it. I guess I was a little confused when stepping through the code with the debugger to see the ‘holder’ having an address value, I was expecting the reference to be nil after the Employee had been dereferenced.


#9

I too have been very confused by this example, going round and round for hours in the debugger, stepping through code. Stepping through it looks like the holder ptr is still set.
when you remove an object from the ARC (employee #5 for instance) is that the first object to go and then all its assets are being removed afterwards therefore the pointer to holder becomes nil in actuality.
I’m just trying to make sure I have a through understanding of this as the whole concept seems very important but the expected output is not given in the book for when you change the holder to a weak ref…

Thanks!

Per reading another thread I have verified that ‘Objective-C Automatic Reference Counting’ is set to Yes in the build settings…