I am doing JSON parsing and I want to show my parsed data in a UITableView.
For that, I am trying to assign parsed data from NSMutableDictionary to NSArray to show in the table view but the array returns null.
Here my array returns null value;
NSMutableDictionary *tempDict1;
NSArray *arr = [[tempDict1 valueForKey:#"rates"] componentsSeparatedByString:#";"];
code
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
[connection release];
NSString *responseString = [[NSString alloc] initWithData:responseData encoding:NSUTF8StringEncoding];
self.responseData = nil;
// NSArray *latestrates = [[responseString JSONValue] objectForKey:#"rates"];
[responseString release];
values = [responseString JSONValue];
array = [[NSMutableArray alloc] init];
array = [values valueForKey:#"rates"];
NSLog(#"array values:--> %#",array);
tempDict1 = (NSMutableDictionary *)array;
arr = [[tempDict1 valueForKey:#"rates"] componentsSeparatedByString:#";"];
NSString *subStar = #"=";
NSMutableArray *arrTitle = [[NSMutableArray alloc] init];
NSMutableArray *arrValues = [[NSMutableArray alloc] init];
[arrTitle removeAllObjects];
[arrValues removeAllObjects];
for (int i=0; i<[arr count]-1; i++)
{
[arrTitle addObject:[[arr objectAtIndex:i] substringToIndex:NSMaxRange([[arr objectAtIndex:i] rangeOfString:subStar])-1]];
[arrValues addObject:[[arr objectAtIndex:i] substringFromIndex:NSMaxRange([[arr objectAtIndex:i] rangeOfString:subStar])]];
NSLog(#"arrTitle is:--> %#",arrTitle);
}
tempDict1 = (NSMutableDictionary*)[array objectAtIndex:0];
array = [values valueForKey:#"rates"];
NSLog(#"tempDict--%#",tempDict1);
[arr retain];
[tbl_withData reloadData];
}
Try editing fourth line in connectionDidFinishLoading to
values = [responseString JSONFragments];
NSError *error = nil;
NSArray *array = [NSJSONSerialization JSONObjectWithData:responseData options:NSJSONReadingMutableContainers error:&error];
NSLog(#"Your data - %#",array);
Now you can get it according to data format.
EDIT
I think you also dont know how to get a webResponse.
So here is a way to get webResponse -
First set XML delegate in your ViewController.h class
and declare a NSMutableData globaly
#interface ViewController : UIViewController<NSXMLParserDelegate>
#property(nonatomic, retain)NSMutableData *responseData;
#end
Now synthesized this responseData in your ViewController.m class
#synthesize responseData = _responseData;
Now you can send request on server in viewDidLoad: method its up to you in which method you want to send it.
-(void)viewDidLoad
{
NSString *urlString = [NSString stringWithFormat:#"http://EnterYourURLHere"];
NSURL *URL = [NSURL URLWithString:urlString];
NSMutableURLRequest *urlRequest = [[NSMutableURLRequest alloc]init];
[urlRequest setURL:URL];
[urlRequest setHTTPMethod:#"POST"];
[urlRequest setValue:#"application/x-www-form-urlencoded" forHTTPHeaderField:#"Content-type"];
NSURLConnection *urlConnection = [[NSURLConnection alloc]initWithRequest:urlRequest delegate:self];
if(!urlConnection)
{
[[[UIAlertView alloc]initWithTitle:#"OOoopppssS !!" message:#"There is an error occured. Please check your internet connection or try again." delegate:self cancelButtonTitle:#"OK" otherButtonTitles:nil, nil] show];
}
}
#pragma mark - Parsing delegate methods
-(void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
self.responseData = [[NSMutableData alloc]init];
[self.responseData setLength:0];
}
-(void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
[self.responseData appendData:data];
}
-(void)connectionDidFinishLoading:(NSURLConnection *)connection
{
//Now parse your data here -
NSError *error = nil;
NSArray *array = [NSJSONSerialization JSONObjectWithData:self.responseData options:NSJSONReadingMutableContainers error:&error];
NSLog(#"Your data - %#",array);
}
Related
I am trying to load web content asynchronously. I have a large amount of web calls in my viewdidappear method and my app is very unresponsive. I understand the concepts of synchronous and asynchronous loading of content, but don't know how to tell if this is being done asynchronously. The code below is simply embedded in my viewdidappear method, and I assume it is loading synchronously. How would I edit this to make it load asynchronously? Thank you all!
NSString *strURLtwo = [NSString stringWithFormat:#"http://website.com/json.php?
id=%#&lat1=%#&lon1=%#",id, lat, lon];
NSData *dataURLtwo = [NSData dataWithContentsOfURL:[NSURL URLWithString:strURLtwo]];
NSArray *readJsonArray = [NSJSONSerialization JSONObjectWithData:dataURLtwo options:0
error:nil];
NSDictionary *element1 = [readJsonArray objectAtIndex:0];
NSString *name = [element1 objectForKey:#"name"];
NSString *address = [element1 objectForKey:#"address"];
NSString *phone = [element1 objectForKey:#"phone"];
You can use NSURLConnectionDelegate:
// Your public fetch method
-(void)fetchData
{
NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:#"http://website.com/json.php?id=%#&lat1=%#&lon1=%#",id, lat, lon]];
// Put that URL into an NSURLRequest
NSMutableURLRequest *req = [NSMutableURLRequest requestWithURL:url];
// Create a connection that will exchange this request for data from the URL
connection = [[NSURLConnection alloc] initWithRequest:req
delegate:self
startImmediately:YES];
}
Implement the delegate methods:
- (void)connection:(NSURLConnection *)conn didReceiveData:(NSData *)data
{
// Add the incoming chunk of data to the container we are keeping
// The data always comes in the correct order
[jsonData appendData:data];
}
- (void)connectionDidFinishLoading:(NSURLConnection *)conn
{
// All data is downloaded. Do your stuff with the data
NSArray *readJsonArray = [NSJSONSerialization jsonData options:0 error:nil];
NSDictionary *element1 = [readJsonArray objectAtIndex:0];
NSString *name = [element1 objectForKey:#"name"];
NSString *address = [element1 objectForKey:#"address"];
NSString *phone = [element1 objectForKey:#"phone"];
jsonData = nil;
connection = nil;
}
// Show AlertView if error
- (void)connection:(NSURLConnection *)conn didFailWithError:(NSError *)error
{
connection = nil;
jsonData = nil;
NSString *errorString = [NSString stringWithFormat:#"Fetch failed: %#", [error localizedDescription]];
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:#"Error" message:errorString delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil, nil];
[alertView show];
}
For asynchronous web content loading, I recommend you to use AFNetworking . It'll solve lots of your major headache of networking in future. How to do:
1) subclass AFHTTPCLient, for example:
//WebClientHelper.h
#import "AFHTTPClient.h"
#interface WebClientHelper : AFHTTPClient{
}
+(WebClientHelper *)sharedClient;
#end
//WebClientHelper.m
#import "WebClientHelper.h"
#import "AFHTTPRequestOperation.h"
NSString *const gWebBaseURL = #"http://whateverBaseURL.com/";
#implementation WebClientHelper
+(WebClientHelper *)sharedClient
{
static WebClientHelper * _sharedClient = nil;
static dispatch_once_t oncePredicate;
dispatch_once(&oncePredicate, ^{
_sharedClient = [[self alloc] initWithBaseURL:[NSURL URLWithString:gWebBaseURL]];
});
return _sharedClient;
}
- (id)initWithBaseURL:(NSURL *)url
{
self = [super initWithBaseURL:url];
if (!self) {
return nil;
}
[self registerHTTPOperationClass:[AFHTTPRequestOperation class]];
return self;
}
#end
2) Request asynchronously your web content, put this code in any relevant part
NSString *testNewsURL = #"http://whatever.com";
NSURL *url = [NSURL URLWithString:testNewsURL];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
AFHTTPRequestOperation *operationHttp =
[[WebClientHelper sharedClient] HTTPRequestOperationWithRequest:request success:^(AFHTTPRequestOperation *operation, id responseObject)
{
NSString *szResponse = [[[NSString alloc] initWithData:responseObject encoding:NSUTF8StringEncoding] autorelease];
NSLog(#"Response: %#", szResponse );
//PUT your code here
}
failure:^(AFHTTPRequestOperation *operation, NSError *error)
{
NSLog(#"Operation Error: %#", error.localizedDescription);
}];
[[WebClientHelper sharedClient] enqueueHTTPRequestOperation:operationHttp];
The code below only works if my JSON data is a series of integers, e.g. [11,12,13]. How could I get it to retrieve a message/phrase instead?
- (IBAction)checkmessages:(id)sender
{
responseData = [[NSMutableData data] retain];
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:#"file:///Users/Alex/Desktop/Test.json"]];
[[NSURLConnection alloc] initWithRequest:request delegate:self];
}
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
[connection release];
NSString *responseString = [[NSString alloc] initWithData:responseData encoding:NSUTF8StringEncoding];
[responseData release];
NSError *error;
SBJSON *json = [[SBJSON new] autorelease];
NSArray *luckyNumbers = [json objectWithString:responseString error:&error];
[responseString release];
if (luckyNumbers == nil)
label.text = [NSString stringWithFormat:#"JSON parsing failed: %#", [error localizedDescription]];
else {
NSMutableString *text = [NSMutableString stringWithString:#"Latest Message:\n"];
for (int i = 0; i < [luckyNumbers count]; i++)
[text appendFormat:#"%#\n", [luckyNumbers objectAtIndex:i]];
label.text = text;
}
}
EDIT:
When my JSON File looks like: [10,11,12], it works fine, but if I change it to: [Message 1,Message 2], I get the error: "JSON Parsing Failed: Expected value while parsing array"
Your JSON looks malformed,
[Message 1,Message 2]
should be
["Message 1", "Message 2"]
"Strings" in JSON must be enclosed in quotes ("").
I am using the code in this question NSURLConnection download large file (>40MB) to download a KML file and load the data in my MKMap using the KMLViewer of Apple.KML files are small <200KB so KMLViewer is just fine.The code provided in the question should be fine too exept the fact that when the I click the button (that should make the request of the url and then load the data in the map) the map just goes to location 0,0 ,zooming tremendously and so all I can see is a black map.What is going wrong? What should I do?
Here is the code:
(By the way, I have two connections, because one uses JSON to get Google search results for locations from a UIsearchBar.)
EDIT 1
//In the ViewController.m
-(void) searchCoordinatesForAddress:(NSString *)inAddress //for Google location search
{
NSMutableString *urlString = [NSMutableString stringWithFormat:#"http://maps.google.com/maps/geo?q=%#?output=json",inAddress];
[urlString setString:[urlString stringByReplacingOccurrencesOfString:#" " withString:#"+"]];
NSURL *url = [NSURL URLWithString:urlString];
NSURLRequest *request = [[NSURLRequest alloc] initWithURL:url];
NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:request delegate:self];
[connection release];
[request release];
}
-(void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
[webData setLength:0]; //webData in the header file
}
-(void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
if ( connection = theConnection ) //theConnection is created before
{
[webData appendData:data];
}
NSString *jsonString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSDictionary *results = [jsonString JSONValue];
NSArray *placemark = [results objectForKey:#"Placemark"];
NSArray *coordinates = [[placemark objectAtIndex:0] valueForKeyPath:#"Point.coordinates"];
double longitude = [[coordinates objectAtIndex:0] doubleValue];
double latitude = [[coordinates objectAtIndex:1] doubleValue];
NSLog(#"Latitude - Longitude: %f %f", latitude, longitude);
[self zoomMapAndCenterAtLatitude:latitude andLongitude:longitude];
[jsonString release];
}
-(void)connectionDidFinishLoading:(NSURLConnection *)connection {
NSString *fileName = [[[NSURL URLWithString:kmlStr] path] lastPathComponent];
NSArray *pathArr = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *folder = [pathArr objectAtIndex:0];
NSString *filePath = [folder stringByAppendingPathComponent:fileName];
NSURL *fileURL = [NSURL fileURLWithPath:filePath];
NSError *writeError = nil;
[webData writeToURL: fileURL options:0 error:&writeError];
if( writeError) {
NSLog(#" Error in writing file %#' : \n %# ", filePath , writeError );
return;
}
NSLog(#"%#",fileURL);
}
-(void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Error !" message:#"Error has occured, please verify internet connection.." delegate:nil cancelButtonTitle:#"Ok" otherButtonTitles:nil];
[alert show];
[alert release];
}
-(IBAction)showKmlData:(id)sender
{
NSString *path = [[NSBundle mainBundle] pathForResource:#"KMLGenerator" ofType:#"kml"];
kml = [[KMLParser parseKMLAtPath:path] retain];
NSArray *overlays = [kml overlays];
[mapview addOverlays:overlays];
NSArray *annotations = [kml points];
[mapview addAnnotations:annotations];
MKMapRect flyTo = MKMapRectNull;
for (id <MKOverlay> overlay in overlays) {
if (MKMapRectIsNull(flyTo)) {
flyTo = [overlay boundingMapRect];
} else {
flyTo = MKMapRectUnion(flyTo, [overlay boundingMapRect]);
}
}
for (id <MKAnnotation> annotation in annotations) {
MKMapPoint annotationPoint = MKMapPointForCoordinate(annotation.coordinate);
MKMapRect pointRect = MKMapRectMake(annotationPoint.x, annotationPoint.y, 0, 0);
if (MKMapRectIsNull(flyTo)) {
flyTo = pointRect;
} else {
flyTo = MKMapRectUnion(flyTo, pointRect);
}
}
mapview.visibleMapRect = flyTo;
}
EDIT 2 I have done modifications,now it doesn't go anywhere, it crashes because it doesn't find KMLGenerator.kml file (path)
-(void)showData
{
NSString *url = /*kmlStr;*/#"http://www.ikub.al/hartav2/handlers/kmlgenerator.ashx?layerid=fc77a5e6-5985-4dd1-9309-f026d7349064&kml=1";
NSURL *path = [NSURL URLWithString:url];
NSURLRequest *request = [[NSURLRequest alloc] initWithURL:path];
NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:request delegate:self];
theConnection = connection;
[connection release];
[request release];
}
//Search Coordinates for address entered in the searchBar
-(void) searchCoordinatesForAddress:(NSString *)inAddress
{
NSMutableString *urlString = [NSMutableString stringWithFormat:#"http://maps.google.com/maps/geo?q=%#?output=json",inAddress];
[urlString setString:[urlString stringByReplacingOccurrencesOfString:#" " withString:#"+"]];
NSURL *url = [NSURL URLWithString:urlString];
NSURLRequest *request = [[NSURLRequest alloc] initWithURL:url];
NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:request delegate:self];
[connection release];
[request release];
}
-(void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
[webData setLength:0]; //Here i get an alert: NSData may not respond to -setLength
//webData is a NSData object.
}
-(void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
[webData appendData:data]; //Here i get an alert: NSData may not respond to -appendData
}
-(void)connectionDidFinishLoading:(NSURLConnection *)connection {
if ( connection == theConnection ) //"theConnection" is for kml file download
{
NSString *fileName = [[[NSURL URLWithString:kmlStr] path] lastPathComponent];
NSArray *pathArr = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *folder = [pathArr objectAtIndex:0];
NSString *filePath = [folder stringByAppendingPathComponent:fileName];
NSURL *fileURL = [NSURL fileURLWithPath:filePath];
NSError *writeError = nil;
[webData writeToURL: fileURL options:0 error:&writeError];
if( writeError) {
NSLog(#" Error in writing file %#' : \n %# ", filePath , writeError );
return;
}
NSLog(#"%#",fileURL);
}
else //it's a geocoding result
{
NSString *jsonString = [[NSString alloc] initWithData:webData encoding:NSUTF8StringEncoding];
NSDictionary *results = [jsonString JSONValue];
//check the Google geocode error code before looking for coordinates...
NSDictionary *statusDict = [results objectForKey:#"Status"];
NSNumber *errorCode = [statusDict objectForKey:#"code"];
if ([errorCode intValue] == 200) //200 is "success"
{
NSArray *placemark = [results objectForKey:#"Placemark"];
NSArray *coordinates = [[placemark objectAtIndex:0] valueForKeyPath:#"Point.coordinates"];
double longitude = [[coordinates objectAtIndex:0] doubleValue];
double latitude = [[coordinates objectAtIndex:1] doubleValue];
NSLog(#"Latitude - Longitude: %f %f", latitude, longitude);
[self zoomMapAndCenterAtLatitude:latitude andLongitude:longitude];
}
else
{
NSLog(#"geocoding error %#", errorCode);
}
[jsonString release];
}
}
-(void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Error!" message:#"Error has occured, please verify internet connection..." delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil];
[alert show];
[alert release];
}
- (IBAction)showKmlData:(id)sender
{
NSString *path = [[NSBundle mainBundle] pathForResource:#"KMLGenerator" ofType:#"kml"];
kml = [[KMLParser parseKMLAtPath:path] retain];
NSArray *annotationsImmut = [kml points];
NSMutableArray *annotations = [annotationsImmut mutableCopy];
//[mapview addAnnotations:annotations];
[self filterAnnotations:annotations];
MKMapRect flyTo = MKMapRectNull;
for (id <MKAnnotation> annotation in annotations) {
MKMapPoint annotationPoint = MKMapPointForCoordinate(annotation.coordinate);
MKMapRect pointRect = MKMapRectMake(annotationPoint.x, annotationPoint.y, 0, 0);
if (MKMapRectIsNull(flyTo)) {
flyTo = pointRect;
} else {
flyTo = MKMapRectUnion(flyTo, pointRect);
}
}
mapview.visibleMapRect = flyTo;
}
It's still hard to pinpoint the cause but there are some problems with the code you posted.
First, in didReceiveData, this line is probably not what you want:
if ( connection = theConnection ) //theConnection is created before
The single = is doing an assignment instead of an equality check (which is ==).
Fixing that, however, is not the solution (the other problem is in connectionDidFinishLoading).
The didReceiveData method is not the right place to process your geocoding JSON result. The didReceiveData method can be called multiple times for a single url request. So it's possible that the geocoding results (just like the kml file) may be delivered in multiple chunks which cannot be processed individually in that method. The data in that method may be a partial stream of the complete result which will not make sense to process. You should only be appending the data to an NSMutableData object or, as an answer to the linked question suggests, write the data to a file.
The data can only be processed/parsed in the connectionDidFinishLoading method.
Since you are using the same connection delegate for both the kml file download and the geocoding, they both call the same connectionDidFinishLoading method. In that method, you are not checking which connection it is being called for.
When the geocoding url request finishes and calls connectionDidFinishLoading, that method takes whatever is in webData (possibly the geocoding results or empty data) and writes it to the kmlStr file. This is probably what causes the kml data to show "nothing".
You have to move the processing of the geocoding results to connectionDidFinishLoading and check there what connection is calling it.
For example:
-(void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
[webData appendData:data];
}
-(void)connectionDidFinishLoading:(NSURLConnection *)connection {
if ( connection == theConnection ) //"theConnection" is for kml file download
{
NSString *fileName = [[[NSURL URLWithString:kmlStr] path] lastPathComponent];
NSArray *pathArr = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *folder = [pathArr objectAtIndex:0];
NSString *filePath = [folder stringByAppendingPathComponent:fileName];
NSURL *fileURL = [NSURL fileURLWithPath:filePath];
NSError *writeError = nil;
[webData writeToURL: fileURL options:0 error:&writeError];
if( writeError) {
NSLog(#" Error in writing file %#' : \n %# ", filePath , writeError );
return;
}
NSLog(#"%#",fileURL);
}
else //it's a geocoding result
{
NSString *jsonString = [[NSString alloc] initWithData:webData encoding:NSUTF8StringEncoding];
NSDictionary *results = [jsonString JSONValue];
//check the Google geocode error code before looking for coordinates...
NSDictionary *statusDict = [results objectForKey:#"Status"];
NSNumber *errorCode = [statusDict objectForKey:#"code"];
if ([errorCode intValue] == 200) //200 is "success"
{
NSArray *placemark = [results objectForKey:#"Placemark"];
NSArray *coordinates = [[placemark objectAtIndex:0] valueForKeyPath:#"Point.coordinates"];
double longitude = [[coordinates objectAtIndex:0] doubleValue];
double latitude = [[coordinates objectAtIndex:1] doubleValue];
NSLog(#"Latitude - Longitude: %f %f", latitude, longitude);
[self zoomMapAndCenterAtLatitude:latitude andLongitude:longitude];
}
else
{
NSLog(#"geocoding error %#", errorCode);
}
[jsonString release];
}
}
(It's probably better to avoid using the same delegate for multiple connections. It would be cleaner to move the geocoding out to another class with its own connection object and delegate methods. By the way, iOS5 has geocoding built-in so you don't need to do this yourself. See the CLGeocoder class.)
I added a check for the Google error code. It's possible the address queried returns no results in which case there will be no placemark coordinates in which case the latitude and longitude will get set to zero. This is another possible cause of the map going to 0,0.
It also seems you are using the deprecated v2 Google geocoder. This is the latest one but you may want to switch to using CLGeocoder instead unless you need to support iOS4 or earlier.
I have the following problem:
in header;
GDataXMLDocument *doc;
NSString *xmlBody;
#property (nonatomic,copy) NSString *xmlBody;
#property (nonatomic,retain) GDataXMLDocument *doc;
in m
#import "tchLoader.h"
#import "Variable.h"
#import "DisplayVariable.h"
#implementation tchLoader
#synthesize responseXMLData,lastLoadedResponseXMLData;
#synthesize conn;
#synthesize doc;
#synthesize xmlBody;
- (void)loadXML:(id<tchLoaderDelegate>)delegate {
NSString *theBaseXML= #"some xml code here"
if (self.xmlBody==nil){
self.xmlBody=theBaseXML;
}
_delegate = delegate;
/*
SCNetworkReachabilityFlags flags;
SCNetworkReachabilityRef reachability = SCNetworkReachabilityCreateWithName(NULL, [#"www.alues.com" UTF8String]);
SCNetworkReachabilityGetFlags(reachability, &flags);
// The reachability flags are a bitwise set of flags that contain the information about
// connection availability
BOOL reachable = ! (flags & kSCNetworkReachabilityFlagsConnectionRequired);
*/
NSString *soapMessage =self.xmlBody;
NSURL *url = [NSURL URLWithString:#"https://area.tch-values.com/soapmwp/mws"];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
NSString *msgLength = [NSString stringWithFormat:#"%d", [soapMessage length]];
[request addValue: #"text/xml; charset=utf-8" forHTTPHeaderField:#"Content-Type"];
[request addValue: #"http://www.tch-values.com/webservice" forHTTPHeaderField:#"SOAPAction"];
[request addValue: msgLength forHTTPHeaderField:#"Content-Length"];
[request setHTTPMethod:#"POST"];
[request setHTTPBody: [soapMessage dataUsingEncoding:NSUTF8StringEncoding]];
if ([NSURLConnection canHandleRequest:request] && true) {
self.conn = [[NSURLConnection alloc ]initWithRequest:request delegate:self];
if (self.conn) {
self.responseXMLData = [NSMutableData data];
}
}
}
-(void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
NSLog(#"ERROR with theConenction");
[self.doc release];
[self.conn release];
[self.responseXMLData release];
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
NSLog(#"DONE. Received Bytes: %d", [self.responseXMLData length]);
//[self.conn release];
if ([_delegate respondsToSelector:#selector(xmlDidFinishLoading)]) {
[_delegate xmlDidFinishLoading];
}
}
-(void)insertAnswers: (NSMutableArray*) answeredVariables{
for (Variable * variable in answeredVariables)
{
NSInteger pageID=[variable pageId];
//NSMutableArray *answers=[NSMutableArray arrayWithCapacity:[[variable variableValues] count]];
NSString *path = [NSString stringWithFormat:#"//inferenceresponse/state/variable[pageId=%d]/valuedefinition",pageID];
NSArray *valueElement = [doc nodesForXPath:path error:nil];
GDataXMLElement *valueDefinitionElement;
if (valueElement.count > 0) {
valueDefinitionElement= (GDataXMLElement *) [valueElement objectAtIndex:0];
}
GDataXMLElement * sourceElement = [GDataXMLNode elementWithName:#"source"];
[sourceElement addAttribute:[GDataXMLNode attributeWithName:#"type" stringValue:#"ask user"]];
GDataXMLElement * timeStampElement = [GDataXMLNode elementWithName:#"timestamp" stringValue:#"12345"];
[sourceElement addChild:timeStampElement];
GDataXMLElement * assignmentElement = [GDataXMLNode elementWithName:#"assignmentnumber" stringValue:#"6"];
for(NSString *answer in variable.variableValues){
GDataXMLElement * variableValueElement = [GDataXMLNode elementWithName:#"variablevalue"];
[variableValueElement addAttribute:[GDataXMLNode attributeWithName:#"value" stringValue:answer]];
[valueDefinitionElement addChild:variableValueElement];
}
[valueDefinitionElement addChild:sourceElement];
[valueDefinitionElement addChild:assignmentElement];
}
NSData *xmlData = self.doc.XMLData;
NSString *theXML = [[NSString alloc] initWithBytes:[xmlData bytes] length:[xmlData length] encoding:NSUTF8StringEncoding];
theXML =[theXML stringByReplacingOccurrencesOfString:#"inferenceresponse" withString:#"inferencerequest"];
theXML =[theXML stringByReplacingOccurrencesOfString:#"<SOAP-ENV:Envelope xmlns:SOAP-ENV=\"http://schemas.xmlsoap.org/soap/envelope/\">" withString:#"<SOAP-ENV:Envelope xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:SOAP-ENC=\"http://schemas.xmlsoap.org/soap/encoding/\" SOAP-ENV:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\" xmlns:SOAP-ENV=\"http://schemas.xmlsoap.org/soap/envelope/\"> "];
theXML =[theXML stringByReplacingOccurrencesOfString:#"xmlns=\"\"" withString:#"xmlns=\"http://www.tch-values.com/xml/webservice\""];
theXML =[theXML stringByReplacingOccurrencesOfString:#"<state goalreached=\"false\">" withString:#"<state goalreached=\"false\"> <value>PlanKB</value> <goalvariable>myGoal</goalvariable> "];
self.xmlBody=theXML;
[theXML release];
//[self.doc release];
NSLog(self.xmlBody);
}
- (NSMutableArray*)variablesForPageID:(NSString*)pageID {
NSMutableArray *variables = nil;
if (self.responseXMLData) {
variables = [NSMutableArray arrayWithCapacity:10];
NSData *xmlData = self.responseXMLData;
NSError *error;
self.doc=nil;
doc = [[GDataXMLDocument alloc] initWithData:xmlData options:0 error:&error];
if (self.doc == nil) {
return nil;
}
NSArray *status = [doc nodesForXPath:#"//inferenceresponse/state[#goalreached='true']" error:nil];
if([status count]==1){
self.xmlBody=nil;
Variable *variable=[[Variable alloc] init];
NSString *path = [NSString stringWithFormat:#"//inferenceresponse/state/displayvariables/display[#isDisplayShown='false']"];
NSArray *displayVariablesElements = [doc nodesForXPath:path error:nil];
NSMutableArray *disps=[[NSMutableArray alloc] init];
if(displayVariablesElements.count >0){
for(GDataXMLElement *disElement in displayVariablesElements){
DisplayVariable *disVar=[[DisplayVariable alloc] init];
NSArray *disPageid = [disElement nodesForXPath:#"#displayPageId" error:nil];
GDataXMLElement *Pageid = (GDataXMLElement *) [disPageid objectAtIndex:0];
disVar.displayPageId =Pageid.stringValue;
NSArray *disName = [disElement nodesForXPath:#"displayname" error:nil];
if(disName.count >0){
GDataXMLElement *disNam = (GDataXMLElement *) [disName objectAtIndex:0];
disVar.displayName =disNam.stringValue;
}
NSArray *disValue = [disElement nodesForXPath:#"displayvalue" error:nil];
if(disValue.count >0){
GDataXMLElement *disVal = (GDataXMLElement *) [disValue objectAtIndex:0];
disVar.displayValue =disVal.stringValue;
}
NSArray *disId = [disElement nodesForXPath:#"#id" error:nil];
GDataXMLElement *disIdEl = (GDataXMLElement *) [disId objectAtIndex:0];
disVar.pageId =[disIdEl.stringValue intValue];
[disps addObject:disVar];
[disVar release];
}
variable.displayVariables=disps;
[disps release];
}
variable.lastVariableofConsultation=YES;
[variables addObject:variable];
[variable release];
}
else{
NSArray *inferenceMembers = [doc nodesForXPath:#"//inferenceresponse/state/variable[not(valuedefinition/variablevalue)]" error:nil];
for (GDataXMLElement *variableElement in inferenceMembers) {
Variable *variable=[[Variable alloc] init];
NSArray *items = [variableElement nodesForXPath:#"domaindefinition/domain/enumType/domainitem" error:nil];
NSMutableArray *domainItems = [NSMutableArray arrayWithCapacity:items.count];
for (int i=0; i<items.count;i++) {
GDataXMLElement *domainItem = (GDataXMLElement *) [items objectAtIndex:i];
[domainItems addObject:domainItem.stringValue];
}
variable.domainItems=domainItems;
NSArray *names = [variableElement nodesForXPath:#"name/#name" error:nil];
if (names.count > 0) {
GDataXMLElement *nameElement = (GDataXMLElement *) [names objectAtIndex:0];
variable.variableName = nameElement.stringValue;
}
NSArray *pageId = [variableElement nodesForXPath:#"pageId" error:nil];
}
}
return variables;
}
- (void)dealloc {
[responseXMLData release] ;
[lastLoadedResponseXMLData release] ;
[conn release];
[doc release];
[xmlBody release];
[super dealloc];
}
#end
#import "tchLoader.h"
#import "Variable.h"
#import "DisplayVariable.h"
#implementation tchLoader
#synthesize responseXMLData,lastLoadedResponseXMLData;
#synthesize conn;
#synthesize doc;
#synthesize xmlBody;
If I [theXML release] it crashes, If I dont release theXML then it works perfect but I see memory leak in simulator Instruments tool. (There are also lots of memory leaks I see in this code but couldnt figure out by instrumnets tool what is going on)
This looks wrong:
[doc release];
Why are you releasing an object managed by a property?
In your #synthesize statements change them to:
#synthesize doc = doc_;
#synthesize xmlBody = xmlBody_;
Then fix all the resulting errors to go through the property, releasing the properties ONLY in dealloc.
Edit:
You say it crashes releasing theXML. This code is wrong:
NSString *theXML = [[NSString alloc] initWithBytes:[xmlData bytes] length:[xmlData length] encoding:NSUTF8StringEncoding];
theXML =[theXML stringByReplacingOccurrencesOfString:#"inferenceresponse" withString:#"inferencerequest"];
[theXML release];
You alloc a string, replace that variable with the "stringByReplacing..." call with a string that is autoreleased, then try to release the resulting string that is autoreleased which will crash. When you don't need to keep a string around after the method you are in, ALWAYS use autorelease. The correct code is:
NSString *theXML = [[[NSString alloc] initWithBytes:[xmlData bytes] length:[xmlData length] encoding:NSUTF8StringEncoding] autorelease];
theXML =[theXML stringByReplacingOccurrencesOfString:#"inferenceresponse" withString:#"inferencerequest"];
And take out [theXML release] - there will be no leak.
I think you should really switch to using ARC as soon as you possibly can... it will save you from a lot of such misunderstandings.
If you want to release an ivar/property(retain), this is not how to to it:
[self.doc release];
instead:
self.doc = nil;
One "problem" with singleton objects is that they appear to leak. If you create an object and never destroy it, Instruments says it's a leak, even if your intention was never to release it.
NSData *xmlData = doc.XMLData;
newXML = [[NSString alloc] initWithBytes:[xmlData bytes] length:[xmlData length]
encoding:NSUTF8StringEncoding];
What is your newXML? is it a ivar and synthesize it and retain it? if yes the compiler will automatically generate getter and setter methods.
NSData *xmlData = doc.XMLData;
self.newXML = [[NSString alloc] initWithBytes:[xmlData bytes] length:[xmlData length]
encoding:NSUTF8StringEncoding];
self.timestamp = nil;
If its not property then
NSString* newXML = [[NSString alloc] initWithBytes:[xmlData bytes] length:[xmlData length]
encoding:NSUTF8StringEncoding];
self.xmlBody=newXML;
[newXML release];
I have parsed JSON data the format of my JSON data is
http://www.krsconnect.no/community/api.html?method=bareListEventsByCategory&appid=620&category-selected=350&counties-selected=Vest-Agder,Aust-Agder
SBJsonParser *parser = [[SBJsonParser alloc] init];
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:#"http://www.krsconnect.no/community/api.html?method=categories&appid=620&mainonly=true"]];
NSData *response = [NSURLConnection sendSynchronousRequest:request returningResponse:nil error:nil];
NSString *json_string = [[NSString alloc] initWithData:response encoding:NSUTF8StringEncoding];
NSDictionary *object = [parser objectWithString:json_string error:nil];
NSArray *results = [parser objectWithString:json_string error:nil];
How about creating a data modal?
#interface book:NSObject {
NSString *catId;
NSString *bookName
}
create properties for these two instance vars.
#end
#implementation book
#synthesize catId,bookName;
- (id)init {
self = [super init];
}
- (id)initWithDictionary:(NSDictionary) dict {
self.catId = [dict valueForKey:#"categoryId"];
self.bookName = [dict valueForKey:#"name"];
}
- (void)dealloc {
[catId release];
[bookName release];
[super dealloc];
}
#end
and use it like this
NSMutableArray *bookArray = [[NSmutableArray alloc] initWithCapacity:0];
NSArray *results = [parser objectWithString:json_string error:nil];
for (int i=0; i<[results count]; i++) {
book *bookObject = [[book alloc] initWithDictionary:[results objectAtIndex:i]];
[bookArray addObject:bookObject];
[bookObject release];
}
I think you can do this by way
Adding dictionary to array.
for (NSDictionary *dict in mydict) {
[myArray addObject:dict];
}
You can do more modification and put the logic to set the values in array according
to key as well.
Hope this may help you.Well I haven't checked it now.But may get you to the solution.
Cheers.....