Declaring _assets as a variable instance and as a property?


#1

[Edit: I should have read previous topics that give some answers to my questions.]

Hello,

In the middle of the lesson, something appears very unclear to my eyes. It’s about the declarations made in the BNREmployee.h file. Here is the code :

#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) addAssets:(BNRAsset *)a;
- (unsigned int) valueOfAssets;

@end

First, we declare _assets as instance variable.
Then, we declare assets as a property.

Why the second declaration is useful or necessary ? Why the first one is not sufficient ?
[Edit : So I read from another thread the what follows :

Then, in our exercise, the program can be executed the same way without declaring assets as a NSArray property, am i wrong ?]

The explanation given by the book isn’t enough explicit to me :

« The property has type NSArray, which tells other classes, “If you ask for my assets, you are going to get something that is not mutable.” However, behind the scenes, the assets array is actually an instance of NSMutableArray so that you can add and remove items in BNREmployee.m. That is why you are declaring a property and an instance variable: in this case, the type of the property and the type of the instance variable are not the same. »

Can someone give me more explanation ? Thank you !


#2

[quote]The explanation given by the book isn’t enough explicit to me :

« The property has type NSArray, which tells other classes, “If you ask for my assets, you are going to get something that is not mutable.” However, behind the scenes, the assets array is actually an instance of NSMutableArray so that you can add and remove items in BNREmployee.m. That is why you are declaring a property and an instance variable: in this case, the type of the property and the type of the instance variable are not the same. »
[/quote]
That explanation is as clear as it can be. To help you get over this hurdle: What part of it do you find troubling?


#3

This part also is unclear to me.

Is the actual type of _assets an NSMutableArray?

I think it is.

However, since it’s a subclass of NSArray, it’s also an array.

Notice the getter method returns _assets as an NSArray and not as an NSMutableArray.

Is this interpretation correct?


#4

Ok so this thread has been the most clear to me on this issue.

The way I understand it now -

The _assets array is NSMutableArray.
To everything else outside of BNREmployee.h _assets is treated as NSArray because it was declared as NSArray in @property.
However, inside BNREmployee.h/m _assets is a NSMutableArray because it was declared as a NSMutableArray instance variable.

I’m assuming that means external files first look at @property of a header file for its cues on how to handle variable types and within a class it first looks at declared instance variables for its cues.

Riiiight guys? Riiight???


#5

[quote] ... @interface BNREmployee : BNRPerson { NSMutableArray *_assets; } ... @property (nonatomic, copy) NSArray *assets; ... @end [/quote]
BNREmployee wants _assets to be an instance of NSMutableArray because it is responsible for managing assets; managing assets involves adding, removing assets, etc.

However, it provides the external world with only an immutable copy of its private assets:

@property (nonatomic, copy) NSArray *assets;

because it does not want the external world to be able to modify its private assets.

Immutable copy is the key to understanding this.


#6

Ah ~ I see. That makes so much more sense.

Thank you!


#7

I have read every page up to this point and this is definitely the strangest thing I have come across and I agree the book should do more to explain why it is fine to do what it suggests.

The way I see it is

  1. we have been taught there are two ways to declare an instance variable i) explicitly ii) implicitly using property declaration
  2. we have been taught how naming conventions are very important and that the property declaration will follow these conventions automatically (ie. it adds the underscore for the instance variable and uses set prefix for setter)
  3. we are suddenly presented with a situation where we declare an instance variable, two different ways, with the same name but two slightly different types (NSArray/NSMutableArray) and expected not to have a lot of questions about that!

eg.
Should we think of the explicit instance variable in some sense overriding the implicit one or should we imagine them as two different instance variables with the same name?
When we explicitly implement the accessor methods should we imagine these are overriding what the property declaration would have done automatically?
When the instance variable “_assets” is referred to in the accessor method implementations should we think of this as referring to the explicitly declared NSMutableArray or the implicitly declared NSArray, and why?


#8

[quote]

[quote]... @interface BNREmployee : BNRPerson { NSMutableArray *_assets; } ... @property (nonatomic, copy) NSArray *assets; ... @end[/quote]
3) we are suddenly presented with a situation where we declare an instance variable, two different ways, with the same name but two slightly different types (NSArray/NSMutableArray) and expected not to have a lot of questions about that![/quote]
Let me try to explain this a bit, after first pointing out that there are two kinds of property, computed and stored, and a stored property needs a backing store.

Now, if you saw these two declarations of BNREmployee:

@interface BNREmployee : BNRPerson
{
    NSArray * _assets;
}

@property NSArray * assets;
@interface BNREmployee : BNRPerson
{
    NSMutableArray * _assets;
}

@property NSMutableArray * assets;

you wouldn’t be confused at all because there is not conflicting type names used above.

However, the following declaration may be confusing:

@interface BNREmployee : BNRPerson
{
    NSMutableArray * _assets;
}

@property NSArray * assets;

because there seems to be a type name conflict: the type of the explicitly created backing store (_assets) is NSMutableArray, and the type of the implicitly created backing store (again _assets) is NSArray. But there is actually no conflict, for two reasons: Firstly, there is no implicitly created backing store anymore; secondly, the object accessed through the property is an NSArray object and an NSMutableArray object is also an NSArray object.

The example in the book is trying to show that you can change the type of the backing store used by a stored property by explicitly creating the backing store with a new type.


#9

thanks ibex, after reading Hiding Mutability section in ch22, the way I think I’m starting to resolve this in my head is that you should think of it as the same variable (there is only one memory allocation for it) BUT you redefine its type IN A PRIVATE CONTEXT ONLY (in some sense that is what it really is)

sound reasonable?

it makes me wonder though, is there a need for a property declaration at all in this case? If the instance variable is explicitly defined mutable but has a getter method that returns immutable version, isn’t that all we need?

  • Maybe the only purpose of the property declaration is to make it clear for anyone else reading the class header file to see the variables. Also, I suppose the property declaration conveniently contains the implicit accessor method declarations which would be needed before implementing them…

#10

After reading “Implementing accessor methods” section in ch34 my understanding has changed again…

So it seems there is no instance variable automatically synthesised when you implement both accessor methods yourself.

Makes me wonder, maybe the compiler also asks:
Does an instance variable with that name already exist? - YES => no need to synthesise one

?


#11

[color=#00BF80]it makes me wonder though, is there a need for a property declaration at all in this case? If the instance variable is explicitly defined mutable but has a getter method that returns immutable version, isn’t that all we need?[/color]

Indeed, I tried commenting out the @property declaration for asset and the program ran the same. …