0

I am trying to grab a relationship property of an object from a mutable array.

theNewItems[0].step is giving the error,  Property 'step' found on object of type id.

Here is how I created the array:

 NSMutableArray* theNewItems = [NSMutableArray arrayWithCapacity:20];

 [theNewItems addObject:_itemsOnLoad[0]];
 [theNewItems addObject:_itemsOnLoad[1]];
 [theNewItems addObject:_itemsOnLoad[2]];

And here is how the array logs out

<Items: 0x1706842e0> (entity: Items; id: 0xd000000001900004 <x-coredata://AFF50577-0975-4124-AC70-074F355B73A0/Steps/p100> ; data: {
    item = "0xd000000016000000 <x-coredata://AFF50577-0975-4124-AC70-074F355B73A0/Dare/p1408>";
    sid = 545;
    step = "step three";
    wasdeleted = nil;
    whenadded = nil;
}),
    <Items: 0x170684330> (entity: Items; id: 0xd000000001840004 <x-coredata://AFF50577-0975-4124-AC70-074F355B73A0/Steps/p97> ; data: {
    item = "0xd000000016000000 <x-coredata://AFF50577-0975-4124-AC70-074F355B73A0/Dare/p1408>";
    sid = 544;
    step = "step two";
    wasdeleted = nil;
    whenadded = nil;
}),
    <Items: 0x170684380> (entity: Items; id: 0xd000000001780004 <x-coredata://AFF50577-0975-4124-AC70-074F355B73A0/Steps/p94> ; data: {
    item = "0xd000000016000000 <x-coredata://AFF50577-0975-4124-AC70-074F355B73A0/Dare/p1408>";
    sid = 543;
    step = "step one";
    wasdeleted = nil;
    whenadded = nil;
})
)}

Should I be creating the mutablearray differently? Or how can I grab the property "step"?

Thanks in advance for any suggestions.

1
  • Is there only one entity you are dealing with or many? Commented Jun 30, 2017 at 20:20

2 Answers 2

2

For clarification...

An NSArray (mutable or not) can hold objects of any type. So, when you "get" an object from the array, the compiler needs to know what you are getting.

Example:

NSMutableArray *a = [NSMutableArray arrayWithCapacity:40];
[a addObject:[UIView new]];     // add a UIView
[a addObject:@"A string"];      // add a NSString
[a addObject:@100];             // add a NSNumber

You now have an array with a View, a String and a Number. If you try to do this:

UIView *v = a[0];
NSString *s = a[1];
NSNumber *n = a[2];

You'll get warnings because while the types are correct, the compiler doesn't know that.

To actually use the objects you've stored in the array, you have to cast them. So, with the same example data:

UIView *v = (USView *)a[0];
NSString *s = (NSString *)a[1];
NSNumber *n = (NSNumber *)a[2];

is fine... you can use your v s and n objects as you'd expect.

For your specific object type of Items, you could:

Items *thisItem = (Items *)theNewItems[0];
NSString *theStep =  thisItem.step;

or, more concisely:

NSString *theStep = ((Items *)theNewItems[0]).step;

In 2015, Apple introduced "Lightweight Generics" into Objective-C. This allows you to declare an array of type:

NSMutableArray <Items *> *theNewItems = [NSMutableArray arrayWithCapacity:20];

[theNewItems addObject:_itemsOnLoad[0]];
[theNewItems addObject:_itemsOnLoad[1]];
[theNewItems addObject:_itemsOnLoad[2]];

NSString *theStep = theNewItems[0].step;

And no more casting. Note that you still add your Items objects to the array in the same manner.

Another note: Reading around you'll find some debate about arrayWithCapacity. The most reliable info I've found explains that it perhaps used to make memory management a bit more efficient, but these days it's simply a "hint" and, really, only makes for readability as in:

"When I review my code, I see that I'm expecting this array to hold 40 objects."

It does not, however, pre-allocate memory... nor does it limit the array to 40 elements - the array will still expand as you continue to add objects to it.

Sign up to request clarification or add additional context in comments.

1 Comment

Wow. This is one of the clearest, answers on SO I have ever read. Wish I could give it more than one upvote. I went with the generic lightweight version and it worked like a charm.
0

You don't need to use arrayWithCapacity you can just make an array using [[NSMutableArray alloc] init]; which will have no limit on capacity.

To get the property just say ((Items *)theNewItems[x]).step, x being the index at which you want the property. Also if you want to skip the casting step when pulling the object out of the array define your array as NSMutableArray<Items *> * theNewItems = [[NSMutablearray alloc] init] then you can just say theNewItems[x].step

1 Comment

Nothing wrong with using arrayWithCapacity - real benefit is readability, and the OP may have some other reason for using it. In any case, it had nothing to do with the issue. You could edit your answer to make it much more clear why the need to cast it.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.