Is there a literal syntax for mutable collections?
Asked Answered
T

5

58

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?

Tedda answered 14/9, 2012 at 1:22 Comment(1)
Just don't forget that its NSDictionary *dictionary = @{@"key" : @"value"};, might be confusing with he way you have it written. Different from :objectsWithKeys.Riles
P
19

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

Phytography answered 14/9, 2012 at 1:36 Comment(8)
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.Neogothic
@JoshCaswell: Does python even have immutable collections?Phytography
Yes, there's things called "tuples" which are immutable. > (1, 2, 3) # tuple (immutable array) > [1, 2, 3] # list (mutable array)Neogothic
as posted below you do the following NSMutableArray *list = [@[] mutableCopy]; i.e. you add mutableCopy at the end. That is how the literal is specifiedTocology
@Tocology That's not a literal. That's an expression that uses a literal.Phytography
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.Tocology
@Tocology 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.Phytography
@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.Sequential
T
105

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

NSMutableArray *array = [@[ @"1", @"2", @"3" ] mutableCopy];
Tramroad answered 14/9, 2012 at 1:39 Comment(9)
This seems less efficient and not much shorter than [NSMutableArray arrayWithObjects:@"1", @"2", @"3", nil].Tedda
Or alternatively: "NSMutableArray *array = [NSMutableArray arrayWithArray:@[ @"1", @"2", @"3" ]];" - though I like your example better :)Carroll
There is a builtin way in NSJSONSerialization.Manganate
@Manganate that is definitely not a literal syntax.Tramroad
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.Rouge
@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.Tramroad
@Tramroad 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.Rouge
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.Blackmun
You can also do NSMutableArray *array = @[].mutableCopy; which seems more readable.Sofko
P
19

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

Phytography answered 14/9, 2012 at 1:36 Comment(8)
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.Neogothic
@JoshCaswell: Does python even have immutable collections?Phytography
Yes, there's things called "tuples" which are immutable. > (1, 2, 3) # tuple (immutable array) > [1, 2, 3] # list (mutable array)Neogothic
as posted below you do the following NSMutableArray *list = [@[] mutableCopy]; i.e. you add mutableCopy at the end. That is how the literal is specifiedTocology
@Tocology That's not a literal. That's an expression that uses a literal.Phytography
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.Tocology
@Tocology 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.Phytography
@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.Sequential
I
18

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

No. Best alternative:

[@[ @"foo", @"bar"] mutableCopy]
Inglebert answered 14/9, 2012 at 1:39 Comment(0)
C
9

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.

Chantell answered 3/8, 2015 at 5:37 Comment(3)
Do you know of any issues arising from using this in lieu of the longhand?Pledgee
@JohnnyRockex there are no issues with this syntax, but it's pretty ugly if the array is empty to start with ;)Saudra
I love me some shorthand was just wondering if had a (technical) effectPledgee
M
3

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.

Manganate answered 29/4, 2013 at 20:42 Comment(4)
Uh dude, JSONKit is faster. By 5x. Plus, this is too circuitous. Just use -mutableCopy, then you can optionally use -autorelease.Doane
@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'.Manganate
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.Morganatic
@Morganatic 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!Manganate

© 2022 - 2024 — McMap. All rights reserved.