0

This is a newbie question. I have an object that looks like the following (e.g. MyObject.h).

#import <Foundation/Foundation.h>
#import "JSONModel.h"
@protocol MyObject
@end
@interface MyObject : JSONModel
@property (strong,nonatomic) NSString* name;
@end

And the implementation looks like the following (e.g. MyObject.m).

#import "MyObject.h"
@implementation MyObject
@end

In my code elsewhere, I then define a NSMutableArray as follows.

NSMutableArray<MyObject>* list;
list = [[NSMutableArray alloc] init];

And I get this warning.

Incompatible pointer types assigning 'NSMutableArray<MyObject> ' from 'NSMutableArray'

I know from generics aren't supported out-of-the-box by Objective-C for collections (and that is not what I am trying to do here either), but my NSMutableArray is defined with such a protocol MyObject because I am trying to follow the examples from "JSONModel's" GitHub page.

The code still compiles, but with the warning above. How do I

  • make the warning go away, or
  • allocate/initialize NSMutableArray correctly?

Update:

I continued to search how to get rid of that warning, and it turns out if I create a NSMutableArray like the following, the warning goes away (and project compiles without errors). I will write a unit test and see if it works as expected.

list = (id)[NSMutableArray new];
Conspicuous Compiler
  • 6,403
  • 1
  • 40
  • 52
Jane Wayne
  • 8,205
  • 17
  • 75
  • 120
  • 1
    What do you think the `` accomplishes? – Hot Licks May 13 '14 at 18:16
  • I'm surprised it didn't give an error message. Only protocols should be used in <>, not classes. – Bedford May 13 '14 at 18:19
  • But the protocol is implemented. `@protocol MyObject @end` – Gonzo May 13 '14 at 18:21
  • Note that you should not use the same name for a protocol and a class. – Hot Licks May 13 '14 at 18:21
  • @HotLicks: `NSObject` is both a protocol and a class. – Martin R May 13 '14 at 18:23
  • 2
    How does NSMutableArray conform to your protocol ? How have you done this ? – Sandeep May 13 '14 at 18:28
  • After reading the github description, I'm not sure you should instantiate the array yourself. Just declare it and let the library do the object creation for you when it's parsing the json string. – Bedford May 13 '14 at 18:29
  • @Bedford Yes, but I need to write at least 2 unit tests, one to create the JSON string from the Object and one to create the Object from the JSON string; for the latter case, you are right, but what about the former case? – Jane Wayne May 13 '14 at 18:32
  • Ouch. Well that's tricky, you can either create a subclass of NSMutableArray which conforms to the protocol MyObject and use assign an instance of that to variable/property you want. The other way would be to use reflection/introspection to instantiate it (kinda ugly). I would go with the first one if I had to. – Bedford May 13 '14 at 18:36
  • @HotLicks Ok, so if one should not use the same name for a protocol and a class, I will definitely consider that practice. But, hopefully, someone from the JSONModel project can help enlighten me (us) why the example code defined a protocol and class with the same name? IMO, example codes should adhere to the practicing convention/standard, especially if the source (of the code) has a wide audience, otherwise, new users and learners will develop very bad habits. – Jane Wayne May 13 '14 at 18:47
  • 1
    Agreed. I'd open a defect with the JSONModel team. I think they've provided a very confusing example code. – Rob Napier May 13 '14 at 18:48
  • @RobNapier I don't see why do you think this should be a defect, the code works as specified. – Marin Todorov May 13 '14 at 19:45
  • When you say "as specified," how do you mean? The extra `` isn't giving any type safety; it's just requiring a cast for the caller (and leading the caller to think that typesafety is happening). The main README doesn't explain what the protocol indicator is for, leading to this question. (This should be a chat; but I can't remember how to do that.) – Rob Napier May 13 '14 at 19:56
  • Let's try http://chat.stackoverflow.com/rooms/52621/jsonmodel for anyone interested in this. I'm very curious what JSONModel is trying to achieve. – Rob Napier May 13 '14 at 20:01
  • @RobNapier so what conclusions were drawn from the chat that happened on that fine day? I am atm doing what Marin Todorov is doing in the hope that I cannot insert an object that does not conform to the protocol that the array adheres to. – Pavan Jan 16 '15 at 19:02
  • If you want an array that can only insert certain types, create another object that HAS-A NSMutableArray, and add the type-specific methods you want (`addMyType:` or whatever). You can't make `NSMutableArray` be type-specific. – Rob Napier Jan 16 '15 at 19:15

1 Answers1

5
NSMutableArray<MyObject>*

This does not mean what you think this means. This is not "an NSMutableArray of things that conform to <MyObject>." This is "a subclass of NSMutableArray that itself conforms to <MyObject>."

I have no idea what the link you provided is trying to achieve. Maybe they subclassed NSArray, or perhaps they've decorated NSArray with a category that tries to conform to the protocol. In either case, that's between a little dangerous and insane. I would talk to them about what they had in mind. My suspicion is that they're doing this as a decoration that appears to mean something and in fact means nothing. (That's not unheard of. Apple does it themselves with CFPropertyListRef, which appears to mean something but is in fact const void*, which can be quite surprising when you expect a warning that never comes.)

To the question of how to get rid of the warning, just get rid of the incorrect protocol decoration. It should be NSMutableArray*, not NSMutableArray<something>*.

BTW, this code gives you between zero and negligible benefit:

NSMutableArray<MyObject>* list = (id)[NSMutableArray new];

It gives you a tiny benefit in that a later call to list = someOtherKindOfList would give a warning, but that's an incredibly unusual operation (and 90% of the time you'll have to cast it anyway, so the warning will almost never catch real errors). Most notably, however, it will not throw a warning if you do [list addObject:someRandomType], which is the most common way to make a mistake here. So there's no point to the decoration.

Rob Napier
  • 286,113
  • 34
  • 456
  • 610