JSON or NSDATA incomplete / truncated after server pull [duplicate] - ios

This question already has answers here:
NSLog on devices in iOS 10 / Xcode 8 seems to truncate? Why?
(7 answers)
Closed 5 years ago.
I'm pulling a .json file from my server and trying to read it into an NSDictionary in my app. Some of the file is being correctly parsed but it is incomplete - only some of the file is being read.
The strange thing is that the NSData is an equal length to the actual file, so it seems that it has full access, at least at some stage. When I log the NSData however, it seems to be way too short for the size of the file.
Here's the code I'm using to find the bug:
//SYNC BOOL
if (isSyncing){ return; }
isSyncing = true;
//FETCH BOOTSTRAP
NSError * fetchError = nil;
NSData * data = [NSData dataWithContentsOfURL:[NSURL URLWithString:syncPath]
options:kNilOptions
error:&fetchError];
if (fetchError){ [self error]; return; }
//PARSE JSON
NSError * jsonError = nil;
NSDictionary * json = [NSJSONSerialization JSONObjectWithData:data
options:kNilOptions
error:&jsonError];
if (jsonError){ [self error]; return; }
NSLog(#"data length is %lu", data.length);
NSLog(#"json is %#", json);
I've tried loading remotely from the server and locally from NSBundle - same result.
Could this be related to encoding / a rogue character in the JSON / some NSData max length?
Those options on the NSData fetch method and JSON Serialisation method, I've always left blank with no issue in the past, in terms of what's being pulled it's the same. I've also tried requests and sessions etc with no love.
EDIT:
I should add that when I log the the .allKeys of the json dictionary, it returns all keys correctly (including those not included in the log of the dictionary itself). This coupled with the correct NSData length implies that the data is in fact there, in completion. An explanation would be if the NSLog itself is somehow being truncated, implying an error when none exists. The problem is I haven't changed anything there. It could be a beta bug in the new Xcode.
EDIT B:
Logger Error on Xcode 9?
NSString * string = #"";
for (int n = 0; n < 10000; n++){
string = [NSString stringWithFormat:#"%# %i",string,n];
}
NSLog(#"string is %#", string);
Outputs to 6.7k not 10k.

See if you get different results with:
NSLog(#"json is %#", json.description);
Or to rule out NSLog altogether, maybe breakpoint the code there, and right click on json in the variables pane of the debug area and choose Print description of "json"
My experience is NSJSONSerialization will return an error for malformed JSON.

This is some silly feature in Xcode itself it seems. This define works for the full NSLog:
#define NSLog(FORMAT, ...) printf("%s\n", [[NSString stringWithFormat:FORMAT, ##__VA_ARGS__] UTF8String]);
Taken from here:
NSLog on devices in iOS 10 / Xcode 8 seems to truncate? Why?
How many developers will spend time looking for imaginary bugs in the lazy logger...
For those coming afterwards, I'm running Xcode 9.0.

Related

Extract data from Json into Label Text IOS

So I am using the pokedex API as a learning curve for IOS and web services,
Here is my didrecivedata when the connection completes
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data{
//If the resposne recieved is good the call this function
// NSLog(#"data is %#", data);
//NSString *myString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
//NSLog(#"string is %#", myString);
//Put data into a string
NSError *e = nil;
pokeDictionary = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableContainers error:&e];
NSLog(#"dictionary is %#", pokeDictionary);
}
This outputs Json to the console, I can log it into the console like this
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
// do something with the data
// receivedData is declared as a method instance elsewhere
NSLog(#"Succeeded!");
NSLog(#"The Pokemon's name is %#", pokeDictionary[#"name"]);
NSLog(#"The Pokemon's attack is %#", pokeDictionary[#"attack"]);
NSLog(#"The Pokemon's speed is %#", pokeDictionary[#"speed"]);
}
However tried to extract Json into text fields like this
{
self.pokemonAttack.text = (#"The Pokemon's speed is %#", pokeDictionary[#"name"]);
self.pokemonAttack.text = (#"The Pokemon's speed is %#", pokeDictionary[#"attack"]);
self.pokemonSpeed.text = (#"The Pokemon's speed is %#", pokeDictionary[#"speed"]);
}
Error is "expression result unused", I guess my main issue is I am not comfortable with objective-c and just hacking around in IOS. For this I apologise and understand the comments of saying do objective-c courses
If you can point me in the right direction I can continue my trial by fire, I guess I should also be moving to swift soon
First of all you should know that the delegate method connection:didReceiveData: may be called multiple times as the connection loads the data incrementally. It may be called once if your returned data is very short, but it will most likely break at some point as you'll end up trying to parse incomplete data.
Regarding the warning you're getting - you just can't format strings like that. You're trying to use string formatting like you're calling NSLog, but the NSLog method does the formatting for you. You need to do something like this:
self.pokemonAttack.text = [NSString stringWithFormat:#"The Pokemon's speed is %#", pokeDictionary[#"speed"]];

Why is my app crashing on iPhone 4S because of Core Data request execute?

I have an app that works fine on the simulator 6.1, works fine on the iPhone5 and iPad3 on iOS6.1 but when run on iPhone4S it crashes in this method with Exc Bad Access:
-(void)parsePlistIntoCD{
self.managedObjectContext = [[SDCoreDataController sharedInstance] backgroundManagedObjectContext];
// 3: Now put the plistDictionary into CD...create get ManagedObjectContext
NSManagedObjectContext *context = self.managedObjectContext;
NSError *error;
//Create Request & set Entity for request
NSFetchRequest *holidayRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *topicEntityDescription = [NSEntityDescription entityForName:#"Holiday" inManagedObjectContext:context];
[holidayRequest setEntity:topicEntityDescription];
//Create new NSManagedObject
//Holiday *holidayObjectToSeed = nil;
Holiday *newHoliday = nil;
//Execute fetch just to make sure?
NSArray *holidayFetchedArray = [context executeFetchRequest:holidayRequest error:&error];
**if (error) NSLog(#"Error encountered in executing topic fetch request: %#", error); // if I comment this line out it reaches as far as the next bold line**
// No holidays in database so we proceed to populate the database
if ([holidayFetchedArray count] == 0) {
//Get path to plist file
NSString *holidaysPath = [[NSBundle mainBundle] pathForResource:#"PreloadedFarsiman" ofType:#"plist"];
//Put data into an array (with dictionaries in it)
NSArray *holidayDataArray = [[NSArray alloc] initWithContentsOfFile:holidaysPath];
**NSLog(#"holidayDataArray is %#", holidayDataArray);**
//Get number of items in that array
int numberOfTopics = [holidayDataArray count];
//Loop thru array items...
for (int i = 0; i<numberOfTopics; i++) {
//get each dict at each node
NSDictionary *holidayDataDictionary = [holidayDataArray objectAtIndex:i];
//Insert new object
newHoliday = [NSEntityDescription insertNewObjectForEntityForName:#"Holiday" inManagedObjectContext:context];
//Parse all keys in each dict object
[newHoliday setValuesForKeysWithDictionary:holidayDataDictionary];
//Save and or log error
[context save:&error];
if (error) NSLog(#"Error encountered in saving topic entity, %d, %#, Hint: check that the structure of the pList matches Core Data: %#",i, newHoliday, error);
};
}
//set bool that specifies the coredata has been populated from plist already
NSString *bundleVersion = [[NSBundle mainBundle] objectForInfoDictionaryKey:(NSString *)kCFBundleVersionKey];
NSString *appFirstStartOfVersionKey = [NSString stringWithFormat:#"first_start_%#", bundleVersion];
NSUserDefaults *prefs = [NSUserDefaults standardUserDefaults];
[prefs setObject:#(YES) forKey:appFirstStartOfVersionKey];
[prefs synchronize];
}
Why only on 4S? It gives no console log and the last know method traversed in this one above. Here is a pic:
And as mentioned above, if I uncomment that NSLog line it reaches as far as logging the array, as shown in the pic. If I leave it in it stops at that line.
NSArray *holidayFetchedArray = [context executeFetchRequest:holidayRequest error:&error];
if (error)
NSLog(#"Error encountered in executing topic fetch request: %#", error);
No no no no no. I know this is a difficult pattern, but please let's try to do it right. Not if (error). error could be anything (esp. under non-ARC). The test is if (!holidayFetchedArray).
For all of these methods that return a value and also take an NSError** by indirection, you test the result to see if it is nil. If it is, then there was an error because returning nil is the sign that there was an error. Then and only then you may touch the error meaningfully.
The docs are always quite clear about this, though it is true that a fog can come over one's eyes at the critical instance, so I've added some comments in italic brackets to call out the key points:
request
A fetch request that specifies the search criteria for the
fetch.
error
If there is a problem executing the fetch, upon return
contains an instance of NSError that describes the problem.
[And if there is no problem executing the fetch, contains garbage so don't touch it!]
Return Value
An array of objects that meet the criteria specified by request
fetched from the receiver and from the persistent stores associated
with the receiver’s persistent store coordinator. If an error occurs,
returns nil. [And that, forsooth, is the sign that an error did occur.] If no objects match the criteria specified by request,
returns an empty array.
This might be the cause of your trouble or it might not, but you must fix it now. I want you to go through all your code looking for NSError* variables declared for use in this pattern and fix all of them! Thank you. Here endeth the lesson.
This is a stab in the dark b/c you haven't identified the line of code where the crash occurs. I recommended you set a breakpoint and then step through until you hit the crash. If what I say below doesn't resolve the issue then edit your post and add more info about where the crash occurs and we'll go from there.
Here's something to check. The line:
[newHoliday setValuesForKeysWithDictionary:holidayDataDictionary]
may be crashing if any of the keys in holidayDataDictionary aren't valid for an instance of the Holiday class.
With regard to your question about why it only crashes on your iPhone 4S there's not enough data to explain that yet. Depending on how you've been doing testing and core data migration (if at all) you may have a model inconsistency on that device, though I don't see anything in the screen shot you posted pointing me in that direction. I would try uninstalling/reinstalling your app and see if the crash is still iPhone 4S only.

How to get json data in ios 6.1 xcode 4.6

How do I get data for the link: https://itunes.apple.com/us/rss/topalbums/limit=10/json using ios6.1 xcode 4.6.
Most of the codes are for ios5 and few use jsonKit. But does ios has any inbuilt json parsing now?
I am looking forward for using only for ios6.1 and not older versions.
NSError *requestError = NULL;
NSDictionary *myDict = [NSJSONSerialization JSONObjectWithData:responseData options:kNilOptions error:&requestError];
if (requestError){
//An error occurred.
}
The return type of +JSONObjectWithData is id. It could return an NSDictionary or an NSArray. Choose whichever fits your JSON data structure.
Where responseData is, well, the data from your response. If you have a string you want to parse, convert it to NSData: https://stackoverflow.com/a/6188605/985050

App gets slow when parsing image using json in ios 5

I'm new to ios development.My app gets slower when i'm parsing image using json parser in ios 5.
Please could anybody help to solve this problem.
-(NSDictionary *)Getdata
{
NSString *urlString = [NSString stringWithFormat:#"url link"];
urlString = [urlString stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
NSURL *url = [NSURL URLWithString:urlString];
NSData* data = [NSData dataWithContentsOfURL:url];
NSError* error;
NSDictionary* json;
if (data) {
json = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:&error];
NSLog(#"json...%#",json);
}
if (error) {
NSLog(#"error is %#", [error localizedDescription]);
// Handle Error and return
// return;
}
return json;
}
Your description of the problem isn't exactly helpful. It's unclear to me if everything in your app is slow, or just certain operations; if you exprience a slow action and then it becomes fast again or if it continues to perform slowly.
Whatever, the general rule is to performan all network communication including the parsing of the answer on a separate thread, i.e. not on the main thread that is responsible for managing the user interface. That way the app remains responsive and appears to be fast.
If you can download the images separately, you can already display the result and put a placeholder where the image will appear. Later, when you have received the image you remove the placeholder and put the image there.
This line is probably the culprit.
NSData* data = [NSData dataWithContentsOfURL:url];
If you're calling this on the main thread (and because you haven't mentioned threads at all I suspect that you are) it will block everything and wait until the server has responded.
This is a spectacularly bad experience for the user :)
You need to do all of this on a background thread and notify the main thread when you're done. There's a couple of ways of doing this (NSOperation etc) but the simplest is just this :
// Instead of calling 'GetData', do this instead
[self performSelectorOnBackgroundThread:#selector(GetData) withObject:nil];
// You can't return anything from this because it's going to be run in the background
-(void)GetData {
...
...
// Instead of 'return json', you need to pass it back to the main thread
[self performSelectorOnMainThread:#selector(GotData:) withObject:json waitUntilDone:NO];
}
// This gets run on the main thread with the JSON that's been got and parsed in the background
- (void)GotData:(NSDictionary *)json {
// I don't know what you were doing with your JSON but you should do it here :)
}

iOS 5 Json and utf8 problems

I use the iOS 5 JSON features to load data from web.
My target is to get some twitter data - the data is filtered via web and I get it via the following url:
http://botpwn.org/ios/getfollowers.json?uid=63964843
Thats working and I dont have problems there - but my problems begin with parsing the data in my app.
I load the data here
dispatch_async(kBgQueue, ^{
NSData* data = [NSData dataWithContentsOfURL:[NSURL URLWithString:[NSString stringWithFormat:#"http://botpwn.org/ios/getfollowers.json?uid=%#", my_uid]]];
[self performSelectorOnMainThread:#selector(fetchedData:)
withObject:data waitUntilDone:YES];
});
-(void)fetchedData:(NSData *)responseData {
NSError* error;
NSDictionary* json = [NSJSONSerialization
JSONObjectWithData:responseData
options:kNilOptions
error:&error];
latestFollower = [json objectForKey:#"followers"]; //2
for (int i = 0; i < [latestFollower count]; i++){
[temp addObject:[latestFollower objectAtIndex:i]];
}
if (latestFollower == nil || latestFollower.count == 0){
NSLog(#"No followers");
}
}
And now I always get the answer that I have an empty latestFollower array - and I know that the problem is, that some names (not screennames) of twitter users contain special chars and iOS can't parse it.
I searched for solutions (set the php header to utf8 etc.) but nothing helps.
Maybe you have an idea how to parse it right, or maybe I'm doing something wrong but i don't get it.
EDIT: Just fixed it myself - finally I used a tool (http://jsonlint.com/) to check whether there is an error in the json output and yes - it was. Thanks for your ideas ! :)
Just fixed it myself - finally I used a tool (http://jsonlint.com/) to check whether there is an error in the json output and yes - it was. Thanks for your ideas ! :)

Resources