why won't @property instantiate an array?

I'm confused a bit about how @property works. My example is this... I have a XYZPerson class, in it I use @property for NSStrings of first and last names, and then an NSMutableArray to hold them. In main, I create an instance of the person (see code below), use the setters for the names... and then use NSLog to test if they print out... and they do. I then use the addObject function to add the names to the array, try to print them out using NSLog, but it returns NULL, because the array doesn't exist. If I then overwrite the init method to instantiate the array, now the array prints as expected. So why would @property create NSStrings without having to instantiate them elsewhere, while it won't do the same for an array, and possibly other things like sets and dictionaries?


//XYZPerson interface


@interface XYZPerson : NSObject


@property (strong, nonatomic) NSString *firstName;

@property (strong, nonatomic) NSString *lastName;

@property NSMutableArray *arr1;

@end


//XYZPerson implementation


#import "XYZPerson.h"


@implementation XYZPerson

@end


//main



#import <Cocoa/Cocoa.h>

#import "XYZPerson.h"


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

{

XYZPerson *fredJones = [XYZPerson new];


fredJones.firstName = @"Fred";

fredJones.lastName = @"Jones";

[fredJones.arr1 addObject:@"Fred"];

[fredJones.arr1 addObject:@"Jones"];


NSLog(@"first name: %@", fredJones.firstName);

NSLog(@"last name: %@", fredJones.lastName);

NSLog (@"array contents: %@", fredJones.arr1);


return NSApplicationMain(argc, argv);

}


the strings exist, will print out, the array does not. ???

however, if I add this to the XYZ implementation... now the array works:



-(id) init

{

self = [super init];

if(self)

{

_arr1 = [[NSMutableArray alloc] init];

}

return self;

}

Accepted Reply

You are assigning a new value to the strings, effectively creating a new object.


For the array you are just assuming it already exists and sending it a message.

Replies

You are assigning a new value to the strings, effectively creating a new object.


For the array you are just assuming it already exists and sending it a message.

ah. okay, let me see if I have this right. When I use the @"Fred" ... that is the point where a new object IS being created, and then it is being assigned to my instance variable.


Can I clarify here... if I have a class that has arrays and sets and dictionaries... is creating those objects on the heap in the init method the best practice? Or is there a better way?

If you have properties whose value are collections (NSArray, NSSet, NSDictionary), then, yes, the normal practice is to remember to actually create those objects in your init.


It's worth noting that exposing a property of type NSMutableArray is almost certainly a terrible idea, because it defeats your attempt to encapsulate that property within the class. Anyone can modify the array without the XYZPerson object knowing about it.


Of course, anyone can change the NSString properties, too, but there's a difference. In that case, they can only replace the value with another NSString, and they can only replace the value. They can't mutate the values themselves. (They could if you declared them NSMutableString, but you didn't.)


There's a whole series of subtle but major problems with properties with mutable values, which tend to manifest themselves as bugs that crash your app, or cause your UI to malfunction.


I'm not suggesting that you do anything different for now, but it's an overall perspective to keep in mind for the future.

I hope you don't mind me expanding upon your comments... this is another area I'm pretty fuzzy on and isn't ever really explicitly layed out in any of the texts I've read on Objective-C. So, first question... who do you mean when you say "Anyone?" I know that my NSMutableArray is declared in the interface, making it public... but who would manipulate it besides me? Are we talking about in a much larger software development environment where you're perhaps designing objects to fit into a larger whole... and other developers might misuse your object if you gave them the opportunity?


Next, if a the interface is not a good place for an NSMutableArray, where else should it go... a class extension?


Thanks for letting me get a little off topic here... this is my second post to this forum so I'm not sure if we're allowed to drift off from the original topic... my first post someone kind of spanked me for asking a follow up question. In general I find that it is very hard to learn Objective-C in 2019... everyone seems to have migrated to Swift, and the language has not stayed static, meaning that the books and web info (youtube) you can find on Objective-C mostly come from 2014 and earlier and very few of the examples actually work because things have been deprecated or otherwise changed, or most insidious the examples rely on a variety of cocoa bindings which are rarely explained in a clear manner.

It is generally a bad idea to have private members of an object be directly accessible. That being said, this is a "good practice" kind of thing. You wouldn't want an interviewer or some other person with power over see you do that. You'd get spanked again. But if you are writing this just for yourself, it won't hurt anything. I do it all the time.


There are a number of ways to be clever and fancy with properties. You can define them in an extension to your own class, defined in the .m file. As object-oriented languages go, Objective-C is quite primitive. If you want to have private properties, you have to do tricks like this. This is why people prefer Swift. They want a complicated and "elegant" solution to these problems. But complicated solutions are often just that. Swift is a good example of this phenomenon. In 4 years, the authors of Swift still haven't figured out how to do a string. Swift's most valuable attribute is its ability to help its programmers demonstrate encyclopedic knowedge of "good practice" language minutae to impress other people. By comparison, Objective-C is messy and dirty, but always gets the job done somehow.


In an earlier reply, I considered telling you about yet another property trick to make them easier to use. But you'll figure those things out. Any of these tricks come with a cost of performance and/or complexity. That's why I rarely use them. But I don't write code for anybody else. And I'm also the king of person that doesn't use ARC. So do what I say, not what I do.🙂


I can't imagine anyone complaining about a follow-up question. But drifting off-topic is a bad idea. How would you feel if you were looking for one specific answer and it was only found in a thread that started off about something else entirely. You might skip over that thread because it looks irrelevent. If you have a question about bindings, start a new question.

>I can't imagine anyone complaining about a follow-up question


I think it was about failing to initially mark a thread solved, even admitting it was - before going back to the trough 😉 - all good now, as evidenced in this thread...marking solved/helped all around works to let others know they're on the right track. New users need spanking, errrr, prodding, sometimes.