-2

I want to keep track of a variable amount of objects in a game, which are all instances of the same class or inheriting classes, in Objective-C.

In Java I would do something like

List<MyClass> list = new ArrayList<>();

And that would be it. I couldn't find a similarly obvious solution using Cocoa / Foundation. Can I use NSMutableArray for that in some way? Note, I need the objects to be of the specific type I want them to be, not id. I would also prefer not having to use Categories or inherit from NSMutableArray, but instead just use NSMutableArray in a way so that what it returns is cast into the class I need.

Vingdoloras
  • 109
  • 8
  • It wouldn't be hard to right your own collection class, or a category on NSMutableArray to check the type of what you insert, but as far as foundation classes, something like this does not exist. – Kevin DiTraglia Jun 27 '14 at 17:02
  • There is nothing like that in Obj-C. Even in Java generics came in 1.5, they were not there since the beginning. – Sulthan Jun 27 '14 at 17:03
  • On the bright side it does exist in swift! – Kevin DiTraglia Jun 27 '14 at 17:04
  • Regarding the "duplicate answer": I saw the linked question before, but wasn't quite satisfied with the answer. The accepted answer to my question is exactly what I was looking for (a way to use NSMutableArray, but still be able to take out objects and have them be of the type I want, and not id). Should I try to rephrase my question to point out the focus on using NSMutableArray without having to modify or inherit from it? – Vingdoloras Jun 27 '14 at 18:54

2 Answers2

1

Objective-C does not have generics, so NSArray and NSMutableArray are not strongly typed in the way you desire. It's pretty simple to work around this though. Given the following code, where you have a NSMutableArray named list with an item in it of type MyClass:

NSMutableArray *list = [NSMutableArray new];
MyClass *objectToInsert = [MyClass new];
[list addObject:objectToInsert];

To retrieve the object from the array and treat it as a pointer to type MyClass, simply declare your variable as such:

MyClass *myObject = list[0];
myObject.someProperty = someValue;
[myObject doSomething];

Xcode will offer full code completion, etc. Note that you do not need to use a C-style cast; you can implicitly cast any variable of type id to an object pointer when declaring a variable. You can also do this in loops:

for (MyClass *item in list) {
    item.someProperty = someValue;
    [item doSomething];
}

Note that in simple cases where you just want to pass the objects around or maybe invoke one method, you can leave the object of type id if you're comfortable with that.

[list[0] doSomething];

The above will still send the message doSomething to an object of type MyClass and invoke the proper method on that object, assuming the object in the array is of the correct type. There is basically no distinction at runtime between doing this and the more explicit syntax shown earlier.

Note that the compiler or runtime will not check that the items in the array actually are of type MyClass. Thus, you can get unexpected behavior or runtime errors if you insert other types of objects into the array. In my experience, this usually isn't much of a risk for most code.

Also, as mentioned in the comments, you could create a custom class with "strongly typed" convenience methods to populate and access an NSMutableArray. Methods with signatures like - (void)addWidget:(MyWidget *)obj or - (void)insertWidget:(MyWidget *)obj atIndex:(NSInteger)index will allow Xcode to check the type of objects inserted into the array at compile time in some but not all cases (if you have a variable of type id, you can still use it with these methods without any compile-time warnings or errors, thus allowing insertion of objects of other types). If you want to be even more defensive about it, you could add an assertion to these methods to check the type at runtime:

- (void)addWidget:(MyWidget *)obj
{
    NSAssert([obj isKindOfClass:[MyWidget class]]);
    [self.list addObject:obj];
}

In my experience though I find this all to be more effort than it's worth, unless you have some significant logic to associate with the manipulation of the array.


Note that Swift does have a full implementation of generics.

Mike Mertsock
  • 11,825
  • 7
  • 42
  • 75
  • Thank you, that works just like I expected. I tried to explicitly cast it but that didn't work so well, so I did not expect implicit casting to work. And oh yeah, looking forward to Swift, but I want to be able to use Obj-C properly as well :) – Vingdoloras Jun 27 '14 at 18:50
0

It's against objective-c concepts. In objective-c you can send any selector to any object.

However there's a workaround for that. I didn't use this library, so I can't say if it's handy or not, but it's something you may want to look at.

kovpas
  • 9,553
  • 6
  • 40
  • 44