Help pls with warnings


#1

I have some problem with BMITime project from chapter 20.

May I ask you to explain me why I got this warnings when I’d changed :
in Employee.h from

@class Asset; //#import "Asset.h"
to

//@class Asset; #import "Asset.h"
and in Asset.h from

@class Employee; //#import "Employee.h"
to

//@class Employee; #import "Employee.h"

I got errors like this

Here are my code of “BMITime” from the chapter 20

Person.h

[code]//
// Person.h
// BMITime
//
// Created by Sergey-MacOS on 10.12.12.
// Copyright © 2012 Sergey-MacOS. All rights reserved.
//

#import <Foundation/Foundation.h>

@interface Person : NSObject{
// // Variables will be here
// float heightInMeters;
// int weightInKilos;
}
@property float heightInMeters;
@property int weightInKilos;
// // Methods will be here

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

person.m

[code]//
// Person.m
// BMITime
//
// Created by Sergey-MacOS on 10.12.12.
// Copyright © 2012 Sergey-MacOS. All rights reserved.
//

#import “Person.h”
@class Asset;

@implementation Person

@synthesize weightInKilos = _weightInKilos;
@synthesize heightInMeters = _heightInMeters;

// other methods implementation

-(float) bodyMassIndex{
return _weightInKilos / (_heightInMeters * _heightInMeters);
}

@end
[/code]

Employee.h

[code]//
// Employee.h
// BMITime
//
// Created by Sergey-MacOS on 11.12.12.
// Copyright © 2012 Sergey-MacOS. All rights reserved.
//

#import “Person.h”
@class Asset;
//#import “Asset.h”

@interface Employee : Person{
NSMutableArray *assets;

}
@property int employeeID;

  • (void) addAssetObject:(Asset *)a;
  • (int) valueOfAssets;

@end
[/code]

Employee.m

[code]//
// Employee.m
// BMITime
//
// Created by Sergey-MacOS on 11.12.12.
// Copyright © 2012 Sergey-MacOS. All rights reserved.
//

#import “Employee.h”
#import “Asset.h”

@implementation Employee
@synthesize employeeID = _employeeID;
-(float)bodyMassIndex{
return [super bodyMassIndex] * 0.9;
}

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

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

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

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

Asset.h

[code]//
// Asset.h
// BMITime
//
// Created by Sergey-MacOS on 14.12.12.
// Copyright © 2012 Sergey-MacOS. All rights reserved.
//

#import <Foundation/Foundation.h>
@class Employee;
//#import “Employee.h”

@interface Asset : NSObject
@property (strong) NSString *label;
@property unsigned int resaleValue;
@property (weak) Employee *holder;
@end
[/code]

Asset.m

[code]//
// Asset.m
// BMITime
//
// Created by Sergey-MacOS on 14.12.12.
// Copyright © 2012 Sergey-MacOS. All rights reserved.
//

#import “Asset.h”
#import “Employee.h”

@implementation Asset
@synthesize label = _label;
@synthesize resaleValue = _resaleValue;
@synthesize holder = _holder;

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

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

main.m

[code]//
// main.m
// BMITime
//
// Created by Sergey-MacOS on 10.12.12.
// Copyright © 2012 Sergey-MacOS. All rights reserved.
//

#import <Foundation/Foundation.h>
#import “Person.h”
#import “Employee.h”
#import “Asset.h”

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

@autoreleasepool {
    NSMutableArray *employees = [[NSMutableArray alloc] init];
    for (int i = 0; i <10; i++){
        
        //  Create an item of Person class
        Employee *person = [[Employee alloc] init];
        
        // Set its params
        [person setHeightInMeters:2.02-i/10.0];
        [person setWeightInKilos:78+i];
        [person setEmployeeID:i];
        
        [employees addObject:person];
    }
    // allAssets array - pointers to all assets
    NSMutableArray *allAssets = [[NSMutableArray alloc] init];
    
    // Creating assets for our employees array
    for (int i = 0; i < 10; i++) {
        
        Asset *asset = [[Asset alloc] init];
        //  generate random params for asset
        NSString *currentLabel = [NSString stringWithFormat:@"Laptop #%d", i];
        [asset setLabel:currentLabel];
        [asset setResaleValue:i * 23];
        
        //  find random employee and give to him new asset
        NSUInteger randomIndex = random() % [employees count];
        [employees[randomIndex] addAssetObject:asset];
        
        // Adding it to allAssets collection
        [allAssets addObject:asset];
    }
    
    
    NSLog(@"Employees - %@", employees);
    NSLog(@"Giving up ownership of one employee");
    [employees removeObjectAtIndex:5];
    NSLog(@"allAssets : %@", allAssets);
    NSLog(@"Giving up ownership array");
    
    employees = nil;
    allAssets = nil;

}
return 0;

}

[/code]


#2

Why are you importing (circularly) Asset.h from Employee.h and Employee.h from Asset.h?
You should instead use the @class construct to make a forward declaration in order to avoid importing a class’s header file.


#3

[quote=“ibex10”]Why are you importing (circularly) Asset.h from Employee.h and Employee.h from Asset.h?
You should instead use the @class construct to make a forward declaration in order to avoid importing a class’s header file.[/quote]
Thank you for your response.

As I understand in all headers files I should use

@class NameOfClass; instead of #import
And in the .m files I should use #import, because I’ll use some methods from that class in implementation, so I need to know about them from .h file of using class.

Am I right?


#4

You are almost right.

You should use the forward declaration construct whenever the compiler does not need to know much about the object. For example, when declaring a pointer to a class type:

//  FooBar.h

#import <Foundation/Foundation.h>

@class Foo;

@interface FooBar : NSObject

@property (strong) Foo *foo;

@end

However, you should import whenever the compiler needs to know more about a class. For example, when subclassing a class:

//  FooBar2.h

#import "Foo.h"

@interface FooBar2 : Foo

@end

#5

I still don’t understand why I #import “Employee.h” will give an error. The code will only compile if you use @class.


#6

As I understand it, it has to do with the sequence of files in compiling. Don’t ask me precisely how, I just found some info on github and couldn’t follow all of it. From the book, it is suggested that @class is only ‘more lightweight’ than #import. At first I took it as a suggestion instead of an requirement. I had no objections to the headerfile knowing all there is to know about Employee class. But there is clearly more to it.
Cost me hours to find the error in my code :slight_smile:
Anyway, I guess @class is giving the compiler a message: don’t worry, you will see this class later. And #import seems to be more demanding.
Still not very clear, is it? Sorry :frowning: