As per subject, how can I check whether an object is an NSArray or NSDictionary?
if([obj isKindOfClass:[NSArray class]]){
//Is array
}else if([obj isKindOfClass:[NSDictionary class]]){
//is dictionary
}else{
//is something else
}
Try
[myObject isKindOfClass:[NSArray class]]
and
[myObject isKindOfClass:[NSDictionary class]]
Both of these should return BOOL values. This is basic use of the NSObject method:
-(BOOL)isKindOfClass:(Class)aClass
For a bit more information, see this answer here:
In Objective-C, how do I test the object type?
Consider the case when you're parsing data from a JSON or XML response. Depending on the parsing library you are using, you may not end up with NSArrays or NSDictionaries. Instead you may have __NSCFArray or __NSCFDictionary.
In that case, the best way to check whether you have an array or a dictionary is to check whether it responds to a selector that only an array or dictionary would respond to:
if([unknownObject respondsToSelector:#selector(lastObject)]){
// You can treat unknownObject as an NSArray
}else if([unknownObject respondsToSelector:#selector(allKeys)]){
// You can treat unknown Object as an NSDictionary
}
Just in case anyone comes late to this party looking for a Swift equivalent, here you go. It's a lot more elegant than the Objective-C version, IMHO, because not only does it check the types, but it casts them to the desired type at the same time:
if let arrayVersion = obj as? NSArray {
// arrayVersion is guaranteed to be a non-`nil` NSArray
} else if let dictionaryVersion = obj as? NSDictionary {
// dictionaryVersion is guaranteed to be a non-`nil` NSDictionary
} else {
// it's neither
}
Related
I have the following bit of code where I'm getting a response from the server and trying to parse out error messages.
I notice that on occasion the message object isn't returning as type NSDictionary and will crash the application. I'm wondering what the best practice is to protect against that? In general I try to avoid doing instanceof checks. Likewise has selector checks. It feels like there should be a better way to do this than explicitly check I'm allowed to be using those methods / getting back type that I expect.
NSDictionary *message = [serverErrorJSON objectForKey:#"message"];
if (message != nil) {
return [message objectForKey:#"form"];
}
if ([serverErrorJSON isKindOfClass:NSDictionary.class]) {
return serverErrorJSON[#"message"][#"form"];
}
return nil;
Its good to use the literal syntax both syntactically and programatically.
You don't have to chain them together either, you might want to use another property of the JSON,
if ([serverErrorJSON isKindOfClass:NSDictionary.class]) {
NSDictionary *message = serverErrorJSON[#"message"];
//...
return message[#"form"];
}
return nil;
Your code:
NSDictionary *message = [serverErrorJSON objectForKey:#"message"];
if (message != nil) {
return [message objectForKey:#"form"];
}
The reason you are getting "unrecognized selector" here is that [serverErrorJSON objectForKey:#"message"] is not returning an NSDictionary as you expect. Since you are calling objectForKey: on that object, the recommended way to handle this is to wrap that call with respondsToSelector: :
id message = nil;
if ([serverErrorJSON respondsToSelector:#selector(objectForKey:)]){
message = [serverErrorJSON objectForKey:#"message"];
if ([message respondsToSelector:#selector(objectForKey:)]){
return [message objectForKey:#"form"];
}
}
This tests for the presence of the selector (method) you are calling, and is safer and more compatible than using isKindOfClass: and the like. It's always better to test for capabilities rather than class names, etc. You don't care if the object is an NSDictionary, you care if it can provide an object for a key using the method signature you are invoking.
The best way to protect against unrecognized selector errors is to check respondsToSelector or isKindOfClass depending on your use case.
Unfortunately your code can get pretty cluttered if you find yourself needing to verify that an object is a dictionary frequently, which can occur in your situation like yours with nested dictionaries in the data structure.
You can clean things up by adding a category:
#interface NSDictionary (Safe)
//Returns objectForKey if dictionary param is valid, else returns nil
+ (id) _safeObjectForKey: (NSString*) key
dict: (NSDictionary*) dictionary;
#end
#implementation NSDictionary (Safe)
+ (id) _safeObjectForKey:(NSString *)key
dict:(NSDictionary *)dictionary {
if ([dictionary isKindOfClass:[NSDictionary class]]) {
return [dictionary objectForKey:key];
}
return nil;
}
#end
and then to use it, given your example:
NSDictionary *message = [NSDictionary _safeObjectForKey: #"message"
dict: serverErrorJSON];
return [NSDictionary _safeObjectForKey:#"form"
dict:message];
You can do something similar for other common unrecognized selector error generators as well, like NSArray's objectAtIndex etc.
This is probably a long shot, but I've got objects with a lot of properties. The values of these objects are populated from NSDictionary's created from a database request. Because of this, there may be NSNull values contained in those NSDictionaries that will automatically get assigned to the properties. I need the properties to automatically discard values/objects that aren't of the correct type. Currently I do it like this:
- (void) setViewID:(NSString *)viewID{
if (!viewID || [viewID isKindOfClass:[NSString class]]) _viewID = viewID;
}
But that ends up being a lot of extra code when I've got 30-50 properties. Is there a way to synthesize this behavior? It seems like it would be a common enough requirement, but I can't seem to find a way to do it aside from writing it all out.
Why not check for NSNull when you are going through the dictionary? E.g.
for (NSString *key in dictionary) {
id value = [dictionary objectForKey:key];
if (value == [NSNull null]) {
value = nil;
}
[self setValue:value forKey:key];
}
I've a NSDictionary that contain non omogeneus stuff. I need to understand what types of memebers there are into.
With the [dict description] I understand the values into, but not the type.
There is a way to do that?
Thanks
You can ask each object for it's class (type) and then check if it's the type you want, using NSObject's -isKindOfClass: method. Note that if your object is, say, an NSMutableArray this would return true for [myMutableArray isKindOfClass:[NSArray class]]
Example:
id object = [myDict objectForKey:aKey];
if ([object isKindOfClass:[NSString class]])
// It's an NSString!
Source: developer.apple.com
In objective C, what is a better way of doing this:
if ([response class] == [nil class])
response is either a NSDictionary or NSMutableDictionary
The code is working but I'm getting a "Invalid receiver type 'void *' or "comparison of distinct Objective-C types 'Class' and 'struct NSMutableDictionary *' lacks a cast" warning messages
Thanks
If you're actually looking to test [response class], instead of the value of response itself, you'll want to use
if ([response isKindOfClass:[NSNull class])
If you're looking to check if response itself is nil, I describe a nice way of doing this in this answer to a similar question.
An object's class can't be nil unless you've botched some runtime swizzling. All valid objects must be instances of a valid class. Are you trying to do something like the following?
if (!response) {
// 'response' is nil
} else if ([response isKindOfClass:[NSMutableDictionary class]]) {
// response is an NSMutableDictionary
} else if ([response isKindOfClass:[NSDictionary class]]) {
// response is an NSDictionary
// (or an NSMutableDictionary if you remove the above 'if')
}
Since you mentioned either NSDictionary or NSMutableDictionary and appear to be testing for an instances kind...
isKindOfClass: will identify whether or not the receiver is an instance of the class specified. This includes subclasses.
Note that you cannot use this to determine if a dictionary is mutable or immutable, though, as dictionaries are instances of NSCFDictionary which is a subclass of `NSMutableDictionary.
This is very much on purpose.
I'm parsing some input which produces a tree structure containing NSDictionary instances on the branches and NSString instance at the nodes.
After parsing, the whole structure should be immutable. I feel like I'm jumping through hoops to create the structure and then make sure it's immutable when it's returned from my method.
We can probably all relate to the input I'm parsing, since it's a query string from a URL. In a string like this:
a=foo&b=bar&a=zip
We expect a structure like this:
NSDictionary {
"a" => NSDictionary {
0 => "foo",
1 => "zip"
},
"b" => "bar"
}
I'm keeping it just two-dimensional in this example for brevity, though in the real-world we sometimes see var[key1][key2]=value&var[key1][key3]=value2 type structures. The code hasn't evolved that far just yet.
Currently I do this:
- (NSDictionary *)parseQuery:(NSString *)queryString {
NSMutableDictionary *params = [NSMutableDictionary dictionary];
NSArray *pairs = [queryString componentsSeparatedByString:#"&"];
for (NSString *pair in pairs) {
NSRange eqRange = [pair rangeOfString:#"="];
NSString *key;
id value;
// If the parameter is a key without a specified value
if (eqRange.location == NSNotFound) {
key = [pair stringByReplacingPercentEscapesUsingEncoding:NSASCIIStringEncoding];
value = #"";
} else {
// Else determine both key and value
key = [[pair substringToIndex:eqRange.location] stringByReplacingPercentEscapesUsingEncoding:NSASCIIStringEncoding];
if ([pair length] > eqRange.location + 1) {
value = [[pair substringFromIndex:eqRange.location + 1] stringByReplacingPercentEscapesUsingEncoding:NSASCIIStringEncoding];
} else {
value = #"";
}
}
// Parameter already exists, it must be a dictionary
if (nil != [params objectForKey:key]) {
id existingValue = [params objectForKey:key];
if (![existingValue isKindOfClass:[NSDictionary class]]) {
value = [NSDictionary dictionaryWithObjectsAndKeys:existingValue, [NSNumber numberWithInt:0], value, [NSNumber numberWithInt:1], nil];
} else {
// FIXME: There must be a more elegant way to build a nested dictionary where the end result is immutable?
NSMutableDictionary *newValue = [NSMutableDictionary dictionaryWithDictionary:existingValue];
[newValue setObject:value forKey:[NSNumber numberWithInt:[newValue count]]];
value = [NSDictionary dictionaryWithDictionary:newValue];
}
}
[params setObject:value forKey:key];
}
return [NSDictionary dictionaryWithDictionary:params];
}
If you look at the bit where I've added FIXME it feels awfully clumsy, pulling out the existing dictionary, creating an immutable version of it, adding the new value, then creating an immutable dictionary from that to set back in place. Expensive and unnecessary?
I'm not sure if there are any Cocoa-specific design patterns I can follow here?
Expensive and unnecessary?
Yes. Apple's Cocoa APIs regularly say they return an immutable object, but actually return a mutable subclass that's been cast to the immutable version. This is a standard operating procedure and an accepted Cocoa design principle. You just trust that your clients aren't going to cast it back to a mutable version and change things from underneath you.
From Cocoa Core Competencies: Object Mutability:
Receiving Mutable Objects
When you call a method and receive an object in return, the object could be mutable even if the method’s return type characterizes it as immutable. There is nothing to prevent a class from declaring a method to return an immutable object but returning a mutable object in its implementation. Although you could use introspection to determine whether a received object is actually mutable or immutable, you shouldn’t. Always use the return type of an object to judge its mutability.
See also: Cocoa Fundamentals Guide: Cocoa Objects.