Removing Assets Challenge: Solution

ZGCPerson.h

[code]//
// ZGCPerson.h
// ObjC_MyFirst_CLASS_ZGCPerson_time_using_Properties
//
// Created by EvilKernel on 9/30/14.
// Copyright © 2014 Zerogravity. All rights reserved.
//

#import <Foundation/Foundation.h>

@interface ZGCPerson : NSObject

// Using properties. Properties are a shorthand for automatically declaring and implementing accessor methods. it simplifies code by making declarations and implementations ‘implicit’.

@property (nonatomic) float heightInMeters;
@property (nonatomic) int weightInKilos;

// only declaring this method explicitely for calculating BMI. Setter/getter accessors
// for remaining ones automatically taken care of by ‘@property’ shorthand.

// BMIPerson will have a method to calculate the Body Mass Index

  • (float)bodyMassIndex;

@end
[/code]

ZGCPerson.m

[code]//
//
// ZGCPerson.m
// ObjC_MyFirst_CLASS_ZGCPerson_time_using_Properties
//
// Created by EvilKernel on 9/30/14.
// Copyright © 2014 Zerogravity. All rights reserved.
//

#import “ZGCPerson.h”

@implementation ZGCPerson

  • (float)bodyMassIndex
    {
    // Using “self” (implicit local variable). self is a pointer to the object that is running the method.
    // many devs are regliious about never reading/writing to an instance variable directly.

    float h = [self heightInMeters];
    return [self weightInKilos] / (h * h);

}

@end

[/code]

ZGCEmployee.h

[code]//
// ZGCEmployee.h
// ObjC_MyFirst_CLASS_ZGCPerson_time_using_Properties
//
// Created by EvilKernel on 9/30/14.
// Copyright © 2014 Zerogravity. All rights reserved.
//

#import “ZGCPerson.h”

@class ZGCAsset; // @class can be used with header files instead of import as it does not need all of the info #import provides, just enough to read declarations. it is faster for this purpose.

@interface ZGCEmployee : ZGCPerson // ZGCEmployee is a subclass of ZGCPerson (my original class)

{
NSMutableArray *_assets;
}

//some properties for employee object
// properties will automatically create _instanceVariables as well as synthetize setter and getter methods for you
// both on primitive types declarations as well as objects type declarations, like NSDate, NSString, etc (typedefs as they are called)
@property (nonatomic) unsigned int employeeID;
@property (nonatomic) unsigned int officeAlarmCode;
@property (nonatomic) NSDate *hireDate; // points to an object
@property (nonatomic, copy) NSArray *assets; //point to an object

// method for calculating years of employment

  • (double)yearsOfEmployment;

// method to add asset objects to an array

  • (void)addAsset:(ZGCAsset *)a;

// method to remove asset from an array

  • (void)removeAsset:(NSUInteger)i;

// method for calculating value of assets

  • (unsigned int)valueOfAssets;

@end
[/code]

ZGCEmployee.m

[code]//
// ZGCEmployee.m
// ObjC_MyFirst_CLASS_ZGCPerson_time_using_Properties
//
// Created by EvilKernel on 9/30/14.
// Copyright © 2014 Zerogravity. All rights reserved.
//

#import “ZGCEmployee.h”
#import “ZGCAsset.h” //using import in this case - @class is not sufficuent as more is needed to know.

@implementation ZGCEmployee

  • (double)yearsOfEmployment
    {
    // Do I have a nil hireDate?
    if (self.hireDate) {
    //NSTimeInterval is the same as double typedef
    NSDate *now = [NSDate date];
    NSTimeInterval secs = [now timeIntervalSinceDate:self.hireDate];
    return secs / 31557600.0; //seconds per year
    }else{
    return 0;
    }
    }

/* you can override an inherited method in a subclass by writing
a new implementation (original declaration must remain the same) */

  • (float)bodyMassIndex
    {
    // return 19.0; //overrides output to fixed BMI for instance

/* when overriding a method, a subclass can also build on the original
implementation of the Superclass rather than replacing it whole. In this
case we are discounting 10% off their BMI as calculated by the original
implementation */
float normalBMI = [super bodyMassIndex]; //instruct to use method at superclass
return normalBMI * 0.9;
}

// acceessors for asset properties
/* here I override the synthetized property method/accessor for 'assets’
for a setter which sets ‘assets’ to a mutable version of NSArray */

  • (void)setAssets:(NSArray *)a
    {
    _assets = [a mutableCopy]; // means: assets = an [empty] mutable array

}

//again, overriding synthetized property method
// to return copied version of NSArray above (which is a mutable version)

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

  • (void)addAsset:(ZGCAsset *)a
    {
    // Is assets nil?
    if (!_assets) {
    // create the array
    _assets = [[NSMutableArray alloc] init];

    }
    [_assets addObject:a]; //adds an asset object to the mutable array
    }

  • (void)removeAsset:(NSUInteger)i //removes asset at supplied index
    {
    [_assets removeObjectAtIndex:i];
    }

  • (unsigned int)valueOfAssets
    {
    // sum up the resale value of assets
    unsigned int sum = 0;
    for (ZGCAsset *a in _assets) { // must count each asset in array as each employee object owns one array of assets, as per main()
    sum += [a resaleValue];
    }
    return sum;

}

// overriding description method for illustration purposes to track dealloaction

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

// overriding dealloc method to illustrate deallocation (will not actually dealloc like this

  • (void)dealloc
    {
    NSLog(@“deallocating %@”, self);
    }

@end
[/code]

ZGCAsset.h

[code]//
// ZGCAsset.h
// ObjC_MyFirst_CLASS_ZGCPerson_time_using_Properties
//
// Created by EvilKernel on 10/3/14.
// Copyright © 2014 Zerogravity. All rights reserved.
//

#import <Foundation/Foundation.h>

@interface ZGCAsset : NSObject

//properties for asset object
@property (nonatomic, copy) NSString *label;
@property (nonatomic) unsigned int resaleValue;

@end
[/code]

ZGCAsset.m

[code]//
// ZGCAsset.m
// ObjC_MyFirst_CLASS_ZGCPerson_time_using_Properties
//
// Created by EvilKernel on 10/3/14.
// Copyright © 2014 Zerogravity. All rights reserved.
//

#import “ZGCAsset.h”

@implementation ZGCAsset

// overriding description method for illustration purposes to track dealloaction - this overrides what %@ returns for the object.

  • (NSString *)description
    {
    return [NSString stringWithFormat:@"<%@: $%u>", self.label, self.resaleValue];
    }

// override dealloc method to illustrate
// how ARC deallocaction activity (will not actually dealloc this way, just log)

  • (void)dealloc
    {
    NSLog(@“deallocating %@”, self);
    }

@end
[/code]

main.m

[code]//
// main.m
// ObjC_MyFirst_CLASS_ZGCPerson_time_using_Properties
//
// Created by EvilKernel on 9/29/14.
// Copyright © 2014 Zerogravity. All rights reserved.
//

#import <Foundation/Foundation.h> //angled brackets tells the compiler that Foundation.h is a precompiled header found in the apple libs

// #import “ZGCPerson.h” //importing my first class - ZGCPerson. The quotation marks tell compiler to look for header within current project

#import “ZGCEmployee.h” //importing subclass header only - superclass header already imported in subclass’s header
#import “ZGCAsset.h” // importing header for asset class.

int main(int argc, const char * argv[])
{

@autoreleasepool {

    // Create an array of 10 ZGCEmployee objects
    NSMutableArray *employees = [[NSMutableArray alloc] init];
    
    for (int i = 0; i < 10; i++) {
        ZGCEmployee *myEmployee = [[ZGCEmployee alloc] init];
        
        // Give the instance variables interesting values
        myEmployee.weightInKilos = 90 + i;
        myEmployee.heightInMeters = 1.8 - i/10.0;
        myEmployee.employeeID = i;
        myEmployee.hireDate = [NSDate dateWithNaturalLanguageString:@"January 6th, 2003"];
        
        // Put the employees in the employee array
        [employees addObject:myEmployee];
        
    }
    
    
    // Create 10 assets objects
    for (int i = 0; i < 10; i++) {
        ZGCAsset *asset = [[ZGCAsset alloc] init];
        
        // Give them  interesting labels and resale values
        NSString *currentLabel = [NSString stringWithFormat:@"Laptop %d", i];
        asset.label = currentLabel;
        asset.resaleValue = 350 + i * 17;
    
        // Get a random number (employee) between 0 and 9 inclusive (based on array count)
        NSUInteger randomIndex = random() % [employees count];
        
        // Find that employee
        ZGCEmployee *randomEmployee = [employees objectAtIndex:randomIndex]; //avioding subscripting / easy toread

        //Assign the asset to the employee  
        [randomEmployee addAsset:asset]; // this method creates a mutable array (_assets) if it doesnt exist and adds asset to it - each employee object gets an array object of assets.
    }

   
    NSLog(@"Employees: %@", employees); // uses overwritten description method in zgemployee.m
    sleep(3);
    
    
    NSLog(@"------Giving up ownership of one employee------");
    [employees removeObjectAtIndex:5]; // invokes ovewritten dealloc() method in the class for illustration.
    sleep(3);
    
    NSLog(@"------Removing an asset from a random employee------");
        // Get a random number employee from what is left in the employee array
        NSUInteger randomIndex = random() % [employees count];
        ZGCEmployee *randomEmployee = [employees objectAtIndex:randomIndex];
    
        // iterate up to # of remaining assets to avoid NSException.
    for (int i = 0; i < [randomEmployee.assets count]; i++) {
        [randomEmployee removeAsset:i]; // method to remove an asset
    }
    sleep(3);
    
    
    NSLog(@"------Giving up ownership of arrays------");
    employees = nil; // invokes overwritten dealloc() method in the class object for illustration
    sleep(3);
    
}
return 0;

}

[/code]

[color=#4000FF]****** OUTPUT *******
2014-10-21 01:48:09.652 ObjC_MyFirst_CLASS_ZGCPerson_time_using_Properties[41868:5351905] 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>"
)
2014-10-21 01:48:12.656 ObjC_MyFirst_CLASS_ZGCPerson_time_using_Properties[41868:5351905] ------Giving up ownership of one employee------
2014-10-21 01:48:12.656 ObjC_MyFirst_CLASS_ZGCPerson_time_using_Properties[41868:5351905] deallocating <Employee 5: $836 in assets>
2014-10-21 01:48:12.656 ObjC_MyFirst_CLASS_ZGCPerson_time_using_Properties[41868:5351905] deallocating <Laptop 3: $401>
2014-10-21 01:48:12.657 ObjC_MyFirst_CLASS_ZGCPerson_time_using_Properties[41868:5351905] deallocating <Laptop 5: $435>

2014-10-21 01:48:15.659 ObjC_MyFirst_CLASS_ZGCPerson_time_using_Properties[41868:5351905] ------Removing an asset from a random employee------
2014-10-21 01:48:15.660 ObjC_MyFirst_CLASS_ZGCPerson_time_using_Properties[41868:5351905] deallocating <Laptop 1: $367>

2014-10-21 01:48:18.665 ObjC_MyFirst_CLASS_ZGCPerson_time_using_Properties[41868:5351905] ------Giving up ownership of arrays------
2014-10-21 01:48:18.665 ObjC_MyFirst_CLASS_ZGCPerson_time_using_Properties[41868:5351905] deallocating <Employee 0: $0 in assets>
2014-10-21 01:48:18.665 ObjC_MyFirst_CLASS_ZGCPerson_time_using_Properties[41868:5351905] deallocating <Employee 1: $503 in assets>
2014-10-21 01:48:18.665 ObjC_MyFirst_CLASS_ZGCPerson_time_using_Properties[41868:5351905] deallocating <Laptop 9: $503>
2014-10-21 01:48:18.665 ObjC_MyFirst_CLASS_ZGCPerson_time_using_Properties[41868:5351905] deallocating <Employee 2: $469 in assets>
2014-10-21 01:48:18.665 ObjC_MyFirst_CLASS_ZGCPerson_time_using_Properties[41868:5351905] deallocating <Laptop 7: $469>
2014-10-21 01:48:18.666 ObjC_MyFirst_CLASS_ZGCPerson_time_using_Properties[41868:5351905] deallocating <Employee 3: $768 in assets>
2014-10-21 01:48:18.666 ObjC_MyFirst_CLASS_ZGCPerson_time_using_Properties[41868:5351905] deallocating <Laptop 0: $350>
2014-10-21 01:48:18.666 ObjC_MyFirst_CLASS_ZGCPerson_time_using_Properties[41868:5351905] deallocating <Laptop 4: $418>
2014-10-21 01:48:18.666 ObjC_MyFirst_CLASS_ZGCPerson_time_using_Properties[41868:5351905] deallocating <Employee 4: $0 in assets>
2014-10-21 01:48:18.666 ObjC_MyFirst_CLASS_ZGCPerson_time_using_Properties[41868:5351905] deallocating <Employee 7: $384 in assets>
2014-10-21 01:48:18.666 ObjC_MyFirst_CLASS_ZGCPerson_time_using_Properties[41868:5351905] deallocating <Laptop 2: $384>
2014-10-21 01:48:18.667 ObjC_MyFirst_CLASS_ZGCPerson_time_using_Properties[41868:5351905] deallocating <Employee 8: $0 in assets>
2014-10-21 01:48:18.667 ObjC_MyFirst_CLASS_ZGCPerson_time_using_Properties[41868:5351905] deallocating <Employee 9: $486 in assets>
2014-10-21 01:48:18.667 ObjC_MyFirst_CLASS_ZGCPerson_time_using_Properties[41868:5351905] deallocating <Laptop 8: $486>
2014-10-21 01:48:21.670 ObjC_MyFirst_CLASS_ZGCPerson_time_using_Properties[41868:5351905] deallocating <Employee 6: $452 in assets>
2014-10-21 01:48:21.670 ObjC_MyFirst_CLASS_ZGCPerson_time_using_Properties[41868:5351905] deallocating <Laptop 6: $452>
Program ended with exit code: 0[/color]