I've exhausted other threads, so I'm posting this question here. Please pardon any newbie mistakes I've made along the way. I've been reading a lot, and I think I'm getting confused.
The Goal:
I'm trying to pass data from a form in objective-c to my django web service. In an effort to assist with this, I've employed the ASIHTTPRequest class to facilitate information transfer. Once sent to the web service, I'd like to save that data to my sqlite3 database.
Procedure:
On the Objective-C side:
I've stored the inputted form data and their respective keys in an NSDictionary, like this:
NSDictionary *personInfo = [NSDictionary dictionaryWithObjectsAndKeys:firstName.text, #"fName", middleName.text, #"mName", lastName.text, #"lName", nil];
I've added it to my ASIHTTPRequest in a different class by using a delegate. I've made the NSDictionary the same as above in the code block below for simplicity, like so:
NSString *jsonPerson = [personInfo JSONRepresentation];
[request addRequestHeader: #"Content-Type" value:#"application/json; charset=utf-8"];
[request appendPostData:[jsonPerson dataUsingEncoding:NSUTF8StringEncoding]];
[request setRequestMethod:#"POST"];
[request startAsynchronous];
And a NSLog shows the string I'm passing to look like this, which validates at least in JSONLint
{"mName":"Arthur","lName":"Smith","fName":"Bob"}
Because I'm seeing what appears to be valid JSON coming from my ASIHTTPRequest, and actions are running from requestfinished: rather than requestfailed:, I'm making the assumption that the problem more than likely isn't on the Objective-C side, but rather on the django side.
Here's what I've tried so far:
json.loads(request.POST)
>>expected string or buffer
json.loads('request.POST')
>>no JSON object to decode
json.loads(request.raw_post_data)
>>mNamelNamefName
incoming = request.POST
>>{"mName":"Arthur","lName":"Smith","fName":"Bob"}
incoming = request.POST
onlyValues = incoming.iterlists()
>>(u'{"mName":"Arthur","lName":"Smith","fName":"Bob"}', [u''])
...and a smattering of other seemingly far-fetched variations. I've kept a log, and can elaborate. The only hope I've been able to find is in the last example; it looks like it's treating the entire string as the key, rather than breaking up each dict object and key as I would have expected.
I realize this is terribly elementary and I don't normally ask, but this problem has me particularly stumped. I do also remember reading somewhere that python won't recognize the double-quotes around each object and key, that to get it to something django likes, each should be surrounded by single-quotes. I just don't have any idea how to get them that way.
Thanks!
This might be a little cumbersome but you may try some simple regexp in objective c just to see if that is really the case
NSError *error = NULL;
NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:#"\"" options:NSRegularExpressionCaseInsensitive error:&error];
NSString *json = [regex stringByReplacingMatchesInString:jsonPerson options:0 range:NSMakeRange(0, [jsonPerson length]) withTemplate:#"'"];
There might be some errors because I didn't run the code.
Related
Is there a way I can NSLog JSON response of NSData in JSONformat?
NSLog(#"JSON NSString: %#" ,jsonData);
In this post they are printing NSDictionary,I can convert it to NSDictionary. and this solution returns (null).
How can I NSLog in JSON format?
• What's wrong:
jsonData (as you gave) IS NOT a hexData representing a JSON.
• Quick hack (not viable solution!) to get your JSON to use in your site CodeBeautify:
NSDictionary *dictFromData = [NSKeyedUnarchiver unarchiveObjectWithData:jsonData];
NSData *realJSONData = [NSJSONSerialization dataWithJSONObject:dictFromData options:0 error:nil];
NSString *strFINAL = [[NSString alloc] initWithData:realJSONData encoding:NSUTF8StringEncoding];
NSLog(#"StrFINAL: %#", strFINAL);
Note: Yeah, I bypassed the error parameters, and we shouldn't. With
NSJSONWritingPrettyPrinted instead of 0 in options: parameter, you have a result almost similar to the one of CodeBeautify.
• How did I get there:
Firt, I copy/paste your bump string of NSData with this answer.
That way, I got jsonData as you got.
Then, I tried simply what it should be given your informations:
NSDictionary *dict = [NSJSONSerialization JSONObjectWithData:jsonData options:NSJSONReadingAllowFragments error:&errorJSON];
Which didn't work giving the error:
Error Domain=NSCocoaErrorDomain Code=3840 "The operation couldn’t be
completed. (Cocoa error 3840.)" (Invalid value around character 0.)
UserInfo=0x17598540 {NSDebugDescription=Invalid value around character
0.}
But with NSDictionary *dictWithData = [NSKeyedUnarchiver unarchiveObjectWithData:jsonData];, I managed to get the real NSDictionary. But NSKeyedArchiver/NSKeyedUnarchiver are doing something "equivalent" to NSJSONSerialization: it serializes, transforming a NSObject into NSData (and vice-versa). But more powerful: for any kind of object that are NSCoding compliant. Here, since it's originally from a JSON (only NSString, NSNumber, NSArray and NSDictionary objects, and not a custom one), it's working without any more code.
Did you for instance tried to save it into NSUserDefaults and it's not a .plist either (that was also one on my tries, I saved jsonData into memory, and used dictionaryWithContentsOfFile: giving me weird answer, but a important one in the bump of it: ""$class" = "{value = 23}";" which lead me to NSKeyArchiver/NSKeyUnarchiver). I don't know what you did exactly.
• Conclusion:
So clearly, somewhere, you mixed stuff found on the web. You need to rework that. You can't let it like this. There is issue in your code elsewhere. Where did you get jsonData from? What did you do with it?
Code:
NSLog("Formatted JSON : %#" ,[[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding]);
There are different situations. If parsing the JSON data was fine, then you just want to log the result (dictionary or array). If parsing the JSON data failed, and you suspect there is something wrong with the JSON data, then you convert the JSON data to an NSString and log that. And finally, if either conversion to NSString failed, or you look at the NSString and can't find what's wrong with it, then you log the NSData itself to be able to see the bytes. That's useful if someone managed to put control characters or some other nonsense into your JSON data.
The best is to write a method (warning! not for the timid! requires writing code yourself) that takes the NSData, analyses it and prints out the information that you need.
What's the reason that I can't parse a base64 string from a JSON request? when I make it a small string it works.
To clarify a little:
else if([connection isEqual:self.appearanceConnection]){
NSArray *arrayOfAppearances = [NSJSONSerialization JSONObjectWithData:[[[NSString alloc] initWithData:data
encoding:NSUTF8StringEncoding] dataUsingEncoding:NSUTF8StringEncoding]options:NSJSONReadingAllowFragments error:&error];
NSLog(#"het aantal appearances is: %i", arrayOfAppearances.count);
[self syncAppearances:arrayOfAppearances];
}
When I edit it to a small string, I get the response that the length of the received array is 1. If I change it again to the base 64 of the image, the length is 0.
http://cl.ly/image/470Z0X1P3K1b (image form JSON response)
The error I get on the String:
Updated answer:
You now inform us that JSONObjectWithData is reporting an error:
Unterminated string around character 62
Character 62 is the start of the logo. I'm not seeing the end of the JSON in any of your screen snapshots. It looks like it's getting cut off.
You haven't shown us how you are populating data, but it looks almost like you're using a NSURLConnection but trying to parse in didReceiveData as opposed to waiting for the full results and only invoking the the JSON parse in connectionDidFinishLoading. NSURLConnection will break a long response into several calls to didReceiveData and you have to append all of those NSData to a single NSMutableData, and only try to parse it when it's done retrieving everything.
You either need to (a) show us the code where you're loading data and/or (b) share the full JSON. Either your JSON isn't properly terminated or you're trying to parse it before the whole thing is downloaded (probably the latter).
Original answer:
I'm not sure if this is the problem, but your line that says:
NSArray *arrayOfAppearances = [NSJSONSerialization JSONObjectWithData:[[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding] dataUsingEncoding:NSUTF8StringEncoding]options:NSJSONReadingAllowFragments error:&error];
should simply be:
NSArray *arrayOfAppearances = [NSJSONSerialization JSONObjectWithData:data
options:0
error:&error];
The JSONObjectWithData method takes a NSData, not a NSString.
And, if you're not getting anything returned from this method, you should examine the contents of error and see what it says.
If you're still unable to figure out what the problem is, perhaps you can share the full JSON response with us (give us a URL or upload it somewhere) and we can take a look at it.
With a big thanks to #Rob!
Here a little summary:
Create a variable NSMutableData (don't forget to initialise in the viewdidload)
In the didReceiveData, you append the data to your mutable data using [self.appearancedata appendData:data];
In the connectionDidFinishLoading you parse your JSON
I need to send a series of printer commands to a Sato barcode printer. For example:
<ESC>A
<ESC>H0120
<ESC>V0060
<ESC>$B,180,180,0
<ESC>$=Information
...
I have an open tcp/ip connection to the printer and simply want to write an NSData object, such as:
[connection write:data error:error];
wheras data is an NSData object. I realize that I can insert the escape into a string using the binary value with \x1B. For example:
NSString *printString=[[NSString alloc]initWithString:#"\x1BA\X1BH0120\X1BV0060\X1B$B,180,180,0/X1B$=Information"];
The problem I'm having is that I don't know how to translate my string to NSData for the write.
I appreciate any suggestions.
You can simply do:
NSData *data = [printString dataUsingEncoding:NSUTF8StringEncoding];
Choose the encoding that best suits your needs, apart from that it's pretty straightforward.
I'll give an update on some of my findings in case someone stumbles upon a similar problem in the future. My problem was that I needed to send a series of printer commands to a Sato barcode printer. Sato uses a proprietary language that requires syntax like above whereas I needed to send commands like <ESC>A and <ESC>Z. I had an open tcp/ip connection and kept trying several methods to send the commands with no luck. I though the problem was in my translation to NSData. I was close, but not close enough. The problem turned out to be in my translation from a file to an NSString...not when I was converting the NSString to NSData. I also had problems trying to use \x "escapes" to send the binary equivalent of <ESC>. I finally settled on using the octal equivalent.
// load the appropriate file as a string
NSString *filePath = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:#"sato.txt"];
NSError *firstError=nil;
NSString *satoData=[[NSString alloc]initWithContentsOfFile:filePath encoding:NSNonLossyASCIIStringEncoding error:&firstError]; // the NSNonLossyASCIIStringEncoding was the key to correcting my problem here.
satoData=[satoData stringByReplacingOccurrencesOfString:#"Description" withString:self.description];
satoData=[satoData stringByReplacingOccurrencesOfString:#"ItemID" withString:self.itemId];
satoData=[satoData stringByReplacingOccurrencesOfString:#"Quantity" withString:self.printQty];
NSDate *now=[NSDate date];
NSString *formattedDate=[NSDateFormatter localizedStringFromDate:now dateStyle:NSDateFormatterMediumStyle timeStyle:NSDateFormatterNoStyle];
satoData=[satoData stringByReplacingOccurrencesOfString:#"Date" withString:formattedDate];
NSData *data=[satoData dataUsingEncoding:NSUTF8StringEncoding];
[connection write:data error:error];
Here is a sample of some of the contents of the sato.txt file
\033A\033#E5\033Z
\033A\033H0120\033V0060\033$B,180,180,0\033$=ItemID
The \033 is the octal escapes for <ESC>
I have a Mac application that keeps it's own log file. It appends info to the file using NSString's writeToFile method. One of the things that it logs are URL's of web services that it is interacting with. To encode the URL, I'm doing this:
searchString = (NSString *)CFURLCreateStringByAddingPercentEscapes(NULL, (CFStringRef)searchString, NULL, (CFStringRef)#"!*'();:#&=+$,/?%#[]", kCFStringEncodingUTF8 );
The app then appends searchString to the rest of the URL and writes it to the log file. Now the problem is that after adding that URL encoding line, nothing seems to be getting written to the file. The program functions as expected otherwise however. Removing the line of code above results in all of the correct information being logged to the file (removing that line is not an option because searchString must be URL encoded).
Oh and I am using NSUTF8StringEncoding when writing the NSString to the file.
Thanks for any help.
EDIT: I know there's also a similar function to CFURLCreateStringByAddingPercentEscapes in NSString, but I've read that it doesn't always work. Can anyone shed some light on this if my original question cannot be answered? Thanks! (EDIT: same problem occurs when using stringByAddingPercentEscapesUsingEncoding:)
EDIT 2: Here's the code that I'm using to append messages to the log file.
+(void)logText:(NSString *)theString{
NSString *docsDirectory = [NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory,NSUserDomainMask,YES) objectAtIndex:0];
NSString *path = [docsDirectory stringByAppendingPathComponent:#"Folder/File.log"];
NSString *fileContents = [[[NSString alloc] initWithContentsOfFile:path] autorelease];
if([fileContents lengthOfBytesUsingEncoding:NSUTF8StringEncoding] >= 204800){
fileContents = #"";
}
NSString *timeStamp = [[NSDate date] description];
timeStamp = [timeStamp stringByAppendingString:#": "];
timeStamp = [timeStamp stringByAppendingString:theString];
fileContents = [fileContents stringByAppendingString:timeStamp];
fileContents = [fileContents stringByAppendingString:#"\n"];
[fileContents writeToFile:path atomically:YES encoding:NSUTF8StringEncoding error:NULL];
}
Because after almost a whole day no one else has offered any answers, I'm going to post a wild guess here: you're not accidentally using the string you want to output (with percent characters in it) as a format string are you?
That is, making the mistake of doing:
NSLog(#"In format strings you can use %# as a placeholder for an object, and %i for a plain C integer.")
Instead of:
NSLog(#"%#", #"In format strings you can use %# as a placeholder for an object, and %i for a plain C integer.");
But I'm going to be surprised if this turns out to be the cause of your problem, as it usually causes random-looking output, rather than absolutely no output. And in some cases, Xcode also gives compiler warnings about it (when I tried NSLog(myString), I got "warning: format not a string literal and no format arguments").
So don't shoot me down if this answer doesn't help. It would be easier to answer your question if you could show us more of your logging code. As for the one line you provided, I can't detect anything wrong with it.
Edit: Oops, I kind of missed that you mentioned you're using writeToFile:atomically:encoding:error: to write the string to the file, so it's even more unlikely you're accidentally treating it as a format string somewhere. But I'm going to leave this answer up for now. Again, you should really show us more of your code though ...
Edit: Regarding your question on a method in NSString that has similar percent encoding functionality, that would be stringByAddingPercentEscapesUsingEncoding:. I'm not sure what kind of problems you're thinking of when you say you've heard it doesn't always work. But one thing is that CFURLCreateStringByAddingPercentEscapes allows you to specify extra characters that don't normally have to be escaped but which you still want to be escaped, while the method of NSString doesn't allow you to specify this.
I'm using the following code to grab a few objects from SQLite store (which is a prepared SQLite db file, generated with Core Data on desktop):
NSFetchRequest * request = [[NSFetchRequest alloc] init];
[request setEntity: wordEntityDescription];
[request setPredicate: [NSPredicate predicateWithFormat: #"word = %#", searchText]];
NSError * error = [[NSError alloc] init];
NSArray * results = [[dao managedObjectContext] executeFetchRequest: request error: &error];
Eveyrthing seems to be setup properly, but executeFetchRequest:error: fails deeply inside Core Data (on NSSQLCore _newRowsForFetchPlan:selectedBy:withArgument) producing 256 error to the outside code.
The only kink I had setting up managedObjectContext is I had to specify NSIgnorePersistentStoreVersioningOption option to addPersistentStoreWithType as it was constantly producing 134100 error (and yes, I'm sure my models are just identical: I re-used the model from the project that produced the SQL file).
Any ideas?
P.S. Don't mind code style, it's just a scratch pad. And, of course, feel free to request any additional info. It would be really great if someone could help.
Update 1
Alex Reynolds, thanks for willingness to help :)
The code (hope that's what you wanted to see):
NSEntityDescription * wordEntityDescription; //that's the declaration (Captain Obviousity :)
wordEntityDescription = [NSEntityDescription entityForName: #"Word" inManagedObjectContext: ctx];
As for predicate – never mind. I was removing the predicate at all (to just grab all records) and this didn't make any differences.
Again, the same code works just fine in the desktop application, and that drives me crazy (of course, I would need to add some memory management stuff, but it at least should produce nearly the same behavior, shouldn't it?)
Can you add code to show how wordEntityDescription is defined?
Also, I think you want:
NSError *error = nil;
You may want to switch the equals symbol to like and use tick marks around the searchText field:
[request setPredicate: [NSPredicate predicateWithFormat: #"word like '%#'", searchText]];
NSPredicate objects are not put together like SQL, unfortunately. Check out Apple's NSPredicate programming guide for more info.