I am using SBJsonParser to parse JSON. An input can be 0 or a string (ex. a829d901093), and if it's zero, NSCFBoolean is returned, if its string NSCFString is returned. How can I tell which one is returned?
Thanks!
Calling these by their internal toll-free names is what makes this confusing. If you call them NSNumber and NSString (as they are listed in the documentation), then the answer is clear:
if ([value isKindOfClass:[NSNumber class]]) { ... }
EDIT: #Magnus points out that it isn't obvious that a NSCFBoolean isa NSNumber in order to look them up. That's true. To me it's very obvious because I know the Core Foundation type system and I know what the toll free bridge classes mean and how they're implemented (it's one of the coolest tricks in all of Cocoa IMO). But what if you didn't know those things? It's still no problem.
In the debugger, look in the variable list and expand the variable you care about. Its first "member" will be it superclass. Expand. Continue until you find a class you know.
Alternately, you can walk the superclasses using NSStringFromClass([object superclass]). Keep tacking superclass on for as many levels as you'd like to check.
Related
I am going through some walkthroughs fpr Objective-C and I got to many places where I raised my eyebrows. I would love to get them down.
Is there a fundamental difference in message sending and method calling? Objective-C lets me do both: object.message yields the same result as [object message]. I think maybe nested messages cannot be created using the dot operator strategy?
I created an NSArray object, now I am about to print results for this using an NSEnumerator:
id myObject = [object objectEnumerator];
in a while loop iterating and printing results. The type of myObject is id, which means it's resolved at runtime and not compile time. I know very clearly what kind of objects are stored in my NSArray—they are NSStrings—so by changing the type of myObject to
NSString * myObject, it works just fine. However, I experimented and found out that myObject can be of any type, be it NSString or NSArray or NSEnumerator, and any of these work just fine, perfectly iterating the NSArray object and yielding the same results.
What's up with that?
I'm not sure what kind of distinction you're trying to make between "message sending" and "method calling", since they're two ways of describing the same thing. The dot syntax is just a shortcut for calling getters and setters, that is:
[foo length]
foo.length
are exactly the same, as are:
[foo setLength:5]
foo.length = 5
You should generally only use the dot syntax when you're using getters and setters; use the square bracket syntax for all of your other method calls.
For your second question: this is how dynamic typing works. Any type declarations you put in your code are hints to the compiler; your Objective-C method calls will always work as long as the objects respond to them.
It's a distinction oriented at the person reading your code. Dot syntax indicates state (I'm accessing an ivar), method syntax indicates behavior (I'm performing some action). To the runtime, both are the same.
I think Apple's intention is to show accessors as an implementation detail you shouldn't worry about. Even when they could trigger side effects (due to some additional code in the accessor), they usually don't, so the abstraction is imperfect but worth it (IMHO). Another downside of using dot notation is that you don't really know if there is a struct or a union behind it (which unlike message sending, never trigger side effects when being assigned). Maybe Apple should have used something different from a dot. *shrugs*
I think maybe nested messages cannot be created using the dot operator strategy?
Dot notation can be used to nest calls, but consider the following:
shu.phyl.we.spaj.da
[[[[[shu]phyl]we]spaj]da]
In this case, the uglier, the better. Both are a code smell because one object is creating dependencies to another object far far away, but if use brackets to pass messages you get that extra horrible syntax from the second line, which makes the code smell easier to notice. Again, convention is to use dots for properties and brackets for methods.
1: Your terminology is incorrect. The dot operator is not "method calling", a different operation. It's just a different visual appearance for message sending. There's no difference between [x y] and x.y. The dot syntax can only take one argument though, as it's intended to be used only for property access.
2: The static (compile-time) type of an object has no effect on its behavior at runtime. Your object is still an NSEnumerator even if you're calling it something else.
1) They're both message sending, just different syntax. [object message] is traditional syntax, object.message is the "dot notation", but means exactly the same thing. You can do some kinds of nesting with dot notation, but you can't do anything with methods that take complex arguments. In general, old hand Obj-C programmers don't use dot notation except for simple accessor calls. IMHO.
2) The runtime is really smart and can figure it out on the fly. The type casting of pointers is really just a clue to the compiler to let you know when you messed up. It doesn't mean a thing (in this case) when the message is sent to the array to fetch a value.
Message sending is the preferred way of doing this. It's what the community uses and reinforces the concept of objects sending messages to one another which comes into play later when you get into working with selectors and asking an object if it responds to a selector (message).
id is basically a pointer to anything. It takes some getting used to but it's the basis for how Objective-C handles dynamic typing of objects. When NSLog() comes across the %# format specifier, it sends a description message to the object that should should replace the token (This is implemented in the superclass NSObject and can be overridden in the subclass to get the desired output).
In the future when you're doing this, you might find it easier to do something like this instead:
for (NSString *s in YourNSArrayInstance) //assuming they are NSStrings as you described
{
NSLog(#"%#", s);
}
Or even simply just:
for (NSString *s in YourNSArrayInstance) //assuming they are NSStrings as you described
NSLog(#"%#", s);
You'll learn to like message sending eventually.
I am just starting climbing the Objective C learning curve (using Nerd Ranch iOS programming book).
Based on what I have know from other languages about "nesting" multiple executions within one line I assumed that I can alter:
NSString* descriptionString = [[NSString alloc] initWithFormat:#"%#", possesionName]
with a two line version:
NSString* descriptionString = [NSString alloc];
[descriptionString initWithFormat:#"%#", possesionName]
but it seems that the second attempt raises an exception
2012-01-22 18:25:09.753 RandomPossessions[4183:707] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '*** -length only defined for abstract class. Define -[NSPlaceholderString length]!'
Could someone help me understand what exactly I am doing wrong here? Thanks a lot in advance.
PS. If this is a way Objective C messages work and you have to make alloc and init in one line just let me know - I assumed this is just a set of functions that either can be executed two in one go or one after another.
An important difference between both versions (they are not exactly equal) is that in the first version you use the result of initWithFormat for the variable descriptionString, while you use the result of alloc in the second. If you change your code to
NSString* descriptionString = [NSString alloc];
descriptionString = [descriptionString initWithFormat:#"%#", possesionName]
all should be well again. It is specified that an object returned by alloc shall not be seen as initialized and functional until some init Method has been called and init might return something else.
The alloc method will allocate memory for a new object. But the init method might throw away that memory and return a completely different object. Or it might return nil. This is why you must always do self = [super init] when you override an init method.
NSString is one class that does this kind of thing all the time.
I'm not exactly sure why the exception is happening, but I believe it could be ARC injecting code in between your two lines of code or something similar. Whatever it is, something is trying to act on the allocated object that has never been initialised, and this is a huge problem that can lead to all kinds of issues. Consider yourself lucky it threw an exception, sometimes it wont.
The NSString class might not actually be a real class. It may contain almost no methods and almost no variables. All it has is a bunch of factory methods to create "real" string objects of some other class, and this is done using methods like initWithFormat:. So, by long standing convention alloc/init must always be done in a single statement and there are a handful of places where, usually for performance reasons, something will rely on this convention being used.
Basically, objective-c is a language where you don't need to know exactly what is going on inside an object. You just need to know what messages can be sent to an object, and how it will respond. Anything else is undefined behaviour and even if you learn how it works, it is subject to change without notice. Sometimes the behaviour will change depending on circumstances that are completely illogical, for example you might expect the "copy" method to give you a copy of the object you send it to, and while this is the default behaviour, there are many cases where it will actually just return the same object with slightly different memory management flags. This is because the internal logic of the class knows that returning the same object is much faster and effectively identical to returning an actual copy.
My understanding is copy sent to NSString may return a new object, or it may return itself. It depends on which NSString subclass is actually being used, and there isn't even any documentation for what subclasses exist, let alone how they're implemented. All you need to know, is that copy will return a pointer to an object that is perfectly safe to treat as if it was a copy even though it might not be.
In a "proper" object oriented language like Objective-C, objects are "black boxes" which can intelligently change their internal behaviour at any time for any reason, but their external behaviour always remains the same.
With regard to avoiding nesting... The coding style for Objective-C often does require extensive nesting, or else you'll be writing 10 lines of code when only 1 is really needed. The square brace syntax is particularly suited to nesting without making your code messy.
As a rule of thumb, I turn on Xcode's "Page Guide at column" feature, and set it to 120 characters. If the line of code exceeds that width then I'll think about breaking it into multiple lines. But often it's cleaner to have a really long line than three short lines.
Be pragmatic about it. :)
From Apple's library reference, initWithFormat:
Returns an NSString object initialized by converting given data into Unicode characters using a given encoding.
So you can use these two lines of code:
NSString* descriptionString = [NSString alloc];
descriptionString = [descriptionString initWithFormat:#"%#", possesionName];
For more info please go to:
https://developer.apple.com/library/mac/documentation/Cocoa/Reference/Foundation/Classes/NSString_Class/Reference/NSString.html#//apple_ref/occ/instm/NSString/initWithFormat:
I'm writing a generic 'attribute/key editor' view class on iOS, and it checks the type of the editing key using [objectForKey isKindOfClass:[NSDate class]], for example. I just ran into a wall when I realized that will fail if objectForKey is nil. Is there a way to get the class/return type for a generic Objective-C property, even if said property is nil? I know about method_getReturnType in the Objective-C run-time, but that sounds like overkill for what I need.
You can’t. Although return type information for methods is available, the return type encoding for methods which return objects is simply #, meaning “object reference”.
What you're asking for doesn't make sense.
Remember that a name alone does not identify a method. Objects respond to those messages (or not); a method does not exist alone, only as part of an object (or class).
Having no object, you cannot tell from it what hypothetically sending a message to an object would return.
ETA: How is it that you could be editing the attributes of something, but not have the object to edit in order to examine its properties? It seems like you have a bug somewhere else.
I know about method_getReturnType in the Objective-C run-time, but that sounds like overkill for what I need.
There are two ways. If you want to support informal properties (KVC-compliant accessor methods with no #property declaration), that's exactly what you need. If you only care about formal properties (#property), use the property_getAttributes function.
Can't you just first check to make sure that objectForKey != nil, and the continue with the isKindOfClass checking? If you make sure that the object doesn't equal nil first you can easily check or safely exit without any failures.
I don't know where your data is coming from, but you might want to consider supplanting nil with NSNull and that will allow you to gain NSObject-like properties on something that is technically null
But the null check becomes more pain in the ass.
It goes from object != nil to
(NSNull *)object != [NSNull null]
I want to ask a question about the objective C. When I study the library from the apple developer website. I always see that there are some subclass called "mutable". For example, the NSArray and NSMutableArray. What does it mean about this word. Are there some special meaning? Can anyone tell me? Thank you.
It means you can change its values. If you look at the NSMutableArray docs, you'll see it defines extra methods like -addObject:. NSArray by itself doesn't have these (and can thus be more efficient / take less memory in implementation).
Also note, if you call [myMutableArray copy] you'll get a non-mutable copy of it (which you must later release0. And similarly there's -mutableCopy.
Mutable means you can change it. Look at the difference between addObject in NSMutableArray and arrayByAddingObject in NSArray.
From the Objective-C Beginner's Guide it states the answer to your specific question:
There are two kinds of arrays (and of
usually most data oriented Foundation
classes) NSArray and NSMutableArray.
As the name suggests, Mutable is
changable, NSArray then is not. This
means you can make an NSArray but once
you have you can't change the length.
This tech note also implies you can change the length of a mutable array after the array has been created.
In general mutability stems from these meanings. This will help provide a more broad understanding for when you encounter it elsewhere.
I have an object called Settings that inherits from NSMutableDictionary. When I try to initialize this object using
Settings *settings = [[Settings alloc] initWithContentsOfFile: #"someFile"]
it returns an object of type NSCFDictionary. As a result, it doesn't recognize my additional methods. For example, when I call the selector "save", it objects:
[NSCFDictionary save]: unrecognized selector sent to instance 0x524bc0
Of course, it's OK when I initialize using the garden variety
Settings *settings = [[Settings alloc] init]
I tried to cast it again to Settings but that didn't work. This seems really simple - what am I missing?
Thanks
NSDictionary is a class cluster. This means that the value returned from its init methods is not strictly an NSDictionary, but a subclass that implements the actual functionality. In almost every case, it is better to give your class an NSDictionary as an instance variable or to simply define a category on NSDictionary.
Chuck is correct about NSDictionary (and Dave, by extension, about NSArray/Set/String) and class clusters. Odds are that -[NSDictionary initWithContentsOfFile:] calls down to a different initializer than -init does, which is why it swaps out your allocated Settings instance for another subclass of NSMutableDictionary. (The initialization action when reading from a file may select a particular known subclass of NSDictionary which performs well for loading from a file, etc.)
I'll echo Chuck's guidance that it is almost always better to use composition or categories than inheritance for an NSDictionary. It's highly likely that you could accomplish what you're doing with categories in a much simpler way, and expose yourself to fewer potential bugs in the process. Consider yourself warned before deciding to subclass.
That being said, both NSDictionary and NSMutableDictionary have been designed to support subclassing, and on rare occasions that's the right thing to do. Think long and hard about it before trying it. If you find it's the right choice for your design, here are some key points to know and do as needed:
Override the following primitive methods from NSDictionary:
-count
-objectForKey:
-keyEnumerator
-initWithObjects:forKeys:count: (designated initializer)
Override the following primitive methods from NSMutableDictionary:
-setObject:forKey:
-removeObjectForKey:
If you're supporting NSCoding, be aware of classForKeyedArchiver and replacementObjectForKeyedArchiver: (both instance methods from NSObject) — they can totally change how your class responds, and you often unintentionally inherit some odd behavior from NS(Mutable)Dictionary. (You can verify if they are the culprit by setting a breakpoint on them, or implementing them to call super and breaking on your own code.)
I've implemented a number of these points in an NSMutableDictionary subclass of my own. You can check it out and use the code however may be helpful to you. One that particularly helped me (and could be the solution for your problem) was overloading the designated initializer, which is currently undocumented (Radar #7046209).
The thing to remember is that even though these bullets cover most common uses, there are always edge cases and less common functionality to account for. For example, -isEqual: and -hash for testing equality, etc.
If you actually read the spec for NSDictionary (a rash action, I know) you'll find a section named "Subclassing Notes". In it you will read:
If you do need to subclass NSDictionary, you need to take into account
that is represented by a Class cluster—there are therefore several
primitive methods upon which the methods are conceptually based:
initWithObjects:forKeys:
count
objectForKey:
keyEnumerator
In a subclass, you must override all these methods.
From https://stackoverflow.com/a/1191351/467588, this is what I did to make a subclass of NSDictionary works. I just declare an NSDictionary as an instance variable of my class and add some more required methods. I don't know what to call them though.
I posted my code sample here https://stackoverflow.com/a/10993594/467588.
This question is very old, and since most of these answers were posted, Apple has introduced object subscripting, which allows you to make your own classes behave more like NSMutableArray or NSMutableDictionary. This is simpler than the alternatives discussed above.
At a minimum, you have to override these methods:
//Array-style
- (id)objectAtIndexedSubscript:(NSUInteger)idx;
- (void)setObject:(id)obj atIndexedSubscript:(NSUInteger)idx;
//Dictionary-style
- (id)objectForKeyedSubscript:(id <NSCopying>)key;
- (void)setObject:(id)obj forKeyedSubscript:(id <NSCopying>)key;
Here's a nice tutorial on how to do just that.