SOAP usage in iOS with touchXML - ios

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]);

Related

Comparing two dictionary values gives me an NSInvalidArgumentException

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!

Is there any way to check if `EncodedPath` string is valid for `GMSPath` in GoogleMaps on iOS swift?

I have a code that will display many Polygons on the map, This is my code:
let path = GMSMutablePath(fromEncodedPath: path_str)
let polygon = GMSPolygon(path: path)
polygon.geodesic = true
polygon.map = pnlMap
This snippet work correct if the path_str variable in the correct format.
But if there is an error in the format of path_str the app will crash.
I tried the following methods:
if let path = GMSMutablePath(fromEncodedPath: path_str) {
// mycode
}
Also:
do {
let path = try GMSMutablePath(fromEncodedPath: path_str)
} catch ()...
I didn't reach to any correct solution.
I couldn't find a way to handle this exception.
Terminating app due to uncaught exception 'NSRangeException', reason: '-[__NSCFString characterAtIndex:]: Range or index out of bounds'
*** First throw call stack:
(...)
I too got stuck in such a problem and I am sorry, but there is no way you can check that. I rectified the problem by making sure that the source is sending me correct encoded path.
In my case the crash was occurring cause Objective C was reading \\ as \.
Please check if its the same with you.
Hope it helps.
I also face the similar problem. To check on iOS end i just handle the exception and assume if any exception has been raised, this means encoded path is not valid. Here is the code snippet:
#try {
GMSPath *path = [GMSPath pathFromEncodedPath:pathEncodedString];
} #catch (NSException *exception) {
NSLog(#"Invalid encoded path raised an Exception: %#", exception);
} #finally {
}
They fixed this issue in the new: version 2.1
GMSPath initFromEncodedPath now returns nil for invalid input (previously invalid input could result in a crash). (Issue 10162.)
Now if the Encoded Path string is wrong, the GMSPath path variable will be nil.

Swift: unrecognized selector sent to instance, how to detect null value?

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")
}
}

Verify a method is called twice with two different parameters

I would like to test that a method is called twice, the first time passing YES for a parameter, the second time NO.
What complicates things is that the method I would like to test is a class method, I'm not sure whether this has anything to do with the issue I'm seeing.
My test looks like this:
- (void)testCreatesMessagesWithCorrectHTMLForcing {
id messageClassMock = OCMClassMock([MyMessage class]);
[messageClassMock setExpectationOrderMatters:YES];
[[[messageClassMock expect] andForwardToRealObject] messageForDictionary:[OCMArg any]
forceHTMLRendering:YES
inContext:[OCMArg any]];
[[[messageClassMock expect] andForwardToRealObject] messageForDictionary:[OCMArg any]
forceHTMLRendering:NO
inContext:[OCMArg any]];
NSMutableDictionary *mockJSON = [self.mockJSON mutableCopy];
MyThread *classUnderTest = [MyThread threadForDictionary:mockJSON
inContext:self.mockContext];
OCMVerifyAll(messageClassMock);
[messageClassMock stopMocking];
}
The threadForDictionary:inContext: method calls the messageForDictionary:forceHTMLRendering:inContext: for each message in the thread and needs an object as return value. That's why I added andForwardToRealObject, otherwise I get exceptions because of the return value being nil. As you can imagine from the signatures it's about parsing JSON to CoreData objects.
Adding this test makes all other tests in the same test file fail with the following message
unexpected method invoked: messageForDictionary:<OCMAnyConstraint: 0x7fab637063d0> forceHTMLRendering:NO inContext:<OCMAnyConstraint: 0x7fab63706eb0>
expected: messageForDictionary:<OCMAnyConstraint: 0x7fab6371cb20> forceHTMLRendering:YES inContext:<OCMAnyConstraint: 0x7fab6371fb50>"
I don't get why this happens as I call stopMocking in the end so the other tests should not be affected.
The following changes make the other tests run correctly:
Remove any of the two expectations. It doesn't matter which of two it is as long as there is only one.
Renaming the method to testZ. This way it's alphabetically after the other tests in the same file; thus, executed last and doesn't seem to affect them anymore.
As the setExpectationOrderMatters:YES does not seem to work I tried to check the order myself doing this:
- (void)testCreatesMessagesWithCorrectHTMLForcing {
id messageClassMock = OCMClassMock([MyMessage class]);
__block BOOL firstInvocation = YES;
[[[messageClassMock expect] andForwardToRealObject] messageForDictionary:[OCMArg any]
forceHTMLRendering:[OCMArg checkWithBlock:^BOOL (id obj) {
NSNumber *boolNumber = obj;
expect([boolNumber boolValue]).to.equal(firstInvocation);
firstInvocation = NO;
return YES;
}]
inContext:[OCMArg any]];
NSMutableDictionary *mockJSON = [self.mockJSON mutableCopy];
MyThread *classUnderTest = [MyThread threadForDictionary:mockJSON
inContext:self.mockContext];
expect(firstInvocation).to.equal(NO);
OCMVerifyAll(messageClassMock);
[messageClassMock stopMocking];
}
But the checkWithBlock: does not seem to be called. (The test fails at expect(firstInvocation).to.equal(NO);)
What's going on here?
Is there another (better?) way to write a test with OCMock that checks whether the method is called with the correct parameters in the correct order?
I finally got the first solution to work. The problem is that OCMock throws an exception if expectationOrderMatters is YES. Due to the exception the test is prematurely exited and the stopMocking is never called which leads to the mock not being cleaned up properly. Subsequent calls to the mocked method then fail with the same exception making all tests fail.
The solution is to ensure stopMocking is called even if everything goes wrong. I achieved this by using try-catch like this (the change to macros and using andReturn instead of andForwardToRealObject do not matter):
MyMessage *message = [MyMessage insertInManagedObjectContext:self.mockContext];
id messageClassMock = OCMStrictClassMock([MyMessage class]);
#try {
[messageClassMock setExpectationOrderMatters:YES];
OCMExpect([messageClassMock messageForDictionary:[OCMArg any]
forceHTMLRendering:NO
inContext:[OCMArg any]]).andReturn(message);
OCMExpect([messageClassMock messageForDictionary:[OCMArg any]
forceHTMLRendering:YES
inContext:[OCMArg any]]).andReturn(message);
MyThread *classUnderTest = [MyThread threadForDictionary:self.mockJSON
inContext:self.mockContext];
OCMVerifyAll(messageClassMock);
}
#catch (NSException *exception) {
XCTFail(#"An exception occured: %#", exception); // you need this, otherwise the test will incorrectly be green.
}
#finally {
[messageClassMock stopMocking];
}
Notice the XCTFail in the catch-block: You need to include this, otherwise your test will be green although an exception occurred.

Fetch Values from NSMutableDictionary?

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]])
{
}

Resources