More convenient NSArray and NSDictionary access - objective-c

Note that this is merely an academic question.
In Ruby, you can access array and dictionary(hash) elements conveniently:
value = myHash['myKey']
In Objective C, you need a method call:
value = [myDict objectForKey:#"myKey"];
How might one override some type of brackets or define a macro to bring the Objective C syntax closer to Ruby's?

Just an update:
Starting with iOS 6 I guess, you CAN use such a syntax:
value = dictionary[#"key"];
This is equivalent to
value = [dictionary objectForKey:#"key"];
Moreover, if we're talking about NSMutableDictionary, you can add new objects into a dictionary like this:
NSMutableDictionary *dictionary = [[NSMutableDictionary alloc]init];
dictionary[#"a"] = #"A";
NSLog(#"%#",dictionary[#"a"]);

What you are trying to do requires a language feature called "operator overloading". Objective-C does not allow for operator overloading because the designers of the language felt that operator overloading was harmful more often than it was helpful.
C++ does allow for operator overloading, so one way to get the syntax you want is to wrap your collections in C++ classes and use those instead. To switch to Objective-C++, just change your implementation files' extensions from .m to .mm.
Personally, I would recommend against using C++ wrappers around collections because it will make your code harder for other Objective-C programmers to read and it will break some of the more advanced features of Xcode. For example, you will no longer be able to use the refactor tools, because Xcode will not be able to parse your code correctly.

The other answers have told you why you can't do it - or how to work around it, but Objective-C is a verbose language - and using descriptive names is part of the pleasure of the language. Sure, you are typing a few more letters, but with code completion it's hardly any slower to write and you can see exactly what you are doing.

Switch to Objective-C++, define C++ wrapper classes for NSDictionary and NSMutableDictionary, and override operator, the array subscript operator.

Related

What does this Objective-C code snippet mean, and what document details it?

Ok, so I've done searches in Xcode, on Apple's developer's site, and on google, and have even downloaded and searched pdf versions of the Key-Value Coding Programming Guide and Collections Programming Topics, but I cannot find this syntax listed anywhere. What does the second line of the following snippet do, and where can I find the details on it?
NSMutableDictionary *change = [NSMutableDictionary new];
change[#(someVariable)] = #(someOtherVariable);
I don't know if I'm having a brain fart, or if I've actually never seen this before, but it really bugs me that I can't find documentation for it.
This is the new syntax introduced in Objective C relatively recently. It is documented at this link.
Scroll down to Object Subscripting syntax for an explanation:
Objective-C object pointer values can now be used with C’s subscripting operator.
Your code fragment translates as
[change setObject:#(someOtherVariable) forKeyedSubscript:#(someVariable)];
To support the new syntax described there, the Objective-C #-expression grammar has been introduced. The #-expression is explained at the bottom of the document.
http://clang.llvm.org/docs/ObjectiveCLiterals.html
Check out "examples" about half way through the doc
There are actually two things going on here:
Dictionary (and array) subscripting
change[key]
This is a new syntactic sugar for
[change objectForKey:key]
Or, if used as an lvalue, it is syntactic sugar for
[change setObject:value forKey:key]
For what's really going on here (objectForKeyedSubscript: and setObject:forKeyedSubscript:) see http://www.apeth.com/iOSBook/ch10.html#_nsdictionary_and_nsmutabledictionary
Number literals
#(someVariable)
This is a new compiler directive, equivalent to:
[NSNumber numberWithInt: someVariable]
Except that in fact it will use numberWithInt:, numberWithFloat:, or whatever is appropriate based on the type of someVariable.
Again, see http://www.apeth.com/iOSBook/ch10.html#_nsnumber

Should I prefer to use literal syntax or constructors for creating dictionaries and arrays?

I am reading through the iOS Developer Guide to get familiarized with the Objective-C language and currently I am having a little confusion on the topic of Container Literals and Subscript Notation as it pertains to creating objects like NSDictionary.
I understand that there are several ways to create NSDictionary objects including Key-Value encoding (dictionaryWithObjects:forKeys: and dictionaryWithObjectsAndKeys:, or their corresponding initializers). Source Link.
From my understanding there are two main ways to do this and then there is another way which is by using container literals, demonstrated here:
NSDictionary *myDictionary = #{
#"name" : NSUserName(),
#"date" : [NSDate date],
#"processInfo" : [NSProcessInfo processInfo]
};
Which is the best way to use? Is there any benefit in using the Container Literal technique over the previous two or is it just a convenience thing for programmers?
I am under the impression that it is also just another easier way to code things like arrays. Is this true or is there something that I'm missing here? Are these techniques just a matter of personal preference?
I disagree with the other answers posted thus far: almost all the time, it's better to use the new container literal syntax than to use constructors. They help with code correctness, and there's not really that much to worry about for compatibility.
Code Correctness
Container literals are indeed syntactic sugar, but specifically they map to the "safe" constructor methods +[NSArray arrayWithObjects:count:] and +NSDictionary dictionaryWithObjects:forKeys:count:. Constructing an array or dictionary using one of these methods directly isn't all that convenient, so many programmers find it simpler to use arrayWithObjects: and dictionaryWithObjectsAndKeys:. However, the latter methods have a nasty pitfall: since the argument list must be terminated with nil, you can find yourself with unexpected array/dictionary contents if you pass nil where you intend to pass an object.
For example, say you're setting up a dictionary mapping the properties of one of your model objects (maybe you're going to send it as JSON?):
NSDictionary *dictionary = [NSDictionary dictionaryWithObjectsAndKeys:
person.name, #"name", person.title, #"title", person.address, #"address",
nil];
If this code runs into a Person for whom no title has been set, the resulting dictionary will be missing the #"address"key and its value. You could spend hours tracking down why some fraction of the people in your database are missing addresses (and even see the code above and tear your hair out wondering why it's not working when c'mon, I'm setting it right there!). Many of us have.
By contrast, if you use the literal form like this:
NSDictionary *dictionary = #{
#"name": person.name, #"title": person.title, #"address": person.address };
It will be expanded to something like this:
id objects[] = { person.name, person.title, person.address };
id keys[] = { #"name", #"title", #"address" };
NSUInteger count = sizeof(objects) / sizeof(keys);
NSDictionary *dictionary = [NSDictionary dictionaryWithObjects:objects
forKeys:keys
count:count];
And if person.name or person.title returns nil, this method will throw an exception instead of silently creating data you don't want. (Either way you'll have to decide how you want your code to handle nil titles, but this way you'll catch the problem sooner.) And sure, you could write this "safer" form yourself instead of using the equivalent syntactic sugar, but are you sure you won't just fall back on the habit of writing dictionaryWithObjectsAndKeys: because it's shorter?
Compatibility
The code generated by container literals (and number literals and boxed expressions, for that matter) uses no new API, so you can compile it with Xcode 4.4 or newer (or Clang 3.1 or newer directly) and deploy to any version of Foundation. You do need to consider compatibility if your source code will also be used with older compilers or GNUStep, however. (Though it sounds like GNUStep is good with Clang now, too.)
And it's not part of the question, but since it's on a related subject: the same is "sort of" true for the new object subscripting syntax. That does use new methods only defined on Mac OS X 10.6 and iOS 6.0... but those methods are provided by libarclite. (You know, the library that gets linked in when you try to deploy ARC code back to iOS 4.3 or Mac OS X 10.6 -- it's not just for ARC anymore!) So all you need to do is declare them in a header, link ARCLite if you're not already, and you're good to go.
There's no "best way". Use whichever is the best for a particular use case. For example, if you want your app to be portable (i. e. the logic that requires Foundation only and not UIKit can run on other platforms as well, like Mac OS X or Linux with GNUstep, etc.) then avoid using the literal syntax - they're not very portable. If you need it to work on iOS only, then use them, because they're convenient.
Also, these notations are only syntactic sugar - that is, they map to method names (as far as I know, exactly to the two methods you mentioned in your question), so they don't have any effect on performance, the behavior of the algorithm, etc.
And yes, you guessed it right: the same applies to the new subscripting syntax - for NSArray, it invokes - objectAtSubscriptedIndex:.
You can use them on GNU/Linux with GNUstep and clang. In most of my cases GNUstep works with clang much better than all versions of gcc. (Sorry I should just edit the other answer, I am new to this)

Use of Pointers in Objective-C [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
what is the point of pointers in objective language
I am confused as to when and why pointers are used in Obj-C code. I am new to Obj-C and have a good grounding in C++ from an intro course at my university.
NSDate *now = [NSDate date];
Why is a pointer used here (and what exactly is its purpose?), and not here...
NSUInteger arrayLength = [<some array> count];
I am much more comfortable with the second example, but the first is still puzzles me.
It's the wording of the typedefs of Apple which are confusing.
NSUInteger
is just a fancy typedef for unsigned int; therefore it's a scalar type and not an object; you don't need a pointer to it in general for such a simple use case.
However,
NSDate
is a Foundation class; it means that its instances are proper Objective-C objects. As you probably know, Objective-C is a fully dynamic language: no static instances of classes are permitted, so every object is essentially a pointer (well, rather the allocated memory behind the pointer). So when you work with Objective-C objects, you always need a pointer to them.
Well, there are a few fundamental differences between Objective-C and C++. In Objective-C, there is actually a "generic object" (type "id"), and you can pass objects around without worrying about classes.
One of the implementation details that makes this possible is that Objective-C doesn't have "static" objects; all objects are created through the equivalent of "new" and are accessed through a pointer (string literals might be different, but they are still of type "NSString*"). It's just the way it is in Objective-C; you simply cannot have an "NSString MyString".
Because of this, the whole "objects are just objects and the compiler doesn't actually what you're dealing with" is possible because all objects are just simple pointers -- they are all the same size. The compiler can pass them around without knowing what they are, you can store them in containers without the containers knowing what they are etc.
Objective-C and C++ may both be "object-oriented" extensions of C, but they are quite different nonetheless.
EDIT: you can write stuff like "NSString* MyString" so the compiler knows what kind of object it is dealing with, but that's just convenience: you can still put other objects into that pointer (and, in fact, since the "new" equivalent usually returns id, one of the more common mistakes that I make is to "new" a different class from what the pointer says)
On the positive side, the compiler will warn you if you assign e.g. an NSWindow* to MyString, and it will also warn you if you call "open" on MyString. However, this is just an added benefit from the compiler; you could just as well declare everything as "id", or cast away the warnings.

Template in Objective C?

Everything is in the title :)
Is there any templates in ObjC ?
I need equivalent of c# :
public class MyClass<T> : Message
in ObjC .
Any helps will be strongly thanks :(
There is no such ObjC feature. While ObjC++ does exist, I strongly discourage its broad use. It has many problems from poor tool and debugger support, to poor compiler optimization, to degraded ARC performance.
Generally templates are not required in ObjC because it is not a strongly typed language. An NSArray can hold any object, so you don't need to use a template to get the right type. Do you have a specific problem you're trying to solve? There is likely a better ObjC solution.
Obj-C supports templates since Xcode v7. It is named generics:
Lightweight generics now allow you to specify type information for
collection classes such as NSArray, NSSet, and NSDictionary. The type
information improves Swift access when you bridge from Objective-C,
and simplifies the code you have to write. For example:
NSArray<UIImage *> *images;
NSDictionary<NSString *, NSURL *> *resourcesByName;
Look for "Objective-C Language Changes" section in
https://developer.apple.com/library/content/documentation/Xcode/Conceptual/RN-Xcode-Archive/Chapters/xc7_release_notes.html
By the way, Xcode supports adding C++ classes through the New->File. Using the extern "C" {} construct in C++ means you can provide as much or as little C-callable interface as you need, which you can then call directly from your Objective-C code, since Objective-C is a superset of C.
Having said that, it's probably a good idea to stick within the Objective-C paradigm unless you have a pressing reason to move outside it, such as the need to incorporate a body of existing C++ code into your project. (That's not to say that Objective-C is a "better" language, which is a different matter entirely.)

cannot convert 'b2PolygonShape' to 'objc_object*' in argument passing

I am not sure if many of you are familiar with the box2d physics engine, but I am using it within cocos2d and objective c.
This more or less could be a general objective-c question though, I am performing this:
NSMutableArray *allShapes = [[NSMutableArray array] retain];
b2PolygonShape shape;
..
..
[allShapes addObject:shape];
and receiving this error on the addObject definition on build:
cannot convert 'b2PolygonShape' to 'objc_object*' in argument passing
So more or less I guess I want to know how to add a b2PolygonShape to a mutable array. b2PolygonShape appears to just be a class, not a struct or anything like that. The closest thing I could find on google to which I think could do this is described as 'encapsulating the b2PolygonShape as an NSObject and then add that to the array', but not sure the best way to do this, however I would have thought this object should add using addObject, as some of my other instantiated class objects add to arrays fine.
Is this all because b2PolygonShape does not inherit NSObject at it's root?
Thanks
b2PolygonShape is a C++ class, not an ObjC class. You can only put ObjC instances into "NS-containers".
Since you need C++ anyway, it's better to use a std::vector<b2PolygonShape>.
NS-container classes can (as KennyTM pointed out) only store NSObjects. This can be a bit of a pain sometimes. But there are plenty of alternatives to NS-containers.
You can write Objective-C wrapper classes (or use NSValue), and store these in an NSArray.
You could use a plain old C array (though, that may not serve your needs, if the array size is undefined and shrinks and grows)
You could use a hash table to store your references.
A linked list of structs can also come in handy, and is fairly easy to create and maintain.
Should you decide to stick to std::vector, which is as good a solution as any, you can read more about that at: http://www.cplusplus.com/reference/stl/vector/