Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Declaration under interface in Objective C

I am studying Big Nerd Ranch's Objective C programming book. I saw a code like below:

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

In this code, why do you declare NSMutableArray *_assets under the interface? How is this different than declaring it as a property, and what purpose does it serve?

Lastly, I see there is a NSArray *assets in a property. Is this basically same as NSMutableArray *_assets?

like image 636
Kahsn Avatar asked Apr 28 '15 21:04

Kahsn


2 Answers

Here, you're declaring an instance variable named _assets:

@interface BNREmployee : BNRPerson {
    NSMutableArray *_assets;
}

You can now use this variable within the implementation of your class:

_assets = @[ @1, @2, @4 ].mutableCopy;
NSLog(@"The Answer is %@.", _assets[0]);

However, instance variables are private in Objective-C, which is good if you do not want anything else to access it. However what if you need other classes to be able to access and/or change assets?

For the most part you will want to use a property iVar.

By using a property we automatically create the setters and getters, meaning this can be overridden for customization and used by other classes (if placed in the header .h file).

@property (nonatomic, assign) NSMutableArray *assets;

NSMutableArray is just the mutable (editable) counterpart to NSArray, it means we can modify the values of the array by inserting new ones, deleting old ones and moving the indexes around.

like image 116
Oliver Atkinson Avatar answered Oct 07 '22 00:10

Oliver Atkinson


I'm not sure why they did that but as a general good practice, you shouldn't do that yourself. The header file should be reserved for the public interface of the class. Only put things in there that callers and users of that class actually need to see, which will generally be properties, methods, and perhaps extern constants.

Then the question becomes in the implementation whether to use a property or a regular instance variable. This is largely preference based. Some people declare properties for everything and don't use plain ivars at all. Others use ivars for everything and only properties when they want to declare a custom setter/getter for the variable in question. I am in the latter camp but it is arguable that is clearer and easier to read if everything is just a property.

edit

I misread the code. What I say above stands normally, but what they are doing there is exposing an API that is different than the underlying data. Editing my answer now.

When you declare a property without a custom @synthesize and without having overridden both the setter and getter if they are applicable, an underlying variable is created with the underscore in front. What they are doing here is returning an NSArray in the public API to ensure the internal variable is not modified while internally using an NSMutableArray.

I would say that in general though, that variable declaration (NSMutableArray *_assets;) should still go in the implementation file. The caller should probably not need to know that it is mutable under the hood.

There are actually a lot of existing questions touching upon this already. Here is a search query with a number of them: https://stackoverflow.com/search?q=mutable+ivar+immutable+property

like image 35
Dima Avatar answered Oct 06 '22 22:10

Dima