This is driving me a bit crazy.
In the first 2-3 pages of Chapter 23, we are to modify by “adding holder relationship.” Upon making the modifications, the build succeeds but when I run the program I get the message:
thread 1:EXC_BAD_ACCESS (code=2, address=0x7fff5f3ffd98)
and one of the new lines that I have entered into BNRAsset.m is hilighted, namely
return [NSString stringWithFormat:@"<%@: $%d, assigned to %@>", self.label, self.resaleValue, self.holder];
I have checked and rechecked for typos and can’t find any. The project runs fine prior to the additions for Chap. 23 and also runs fine if I modify the above line of code and remove the “self.holder” portion, i.e. if I use
return [NSString stringWithFormat:@"<%@: $%d unassigned>", self.label, self.resaleValue];
I assume I’m overlooking something simple… can anyone review this and help me out? Following is all the code for the modified project.
Thanks!
//
// BNRAsset.h
// BMITime with properties
#import <Foundation/Foundation.h>
@class BNREmployee;
@interface BNRAsset : NSObject
@property (nonatomic, copy) NSString *label;
@property (nonatomic) BNREmployee *holder;
@property (nonatomic) unsigned int resaleValue;
@end
//
// BNRAsset.m
// BMITime with properties
#import "BNRAsset.h"
#import "BNREmployee.h"
@implementation BNRAsset
- (NSString *)description
{
// return [NSString stringWithFormat:@"<%@: $%d>", self.label, self.resaleValue];
// Is holder non-nil?
if (self.holder) {
return [NSString stringWithFormat:@"<%@: $%d, assigned to %@>", self.label, self.resaleValue, self.holder];
} else {
return [NSString stringWithFormat:@"<%@: $%d unassigned>", self.label, self.resaleValue];
}
}
- (void)dealloc
{
NSLog(@"deallocating %@", self);
}
@end
//
// BNREmployee.h
// BMITime with properties
// #import <Foundation/Foundation.h>
// above not needed because the #import "BNRPerson" already has imported it (?)
#import "BNRPerson.h"
@class BNRAsset;
@interface BNREmployee : BNRPerson
// Move this next declaration to BNREmployee.m as a class extension (Chap. 22)
/*
{
NSMutableArray *_assets;
}
*/
@property(nonatomic) unsigned int employeeID;
//@property(nonatomic) int officeAlarmCode; removed in Chap. 22
@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
// BMITime with properties
#import "BNREmployee.h"
#import "BNRAsset.h"
// A class extension
@interface BNREmployee ()
{
NSMutableArray *_assets;
}
@property (nonatomic) unsigned int officeAlarmCode;
@end
@implementation BNREmployee
// Accessors for assets properties
- (void)setAssets:(NSArray *)a
{
_assets = [a mutableCopy];
}
- (NSArray *)assets{
return [_assets copy];
}
- (void)addAsset:(BNRAsset *)a
{
// Is asset nil?
if (!_assets) {
// Create the array
_assets = [[NSMutableArray alloc]init];
}
[_assets addObject:a];
a.holder = self;
}
- (void)removeAsset:(BNRAsset *)a
{
[_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 %d>", self.employeeID];
return [NSString stringWithFormat:@"<Employee %d: $%d in assets>, %@", self.employeeID, self.valueOfAssets, self.assets];
}
- (void)dealloc
{
NSLog(@"deallocating %@", self);
}
- (double)yearsOfEmployment
{
// Do I have a non-nil hiredate?
if (self.hireDate) {
// NSTimeInterval is the same as double
NSDate *now = [NSDate date];
NSTimeInterval secs = [now timeIntervalSinceDate:self.hireDate];
return secs / 31557600.0; // secs in a year
} else {
return 0;
}
}
- (float)bodyMassIndex
{
// return 19.0;
float normalBMI = [super bodyMassIndex];
return normalBMI * 0.9;
}
@end
//
// BNRPerson.h
// BMITime with properties
#import <Foundation/Foundation.h>
@interface BNRPerson : NSObject
// BNRPerson has two properties
@property (nonatomic) float heightInMeters;
@property (nonatomic) int weightInKilos;
// BNRPerson has a method that calculates the Body Mass Index
- (float)bodyMassIndex;
@end
//
// BNRPerson.m
// BMITime with properties
#import "BNRPerson.h"
@implementation BNRPerson
/*
- (float)heightInMeters
{
return _heightInMeters ;
}
- (void)setHeightInMeters:(float)h
{
_heightInMeters = h;
}
- (int)weightInKilos
{
return _weightInKilos;
}
- (void)setWeightInKilos:(int)w
{
_weightInKilos = w;
}
*/
- (float)bodyMassIndex
{
float h = [self heightInMeters];
return [self weightInKilos] / (h * h);
}
@end
//
// main.m
// BMITime with properties
#import <Foundation/Foundation.h>
// #import "BNRPerson.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 and instance of BNR employee
BNREmployee *mikey = [[BNREmployee alloc] init];
mikey.weightInKilos = 90 + i;
mikey.heightInMeters = 1.8 - i/10.0;
mikey.employeeID = i;
// Put the employee 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;
// NSLog(@"Current label %d is '%@'", i, asset.label);
asset.resaleValue = 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];
}
// Print employees and their assigned assets
NSLog(@"Employees: %@", employees);
// For Chap. 21 Challenge: removing assets
// Remove an asset from a random employee if he has an asset
// First, choose a random employee
// Get a random number between 0 and 9 inclusive
NSUInteger randomIndex = random() % [employees count];
NSLog(@"randomIndex is %lu", (unsigned long)randomIndex);
// Find that employee
BNREmployee *randomEmployeeLoser = [employees objectAtIndex:randomIndex];
// Second, check if that employee has any assets
if (randomEmployeeLoser.assets) {
NSLog(@"Found an employee with assets");
// Get his asset count
NSLog(@"Loser asset count is %lu", (unsigned long)[randomEmployeeLoser.assets count]);
// Remove his first asset
[randomEmployeeLoser removeAsset:[randomEmployeeLoser.assets objectAtIndex:0]];
NSLog(@"Loser asset count after loss is %lu\n\n", (unsigned long)[randomEmployeeLoser.assets count]);
// Use this if you want his assets to show as (null) if after loss he has 0 assets
if ([randomEmployeeLoser.assets count] == 0) {
randomEmployeeLoser.assets = nil;
}
// Print employees and their assigned assets
NSLog(@"Employees: %@\n\n", employees);
} else {
NSLog(@"This employee has no assets to remove\n\n");
}
// NSLog(@"Giving up ownership of one employee");
// [employees removeObjectAtIndex:5];
// NSLog(@"Giving up ownership of arrays");
// employees = nil;
NSLog(@"\n\n***** END OF ACTIVE CODE IN main.m *****\n\n");
}
return 0;
}