Is there a literal syntax for mutable collections?

15,315

Solution 1

No. Just as how there isn't a syntax for creating an NSMutableString either. Mutable objects are not particularly suited to literal values.

Solution 2

There isn't a built in way, but I just usually use mutableCopy like this:

NSMutableArray *array = [@[ @"1", @"2", @"3" ] mutableCopy];

Solution 3

But, is there a literal syntax for creating an NSMutableArray or an NSMutableDictionary?

No. Best alternative:

[@[ @"foo", @"bar"] mutableCopy]

Solution 4

Yes. But not quite. Take a look at this;

NSMutableArray *list = [@[] mutableCopy];

This creates a non-mutable array @[] and calls mutableCopy which returns a NSMutableArray *. In place of @[], you can give any array literal.

Solution 5

If you have a nested literal of arrays and dictionaries, you can turn this into a fully mutable version by going through NSJSONSerialization. For example:

NSArray* array = @[ @{ @"call" : @{ @"devices" : @[ @"$(devices)" ] } } ];
NSData* data   = [NSJSONSerialization dataWithJSONObject:array 
                                                 options:0 
                                                   error:nil];

NSJSONReadingOptions options = NSJSONReadingMutableContainers | 
                               NSJSONReadingMutableLeaves;
NSMutableArray* mutableArray = [NSJSONSerialization JSONObjectWithData:data 
                                                               options:options
                                                                 error:nil];

It's a bit of a detour, but at least you don't have to write out the code yourself. And the good thing is that NSJSONSerialization is very fast.

Share:
15,315
ma11hew28
Author by

ma11hew28

Updated on June 15, 2022

Comments

  • ma11hew28
    ma11hew28 almost 2 years

    I know I can create an NSArray with @[@"foo", @"bar"] or an NSDictionary with @{@0 : @"foo", @1 : @"bar"}.

    Is there a literal syntax for creating an NSMutableArray or an NSMutableDictionary?

    • serge-k
      serge-k about 8 years
      Just don't forget that its NSDictionary *dictionary = @{@"key" : @"value"};, might be confusing with he way you have it written. Different from :objectsWithKeys.
  • jscs
    jscs over 11 years
    Have to disagree with that last sentence. Programming in Python, for example, collections are created literally and mutable by default. It can be very handy.
  • Lily Ballard
    Lily Ballard over 11 years
    @JoshCaswell: Does python even have immutable collections?
  • jscs
    jscs over 11 years
    Yes, there's things called "tuples" which are immutable. > (1, 2, 3) # tuple (immutable array) > [1, 2, 3] # list (mutable array)
  • ma11hew28
    ma11hew28 over 11 years
    This seems less efficient and not much shorter than [NSMutableArray arrayWithObjects:@"1", @"2", @"3", nil].
  • Marchy
    Marchy over 11 years
    Or alternatively: "NSMutableArray *array = [NSMutableArray arrayWithArray:@[ @"1", @"2", @"3" ]];" - though I like your example better :)
  • meaning-matters
    meaning-matters about 11 years
    There is a builtin way in NSJSONSerialization.
  • danielbeard
    danielbeard about 11 years
    @meaning-matters that is definitely not a literal syntax.
  • Nate Symer
    Nate Symer almost 11 years
    Uh dude, JSONKit is faster. By 5x. Plus, this is too circuitous. Just use -mutableCopy, then you can optionally use -autorelease.
  • meaning-matters
    meaning-matters almost 11 years
    @NathanielSymer Come on dude: The two year old JSONKit readme --well maintained stuff btw-- itself says it was just 25% - 40% faster. And -mutableCopy only does a shallow copy. The only way is to do something 'circuitous'.
  • Mark Amery
    Mark Amery almost 11 years
    Got to agree with @MattDiPasquale's comment; this is barely shorter than NSMutableArray arrayWithObjects:..., is presumably less efficient for what little it matters, and - to my eye - slightly less readable too. A concise literal syntax would've been nice, but if this is the nearest thing to it, then I think I'll stick to the less hacky-feeling arrayWithObjects for initialising mutable arrays.
  • danielbeard
    danielbeard almost 11 years
    @MarkAmery How is that less hacky? The literal syntax expands to +[NSArray arrayWithObjects:count:], not arrayWithObjects so the literal syntax validates that all items are non-nil.
  • Mark Amery
    Mark Amery almost 11 years
    @danielbeard Creating an unnecessary intermediate object and then taking a copy of it just to save a few characters compared to directly creating the NSMutableArray with one of its own initialiser methods is what feels hacky to me.
  • kritzikratzi
    kritzikratzi about 10 years
    you could also just do this: [[NSMutableArray alloc] initWithArray:@[@"A",@"B"]]. sorry for the downvote, but serializing and deserializing is insane and won't work with many types of objects.
  • meaning-matters
    meaning-matters about 10 years
    @kritzikratzi First, insane? You're taking a very simple example, not my example. Please write out @[ @{ @"call" : @{ @"devices" : @[ @"$(devices)" ] } } ] and you'll see how insane that is. Second, this works for the types given in @MattDiPasquale's and my example. Even more, I explicitly mention that this works for literals. So please don't apologise!
  • ecotax
    ecotax over 9 years
    As meaning-matters commented on his own NSJSONSerialization reply, mutableCopy only makes a shallow copy. That may be sufficient, but if not his NSJSONSerialization solution is the only general one so far.
  • Matt Mc
    Matt Mc over 9 years
    You can also do NSMutableArray *array = @[].mutableCopy; which seems more readable.
  • maninvan
    maninvan over 8 years
    as posted below you do the following NSMutableArray *list = [@[] mutableCopy]; i.e. you add mutableCopy at the end. That is how the literal is specified
  • Lily Ballard
    Lily Ballard over 8 years
    @maninvan That's not a literal. That's an expression that uses a literal.
  • maninvan
    maninvan over 8 years
    You are correct in semantics. But from what happens from the programming perspective is that the expression is how you initialize a mutable object with some data in a short form syntax. The compiler will optimize this so it's probably reduced cpu instructions and memory copies. And it's less to write. It's more succinct. Which is what is desired. The answer 'no' is technically correct but not as helpful as showing the expression.
  • Lily Ballard
    Lily Ballard over 8 years
    @maninvan No, the compiler does not optimize that. Obj-C does not allow the compiler to optimize that. It's required to construct an immutable array from the literal, and then invoke mutableCopy on the result. The expression [@[] mutableCopy] simply cannot be called a literal. Even if it was optimized, it's still not a literal.
  • Kevin
    Kevin about 8 years
    @KevinBallard You are correct, but I get his point. Using literal syntax and adding mutableCopy to the end looks better than most alternatives and is easy to type. It's not an answer to OP's question, but it can be a solution to OP's problem.
  • Johnny Rockex
    Johnny Rockex about 7 years
    Do you know of any issues arising from using this in lieu of the longhand?
  • Dan Rosenstark
    Dan Rosenstark over 2 years
    @JohnnyRockex there are no issues with this syntax, but it's pretty ugly if the array is empty to start with ;)
  • Johnny Rockex
    Johnny Rockex over 2 years
    I love me some shorthand was just wondering if had a (technical) effect