I have a for loop that iterates through dictionaries within a dictionary, trying to find one that has a key that matches a key from a completely separate dictionary.
for (id rDCKey in rootDictCopy)
{
tempHouseNumber = rDCKey;
if ([[[rootDictCopy objectForKey:rDCKey] objectForKey:#"RandomUniqueIdentifier"] isEqual:[[routePathRootDictCopy objectForKey:houseNumber] objectForKey:#"RandomUniqueIdentifier"]])
{
NSLog(#"done");
goto DONE;
}
}
When both values are equal to nothing, it's fine, and everything passes. But the moment they have a value (which is always a 256 character long NSString), it crashes, giving me this error:
Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[NSTaggedPointerString objectForKey:]: unrecognized selector sent to instance 0xa000000333939394'
I have no clue what's up, and any help would be appreciated.
I can give more code if necessary.
Thanks.
Update: I updated my for loop to check for types, but the same problem occurs.
Update 2: Changed || to &&
for (id rDCKey in rootDictCopy)
{
tempHouseNumber = rDCKey;
if ([[rootDictCopy objectForKey:rDCKey] isKindOfClass:[NSMutableDictionary class]] && [[routePathRootDictCopy objectForKey:houseNumber] isKindOfClass:[NSMutableDictionary class]])
{
if ([[[rootDictCopy objectForKey:rDCKey] objectForKey:#"RandomUniqueIdentifier"] isEqual:[[routePathRootDictCopy objectForKey:houseNumber] objectForKey:#"RandomUniqueIdentifier"]])
{
NSLog(#"done");
goto DONE;
}
}
else
{
NSLog(#"ERROR");
}
}
reason: '-[NSTaggedPointerString objectForKey:]: unrecognized
selector sent to instance 0xa000000333939394'
Exception occurred because you called objectForKey method with an object type NSTaggedPointerString
Before compare you should check type of your data.
You can do as below:
if ( [obj isKindOfClass:[NSDictionary class]] ) {
// is a NSDictionary
// do further action like get objectForKey, compare ..
} else {
// you don't got what you want -> print error log or something like that
}
And your code should be like below:
for (id rDCKey in rootDictCopy)
{
tempHouseNumber = rDCKey;
// TODO:
// check if rootDictCopy is a NSDictionary (if needed)
// check if routePathRootDictCopy is a NSDictionary (if needed)
// check if [rootDictCopy objectForKey:rDCKey] is a NSDictionary
// check if [routePathRootDictCopy objectForKey:houseNumber] is a NSDictionary
if ([[[rootDictCopy objectForKey:rDCKey] objectForKey:#"RandomUniqueIdentifier"] isEqual:[[routePathRootDictCopy objectForKey:houseNumber] objectForKey:#"RandomUniqueIdentifier"]])
{
NSLog(#"done");
goto DONE;
}
}
Note: My answer will help your code work without crash but your should find why you got unexpected object type here. And how to sure you alway recevied NSMutableDictionary object, that is the best solution!
As users Nhat Dinh, Amit Tandel and Larme suggested, some dictionaries within rootDictCopy had been transformed into an NSString earlier in the code. I fixed that, making those dictionaries remain dictionaries, and I no longer receive that error. Thanks for everyone's help!
Related
I am trying to use Microsoft Graph iOS SDK and followed the official code sample.
The following code snippet is to get basic profile of all users in the organization:
private func getContactInfo(){
self.graphClient.users().request().getWithCompletion{
(collection: MSCollection?, request:MSGraphUsersCollectionRequest?, error: NSError?) in
if let users = collection {
for user: MSGraphUser in users.value as! [MSGraphUser] {
print(user)
print(String(user.surname.dynamicType))
print(user.mobilePhone)
}
}
}
}
Output Result:
{
businessPhones = (
);
displayName = "Boss";
givenName = "Jack";
id = "30fb78ff-522f-45e7-a9cd-75ba8ee2eca6";
jobTitle = "<null>";
mail = "boss#abc.net";
mobilePhone = "<null>";
officeLocation = "<null>";
preferredLanguage = "<null>";
surname = "\U8a79";
userPrincipalName = "boss#abc.net";
}
ImplicitlyUnwrappedOptional<String>
And runtime exception happened
2016-06-05 17:02:55.302 ABC[76976:915052] -[NSNull _fastCStringContents:]: unrecognized selector sent to instance 0xb59398
2016-06-05 17:02:55.305 ABC[76976:915052] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[NSNull _fastCStringContents:]: unrecognized selector sent to instance 0xb59398'
*** First throw call stack:
(
0 CoreFoundation 0x0092c494 __exceptionPreprocess + 180
1 libobjc.A.dylib 0x02640e02 objc_exception_throw + 50
...
When I try to print the null value like mobilePhone, runtime exception occurred. How to detect null value to avoid crashing? Thank you.
Add: MSGraphUser.m snippet used in this case,
#interface MSGraphUser()
{
...
NSString* _mobilePhone;
...
- (NSString*) mobilePhone
{
return self.dictionary[#"mobilePhone"];
}
...
There must be a better swift support, but for now, you could extend the class like what Casey has said.
If you did this, you can check
if user.optMobilePhone is NSNull
The actual extension would look something like this:
extension MSGraphUser {
var optMobilePhone: AnyObject? {
return dictionaryFromItem()["mobilePhone"]
}
}
You can use one way to filter null objects
- (NSString* __nullable) mobilePhone
{
if ([self.dictionary isKindOfClass:[NSString class]])
{
return self.dictionary[#"mobilePhone"];
}
return nil;
}
or
- (NSString* __nullable) mobilePhone
{
if (![self.dictionary isKindOfClass:[NSNull class]]) {
return self.dictionary[#"mobilePhone"];
}
return nil;
}
Many JSON APIs will return null in the JSON document for values that they want to mark explicitely as not present. This is different from keys that will not be reported at all.
The first thing you do is check with the creator of the API or with the documentation how that kind of value should be interpreted. For example, if you ask for the key "user", you might find that the value isn't present at all, that the value is null, or that the value is an empty string. Find out how each value should be interpreted, or if they should be treated the same.
Then since you will need this all the time, you add a function to NSDictionary that will return what you want, and logs things that you didn't expect. You check that a value isn't there at all by checking with if let ... . You check whether a value is null by checking value == NSNull (). And then you make that function return either an optional string or a string.
It looks like mobilePhone can actually return a NSString or NSNull so it should be declared as - (id) mobilePhone. Since it's not, we can extend MSGraphUser
extension MSGraphUser {
var optMobilePhone : String? { return self.dictionary["mobilePhone"] as? String }
}
And then use that computed property to safely access the value:
for obj in users.value {
if let user = obj as? MSGraphUser {
print(user)
print(String(user.surname.dynamicType))
print(user.optMobilePhone ?? "no phone")
}
}
I'm reading through some source code and I noticed the following API, where the developer passes in nil if they want an object to be removed.
- (void)setSomeStatus:(SomeStatusObject *)status {
if (status != nil) {
[store setObject:status forKey:SOME_STATUS_KEY];
} else {
[store removeObjectForKey:SOME_STATUS_KEY];
}
}
My specific question is if the above can be reduced to
- (void)setSomeStatus:(SomeStatusObject *)status {
[store setObject:status forKey:SOME_STATUS_KEY];
}
Or alternatively
- (void)setSomeStatus:(SomeStatusObject *)status {
store[SOME_STATUS_KEY] = status;
}
No, they are not equivalent. In fact, passing nil to setObject:forKey: (either the value or the key) will result in a runtime exception.
You can't set a value to nil using setObject:forKey.
NSDictionary wants an object, even if that object represents NULL, and the value alone can't be set to simply nil. (You could set it to NSNULL though).
So to answer your question, your code can't replace the existing.
I am getting response from Twitter Response using FHSTwitterEngine.
Code Output
How can I get username and name key values. as I try this
self.screenName = [dicUser objectForKey:#"screen_name"];
It gives error.
[__NSArrayM objectForKey:]: unrecognized selector sent to instance 0xcca78b0
You're assuming that the return value is an NSDictionary when in fact it is an NSArray. Protect yourself from crashing by wrapping your call with:
if ([dicUser isKindOfClass:[NSDictionary class]])
{
}
I'm using a sudz-c generated SOAP framework, my service calls seem to work fine, but when I try doing anything with the data, iOS (emulator) crashes.
This is the service call...
[service hentOpgaveliste:self action:#selector(handleToDoList:) userid:userNameTxt.text pdaid:[pdaIdTxt.text intValue]];
For the handleToDoList: I am using the standard method provided in the examples, which successfully NSLogs my result.
....
CXMLNode *xmlResult = (CXMLNode*)value;
NSLog(#"HentToDo: %#", [xmlResult description]);
....
From here, I get the log you see below.
{
hentOpgavelisteResult = {
diffgram = "<null>";
schema = {
element = {
complexType = {
choice = {
element = {
complexType = {
sequence = {
element = "<null>";
};
};
};
};
};
};
};
};
When I attempt to NSLog the child count as seen below, or any of the other CXMLNode instance method for that matter, I get the following exception.
....
NSLog(#"Children %#", [xmlResult childCount]);
....
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSCFDictionary childCount]: unrecognized selector sent to instance
Not sure where to go from here. I've seen blogs such as this talking about issues with touchXML and namespaces, but it appears to me that I have a namespace.
Any ideas would be appreciated, when it comes to SOAP I'm noob class.
This is a common mistake; when logging integers you should use %i instead of %#, like this:
NSLog(#"Children %i", [xmlResult childCount]);
%# is only for logging objects. If you try to log an integer as an object, you get a crash because it thinks it's a pointer to a random place in memory, and tries to call the description method on it.
Also, from the exception that you're getting, xmlResult is an NSDictionary (CFDictionary is the same thing), in which case the method you should be calling is count, not childCount:
NSLog(#"Children %i", [xmlResult count]);
For printing count..
You should use '%d'
ex:
NSLog(#"Children count = %d", [xmlResult childCount]);
I always use NSLog to print out contents of objects when I am debugging my iOS applications. But any time I come across a "nil" object, the program crashes. In Java, if an object is null, it will print "null". Is there a way to do this in Objective-C?
Something like:
if (questionableObject == nil) {
NSLog(#"questionableObject is nil.");
} else {
NSLog(#"questionableObject is: %#", questionableObject);
}
I've only really run into this problem when I send a message to an object inside the NSLog parameter list that uses a nil object as a parameter. Something like this:
if (questionableObject == nil) {
NSLog(#"questionableObject is nil.");
} else {
NSLog(#"result is: %#", [something someMessage:questionableObject]);
}
What do you mean by "print out contents of objects"? If you're dereferencing a nil pointer, that'll cause a problem. If you're just printing the pointer, that should be OK. You can also send messages to nil without problem, so you could do this:
NSLog(#"theObject is: %#", [theObject description]);