PDA

View Full Version : How to access object properties stored in array?




ataylor2009
Mar 24, 2009, 09:56 AM
I want to create a bunch of objects (say 100+) and store them in an array. Each object has, say, 10 instance variables, all declared as properties. My question is, how do I access a specific object.property in the array? In other words, I want to access the bar property in object foo, which is stored at baz[26].

Is it just baz[26].foo.bar = newValue?

Or do I have to do something like

tempValue = [baz objectAtIndex: 26];
tempValue.bar = newValue;
[baz replaceObjectAtIndex: 26 withObject: tempValue];

I really hope it's the first one and not the second.

Thanks in advance for your help.



TEG
Mar 24, 2009, 10:04 AM
I believe it is something like the first one, but you can omit the "foo" from it, since that is just a label for something located in the 26th position on the array. So baz[26].bar = newValue? is very close to what you need.

TEG

Krevnik
Mar 24, 2009, 10:26 AM
Real answer is: Neither.

The first one won't work at all (array operator doesn't work on Obj-C objects), and the second one is redundant. It works, but it has too much code and does operations it doesn't need to.

Either one of these will work:


tempValue = [baz objectAtIndex:26];
tempValue.bar = newValue;



[baz objectAtIndex:26].bar = newValue;


They work because you store a reference to the object in the array. The array retains the object rather than making a copy. When you ask for an object at an index, it simply returns that reference again. You can edit in-place without having to copy the object back into the array (because it already has a reference).

lee1210
Mar 24, 2009, 10:31 AM
I would say that you should pick the "style" you want to use and stick with it. If you want to use Objects, etc. store them in an NS(Mutable)Array. If you want to use C-style arrays, you can use structs, etc. Mixing them just gets ugly. I will also use this as an excuse to speak unkindly about the dot notation, as it only stands to introduce ambiguity in my mind. Sending a message is much clearer in its intent when reading the code. If you see a dot, that says to me that you are accessing the element of a structure that you have a local copy of. A message pass is clearly going to an Object *.

I would say that:

[[baz objectAtIndex: 26] setBar: newValue];


is concise, easy to read, and clear that you are modifying the field of an object via a message pass.

A lot of this is just a matter of style, and this is just my opinion on the matter. I'm sure others will disagree.

-Lee

Edit: Krevnik beat me to it, and stuck with the dot-notation that the OP was using.

Krevnik
Mar 24, 2009, 10:44 AM
A lot of this is just a matter of style, and this is just my opinion on the matter. I'm sure others will disagree.


Pretty much the only extra comment for the OP I have is that using structs/c-arrays for Obj-C objects is dangerous. Yes you can do it, but then you become responsible for managing the lifetime of the object while it lives in the struct/c-array.

I prefer to keep Obj-C objects within other Obj-C objects, as it makes auditing easier, and leaks less likely. The moment I have to think heavily on the lifetime of an object is when I make mistakes, and C data types holding Obj-C objects make me think heavily on the lifetime of the object.

So don't mix the two if at all possible. That is the way to madness.

ataylor2009
Mar 24, 2009, 10:47 AM
Krevnik:

Exactly what I needed. Thank you for the assistance.

Actually, thanks to all who contributed. The dialog is nearly as helpful as the final solution in most cases.

ataylor2009
Mar 24, 2009, 11:10 AM
I was planning on using an NSArray (or NSMutableArray) to hold the objects. If I said something in my original post that led you to believe otherwise, then I misspoke (or miswrote. Whatever.).

Thank you all again for your help.

lee1210
Mar 24, 2009, 11:22 AM
I was planning on using an NSArray (or NSMutableArray) to hold the objects. If I said something in my original post that led you to believe otherwise, then I misspoke (or miswrote. Whatever.).

Thank you all again for your help.

It was just a bit ambiguous... the only thing you said was "in an array", and the confusion was somewhat exacerbated by the use of [], which will only work on C-style arrays, not Objects (as has been mentioned above). No harm, no foul... it just might be best to be explicit in the future so people know "what's on the table", so to speak.

-Lee

ataylor2009
Mar 25, 2009, 10:20 PM
Okay, I've written some code, but I'm clearly doing something wrong. Here's my first attempt:

[rooms objectAtIndex: roomCount].roomID = newID;

where rooms is an instance of NSMutableArray, roomCount is an integer, roomID is an instance variable of type int in my Room object, and newID is an instance of NSNumber. The error message I'm getting when I compile is

"error: request for member 'roomID' in something not a structure or union"

What am I missing here? As usual, thank you all in advance for your guidance.

lee1210
Mar 25, 2009, 10:55 PM
[[rooms objectAtIndex:roomCount] setRoomID: newID];

Is the de-sugared code you're running. Does your room class have a setRoomID: method? Can you post the class declaration?

-Lee

kainjow
Mar 25, 2009, 10:58 PM
You need to create an accessor method to assign the value of roomID, unless you declare it as a property. Also int != NSNumber. You must use the intValue method on an NSNumber.

ataylor2009
Mar 26, 2009, 07:17 AM
The class declaration is

@interface Room : NSObject
{
int roomID;
NSString *name;
NSString *desc;
int N, E, S, W, U, D;
}

@property int roomID, N, E, S, W, U, D;
@property (copy, nonatomic) NSString *name, *desc;

@end

I thought by using the @property directive (and @synthesize in the *.m file) I was spared the hassle of writing accessor methods? Doesn't the property feature create setroomID: and roomID: methods for me?

eddietr
Mar 26, 2009, 08:32 AM
[rooms objectAtIndex: roomCount].roomID = newID;


So, I think, at least with Apple's GCC that ships with the current dev tools, it is still not possible to mix brackets and dots quite this way. You can mix them in other ways, and you would think this way would work, but it doesn't.

I used to know exactly why this is the case, but I can't remember right now.

But you can do something like:


Room* room = [rooms objectAtIndex: roomCount];
room.roomID = [newID intValue];
// or [room setRoomID:[newID intValue]];


or


[[rooms objectAtIndex: roomCount] setRoomID: [newID intValue]] // yuck!

ataylor2009
Mar 26, 2009, 11:52 AM
...Also int != NSNumber. You must use the intValue method on an NSNumber.

Doh! There were so many errors when I compiled my test code the first time that I totally missed this. Thanks for pointing it out.

Originally I was going to store all the data in an array (as opposed to storing the data in an object in an array), which is why I was converting to NSNumber objects. I can remove that bit of deadweight now.

Thanks again.