As mentioned @"age"
is a shortcut for creating an NSString *
- which again is a subclass of NSObject
. The @
in front of the string tells the compiler to create and return an NSString *
.
"@age"
on the other hand does not have the @
prefix, and therefore the compiler creates a const char *
which is what C uses to represent strings. Remember that Objective-C is a strict superset of C, which means that any C code will compile on an Objective-C compiler. This also means that the compiler needs to maintain backwards compatibility for C - which again means that "@age"
is a C string while @"age"
is an Objective-C Foundation Kit NSString object.
In regards to your question: The reason why this is not a compiler error, is because the initWithObjects:
initializer of NSArray does not specify the required type. It simply says a list of pointers. And because both @"age"
(NSString *
) is a pointer and the "@age"
(const char *
) is also a pointer, the compiler won't complain. Both are by the way the initWithObjects:
is defined allowed by the compiler.
Now you say why it is not a run-time error. EXC_BAD_ACCESS
IS a run-time error. You might mean why there is not an exception thrown, as there is a difference in exceptions and run-time errors. Exceptions are run-time errors also, though, but they can be detected and acted upon. Signals (which a EXC_BAD_ACCESS
is) can typically not be acted upon and the application is killed by the operating system.
The reason why it is a run-time error, is because the initWithObject:
are expecting a list of NSObjects
and the first thing this function does is to do some inspection or work on the objects provided. Now internally in the Objective-C run-time it is basically a C struct
with information about the objects methods and variables. These structs typically contains as an example a pointer to the super class of the object. What you are giving this method is basically garbage to it. When it tries to examine what it believes is a struct with pointers and data - all it gets is a four byte buffer ("age\0"
). So when it tries to — as an example dereference a super class pointer in what the method believes is a struct – it will read outside of that four byte buffer and therefore your application will receive a EXC_BAD_ACCESS
.
So there you have it. From a compiler stand point you are doing nothing wrong. From the runtime standpoint you are feeding it garbage, which it has no means of detecting. It just goes about working on the data as if it is what it expects. And when it does that, it goes outside the boundaries of the buffer you have provided and therefore gets a EXC_BAD_ACCESS
.
Hope this clarified your curiosity.