Storing and retrieving NSAttributedString - objective-c

I want to store my Rich Text for UITextView's NSAttributedString. For this as suggested in a question on stackoverflow, I choose NSData. Problem is app crashes while un-archiving and retrieved data is also not same as the saved NSData.
Explanation
DB:
Saving Data into DB
In DB I have a column named rtfText with datatype blob -> (rtfText blob)
While Saving into DB, I do this
NSData *data = [NSKeyedArchiver archiveWithRootObject:_myTextView.attributedString];
and sends the data like this in query
NSString Query = [NSString stringWithFormat:#"Insert into table (rtfText) VALUES \"%#\")",data];
Retrieving Data From DB
Data is retrieved like this:
NSData *data = [[NSData alloc] initWithBytes:(sqlite3_column_blob(statement, 18)) length:sqlite3_column_bytes(statement, 18)];
UnArchive:
From the retrieved NSData from DB I unarchive it into NSAttributedString like this
_myTextView.attributedText = [NSKeyedUnarchiver unarchiveObjectWithData:data]; **<- App Crashes at this point giving error**
Error:
-[__NSCFData objectForKey:]: unrecognized selector sent to instance 0x15d56e80
I even tried to save NSAttributedString to NSData after Archive then converting it to NSString using NSASCIIStringEncoding but DB crashes then. I also tried saving it like this. First using NSKeyedArchiver converted NSAttributedString to NSData then to NSString using NSUTF8StringEncoding which gave me null string.
Kindly look into this.
Thanks in advance

Data Never inserted properly into database. Reason is Query on sqlite3 is always in the form of UTF8. NSString has to be converted to UTF-8 to make a query. After this conversion stored NSData in database is totally changed i.e. encoded again via UTF-8.
When I retrieved the data, it was not same as the old one. Therefore got error while un archiving it.
Solution: Stored NSData into sqlite3 without converting to UTF-8 and used sqlite_bind_blob for storing blob data to sqlite3 database.

Related

How to NSLog NSData JSON response in JSON format?

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.

How to parse base64 image from JSON

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

How can I convert an NSString with printer commands into NSData

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>

NSData or NSAttributedString with SBJSON

I am using the SBJSON to convert my NSDictionary to a JSON String in my iOS application.
when my dictionary contains a NSAttributedString or an NSData, the SBJSON fails to generate the string representaiton.
Incase of NSAttributedString, the error is :
-JSONRepresentation failed. Error trace is: (
"Error Domain=org.brautaset.JSON.ErrorDomain Code=1 \"JSON serialisation not supported for NSConcreteMutableAttributedString\
Incase of NSData, the error is :
-JSONRepresentation failed. Error trace is: (
"Error Domain=org.brautaset.JSON.ErrorDomain Code=1 \"JSON serialisation not supported for NSConcreteMutableData\"
UserInfo=0x7ed2560 {NSLocalizedDescription=JSON serialisation not
supported for NSConcreteMutableData}"
Solving atleast one of the 2 problems will be a great deal.
Please help.
Thanks
Roshit
JSON doesn't have any datatype to do what you want, but you could convert the NSData into a Base64 encoded string. This can be done automatically with a category on NSData that implements the -proxyForJson method. The problem is when you need to convert it back to NSData on the other end. If the key is known, then you can just Base64 decode that key. But if the data portion can be for any key it's a bit more difficult. You'll have to somehow structure your data so you can determine which strings should be Base64 decoded.
You can not pass NSData object. Solution for problem is, Just use the following line (change response to your nsdata object) and use that string as a value.
NSString *json_string = [[NSString alloc] initWithData:response encoding:NSUTF8StringEncoding];
You can not pass NSAttributedString as a value as well. You have to change NSAttributedString to NSString. Please check OHAttributedLabel lib for more information.

Unicode data from NSData to NSString

So if I have NSData from an HTTP request, then I do something like this:
NSString *test = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
This will result in null if the data contains weird unicode data (title is from reddit):
{"title":"click..██me..and..then██________ ██check██_.your...██.__...██____ ██....██████████████....██____ ██████....██████....██████____ ██████████████████████____ ....██████████████████______ ........██..._recently....██________ ....██....viewed....links....██_____"},
How would I convert the data to a string?
Ideally, it would best if the string wasn't null so I could parse it as JSON, but even a lossy conversion is fine with me in these cases.
I'm not familiar with unicode (naive American I am), so any enlightenment about that would be a nice bonus :)
If I copy and paste that text into a UTF-8 text file, read it with dataWithContentsOfURL: and convert it to a string with initWithData:encoding:, it works fine. The most likely explanation is that you are not getting valid UTF-8 data.