SoapRequest to NSString on iOS? - ios

I'm using an API generated by Sudzc.com from a WDSL. I have this method:
- (SoapRequest*) getToolListAsXML: (id <SoapDelegate>) handler getEmptyFC: (BOOL) getEmptyFC repoid: (NSString* ) repoid
And I thought that It calls the webservice and receive an XML as string as the documentation generated by sudzc.com told me:
But I really don't know how the SoapDelegate works, if I want the response (the list as string) what I'm supposed to do? The examples are more confusing, it says:
But, obviously,
NSString resp = [service getToolListAsXML:self action:#selector(getToolListAsXMLHandler:) getEmptyFC: NO repoid: #""];
doesn't work because of 'incompatible pointer types..."
I'm very new on this so sorry if what I'm saying has nonsense.
Thanks.

Try this
[service getToolListAsXML:self action:#selector(getToolListAsXMLHandler:) getEmptyFC: NO repoid: #""]
- (void) getToolListAsXMLHandler: (id) value {
if([value isKindOfClass:[NSError class]]) {
//NSLog(#"%#", value);
return;
}
// Handle faults
if([value isKindOfClass:[SoapFault class]]) {
//NSLog(#"%#", value);
return;
}
NSString * resp =(NSString *)value;
}
you will get soap request in string

Related

Objective-C data type issue

I'm not that strong with Objective-C, so this is probably a simple issue. I cannot understand why the the last line in the error completion block is causing an exception:
- (void)sendInappropriateNewsfeedComment:(NSString *)comment newsfeedEventId:(NSString *)newsfeedEventId completion:(void (^)(NSString *, NSInteger))completion error:(void (^)(NSString *, NSInteger))error {
PAInappropriateNewsFeedRequest *inappropriateNewsfeedRequest = [[PAInappropriateNewsFeedRequest alloc] initWithComment:comment newsfeedEventId:newsfeedEventId];
[inappropriateNewsfeedRequest executeWithCompletionBlock:^(id obj) {
completion(#"SUCCESS", (NSInteger)1);
} error:^(NSError *e, id obj) {
NSString * message = [obj objectForKey:#"message"];
error(message, [obj integerForKey:#"code"]);
}];
}
I've also attached a screenshot showing that the "obj" object has a key called "code" that is of type "(long)-1".
What is the proper way to declare the error block and pass the "-1" value back to the call site?
Simply because NSDictionary has no method called integerForKey. That's what "unrecognized selector" means. Selector is basically a method name.
The fact that this can be even compiled is caused by using id for the parameter type. You can call anything on id but it will crash your app if the method does not exist. You should cast obj to a proper type as soon as possible.
NSDictionary *dictionary = (NSDictionary *) obj;
NSString *message = dictionary[#"message"];
NSNumber *code = dictionary[#"code"];
If obj can be a different type, you should make sure to check [obj isKindOfClass:NSDictionary.self] before casting.
The whole solution taking Sulthan's suggestions into account might looks something like this
typedef void (^NewFeedCompletion)(NSString *, NSInteger);
typedef void (^NewsFeedError)(NSString *, NSInteger);
- (void) sendInappropriateNewsfeedComment: (NSString *)comment
newsfeedEventId: (NSString *)newsfeedEventId
completion: (NewFeedCompletion) completion
error: (NewsFeedError) error
{
PAInappropriateNewsFeedRequest *inappropriateNewsfeedRequest = [[PAInappropriateNewsFeedRequest alloc] initWithComment:comment newsfeedEventId:newsfeedEventId];
[inappropriateNewsfeedRequest executeWithCompletionBlock: ^(id obj) {
completion(#"SUCCESS", (NSInteger)1);
} error:^(NSError *e, id obj) {
assert([obj isKindOfClass: NSDictionary.class])
NSDictionary *errorDictionary = (NSDictionary *) obj;
NSString *message = [errorDictionary objectForKey: #"message"];
NSNumber *code = [errorDictionary objectForKey: #"code"]
error(message, [code integerValue]);
}];
}

Parsing id to NSString

When parsing API responses, sometimes I can not rely on strings being embedded in quotation marks. ID's are a good example of this, where some API's will send the numerical ID as a string while some will send it as a number.
What is a good practice when parsing such a value? If I simply parse it to an NSString like so:
NSString *myID = (NSString *)message["myID"];
I can end up with an NSString object that somehow contains (long)123.
And using stringValue would cause issues when the value is actually already sent as a string (since NSString does not have a stringValue function).
A way that works, but is somewhat ugly, is this:
id myID = (NSString *)message["myID"];
if ([myID respondsToSelector:#selector(stringValue)])
{
myID = [myID stringValue];
}
You could do something like:
id myID = message["myID"];
if ([myID isKindOfClass:[NSString class]]) { ... }
else { ... }
As long as this logic is encapsulated inside data parser and is opaque for your api users (i.e. they will always get a string) any approach is fine, e.g.:
- (NSString*)parseID:(NSDictionary*)message {
id rawID = message["myID"];
if ([rawID isKindOfClass:[NSString class]]){
return rawID;
} else if ([rawID isKindOfClass:[NSNumber class]]) {
return [(NSNumber*)rawID stringValue];
} else {
// We might still want to handle this case.
NSAssert(false, #"Unexpected id type");
return nil;
}
}
Alternative is to define stringValue in extension, so any possible objet will respond to selector:
#implementation NSString(JSONStringParsing)
- (NSString *)stringValue {
return [self copy];
}
#end
Why not just use description?
NSArray *objects = #[
#NSIntegerMin,
#NSIntegerMax,
#"123456789"
];
for (id object in objects) {
NSString *stringObject = [object description];
NSLog(#"%# -> %# | %#", [object className], [stringObject className], stringObject);
}

Check if JSON value exists - iOS

I have an iOS application which downloads and parses a Twitter JSON feed and then presents that feed in a UITableView. This all works fine but I have one question:
When the user taps a UITableView cell, the app will look into the array "tweets_links" and see if that particular tweet has an attached URL, if it does then the web view will appear.
Because not all tweets have website URLs, I have added a simple try catch statement (like in C++) which can tell me if there is an exception when trying to access that part of the array.
My question is: is this is good or bad approach to doing this??
Here is my code:
int storyIndex = indexPath.row;
int url_test = 1;
NSString *url;
#try {
url = [[tweets_links[storyIndex] valueForKey:#"url"] objectAtIndex:0];
}
#catch (NSException *problem) {
// There is NO URL to access for this Tweet. Therefore we get the out of bounds error.
// We will NOT take the user to the web browser page.
// Uncomment the line below if you wish to see the out of bounds exception.
// NSLog(#"%#", problem);
url_test = 0;
}
if (url_test == 1) {
WebBrowser *screen = [[WebBrowser alloc] initWithNibName:nil bundle:nil];
self.seconddata = screen;
seconddata.web_url = url;
screen.modalTransitionStyle = UIModalTransitionStyleCoverVertical;
[self presentViewController:screen animated:YES completion:nil];
}
else if (url_test == 0) {
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:#"Info" message:#"There is no URL attatched to this Tweet." delegate:self cancelButtonTitle:#"Dismiss" otherButtonTitles:nil];
[alertView show];
[tweetTableView deselectRowAtIndexPath:indexPath animated:YES];
}
Is there a much better way of trying to achieve what I am doing???
Thanks, Dan.
Using try and catch is Objective-C isn't encouraged there are other ways checking and handling errors
// firstObject will return the first object in the array or nil if the array is empty.
url = [[tweets_links[storyIndex][#"url"]] firstObject];
if (!url) {
// handle the case for no url
} else {
// do something with url
}
Since sending a message to nil is safe in Objective-C and returns nil it's safe to chain calls. e.g. If the dictionary didn't have an object for that key, then it would return nil and sending firstObject to nil returns nil.
Using either if the below approaches will be fine because TRY CATCH is used to catch programming errors
and use
objectForKey:
instead of
valueForKey:
if ([tweets_links[storyIndex] objectForKey:#"url"] != nil)
OR
if ([url isKindOfClass:[NSString class]])
{
// Code handling the URL
}
else
{
// Code handling there is no URL
}
I don't know a ton about the Twitter feed, but you can probably check for a nil value returned from objectForKey: like so
if ([tweets_links[storyIndex] objectForKey:#"url"] != nil) { /* process the URL */ }
Your code assumes that the value is always an array of at least size = 1, it would be safer to inspect the #"url" key's value before assuming it's an array.
Using exceptions in Objective-C is throwned upon. Exceptions are reserved for programming errors. You don't catch them, you fix the code. With a JSON document, you never have any guarantees what you received, so just be careful.
NSString* url = nil;
NSArray* linksArray = nil;
NSDictionary* linkDict = nil;
NSArray* urlArray = nil;
if ([tweet_links isKindOfClass:[NSArray class]])
linksArray = tweet_links;
if (storyIndex >= 0 && storyIndex < linksArray.count)
linkDict = linksArray [storyIndex];
urlArray = linkDict [#"url"];
if ([urlArray isKindOfClass:[NSArray class]] && urlArray.count > 0)
url = urlArray [0];
if ([url isKindOfClass:[NSString class]])
{
// Code handling the URL
}
else
{
// Code handling there is no URL
}
Note that sending messages to a nil object always returns 0 / NO / nil as appropriate.
And please get into the habit of naming variables properly. You wrote "int url_test = 1;". What does url_test mean? I read the variable name, I have no idea what it means. I need to understand all the code. Making it "int" means it could be 0, 1, 2, 20000 or whatever. If you write instead "BOOL urlValid = YES;" that is clear: It means that you have a valid URL.
Since url value is a NSString value, you could use length to check both if it's nil and if not, if it has any value (not empty string). You can check then if this NSString is a valid url.
- (BOOL) validateUrl: (NSString *) candidate {
NSString *urlRegEx = #"(http|https)://((\\w)*|([0-9]*)|([-|_])*)+([\\.|/]((\\w)*|([0-9]*)|([-|_])*))+";
NSPredicate *urlTest = [NSPredicate predicateWithFormat:#"SELF MATCHES %#", urlRegEx];
return [urlTest evaluateWithObject:candidate];
}
....
NSString *url = [[tweets_links[storyIndex][#"url"]] firstObject];
if ([url length] && [self validateUrl: url]) {
// Has a valid URL
}

Core Data: Automatically Trim String Properties

For my Core Data NSManagedObject, I would like to ensure any NSString properties only contain strings that have been trimmed of whitespace.
I'm aware that I could achieve this by overriding each setter method, like so:
- (void)setSomeProperty:(NSString *)someProperty
{
someProperty = [someProperty stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
if ((!someProperty && !self.someProperty) || [someProperty isEqualToString:self.someProperty]) return;
[self willChangeValueForKey:#"someProperty"];
[self setPrimitiveValue:someProperty forKey:#"someProperty"];
[self didChangeValueForKey:#"someProperty"];
}
However, this seems like a lot of code to have to write, especially since my managed object is likely to have quite a few NSString properties.
Is there an easier way?
You could create a custom NSValueTransformer for NSString and assign all of your NSString properties to the new transformer in the model editor:
#interface StringTransformer: NSValueTransformer {}
#end
#implementation StringTransformer
+ (Class)transformedValueClass {
return [NSString class];
}
+ (BOOL)allowsReverseTransformation {
return YES;
}
- (id)transformedValue:(id)value {
return value;
}
- (id)reverseTransformedValue:(id)value {
return [value stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
}
#end
If you only need to ensure that the saved data is trimmed then you can implement willSave and use changedValues to check only the changed values. This will also make it easy to do in a loop to minimise code duplication.
You could do it during property validation:
- (BOOL)validateSomeProperty:(id *)inOutValue error:(NSError **)error
{
if (inOutValue)
{
NSString *value = *inOutValue;
*inOutValue = [value stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
}
return YES;
}
Core data will automatically call validateSomeProperty:error: before saving your record, so this will make sure that any data that gets saved is trimmed. It won't stop the on-change events firing if someone changes it from, say, foo to \n\nfoo\n\n, but it does mean that you don't have to fire them by hand.

XML into JSON conversion in iOS

I need to convert XML response to JSON and sand to the json To javaScript code.
My XML response:
<cell>
<Result>True</Result>
<sguid>02291c402-2220-422b-b199-f92f22e56d2f</sguid>
</cell>
I am using XMLReader supporting file from this site:
XMLReader
I am using this code to convert XML to JSON :
+ (NSString*) XMLToJson:(CXMLDocument *)xmlDocument
{
NSError *error = nil;
NSArray *resultNodes = [xmlDocument nodesForXPath:#"//cell" error:&error];
if(error)
NSLog(#"%#",error.description);
CXMLNode *cellNode = [resultNodes objectAtIndex:0];
NSLog(#"%#",cellNode.XMLString);
NSError *parseError = nil;
NSDictionary *xmlDictionary = [XMLReader dictionaryForXMLString:cellNode.XMLString error:&parseError];
NSLog(#"%#", xmlDictionary);
//{print this.
// cell = {
// Result = {
// text = True;
// };
// sguid = {
// text = "0391c402-1120-460b-b199-f92fffe56d2f";
// };
// };
//}
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:xmlDictionary
options:NSJSONWritingPrettyPrinted // Pass 0 if you don't care about the readability of the generated string
error:&error];
if(error)
NSLog(#"%#",error.description);
NSString *jsonString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
NSLog(#"%#", jsonString);
return jsonString;
}
I got JSON response like this:
{
"cell" : {
"Result" : {
"text" : "True"
},
"sguid" : {
"text" : "0391c402-1120-460b-b199-f92fffe56d2f"
}
}
}
I need JSON response like this:
{
"cell": {
"Result": "True",
"sguid": "02291c402-2220-422b-b199-f92f22e56d2f"
}
}
Because then I send this json to javascript code I get that exception jquery mobile dont know parser this and throws an exception of syntax error.
I've seen programmers use this solution and is helping them but I still get the same result in this solution.
XML into JSON conversion in iOS
thanks
I just wrote a function for your problem, I tried it on with a couple of XMLs. Let me know if you find any issues
- (NSMutableDictionary *)extractXML:(NSMutableDictionary *)XMLDictionary
{
for (NSString *key in [XMLDictionary allKeys]) {
// get the current object for this key
id object = [XMLDictionary objectForKey:key];
if ([object isKindOfClass:[NSDictionary class]]) {
if ([[object allKeys] count] == 1 &&
[[[object allKeys] objectAtIndex:0] isEqualToString:#"text"] &&
![[object objectForKey:#"text"] isKindOfClass:[NSDictionary class]]) {
// this means the object has the key "text" and has no node
// or array (for multiple values) attached to it.
[XMLDictionary setObject:[object objectForKey:#"text"] forKey:key];
}
else {
// go deeper
[self extractXML:object];
}
}
else if ([object isKindOfClass:[NSArray class]]) {
// this is an array of dictionaries, iterate
for (id inArrayObject in (NSArray *)object) {
if ([inArrayObject isKindOfClass:[NSDictionary class]]) {
// if this is a dictionary, go deeper
[self extractXML:inArrayObject];
}
}
}
}
return XMLDictionary;
}
And use it like this
NSDictionary *clearXML = [[self extractXML:[yourParsedXMLDictionary mutableCopy]] copy];
Your problem in using XMLReader. For resolve this problem you can use XMLConverter instead of the XMLReader.

Resources