ASIHTTPRequest as instance variable and deallocating and releasing - iphone

"Informazioni.h file"
#interface Informazioni : UIViewController{
.....
ASIHTTRequest *mASIHTTPRequest;
}
#property (nonatomic, retain) ASIHTTRequest *mASIHTTPRequest;
----------------------------
#import "Informazioni.h"
#import "Globals.h"
#implementation Informazioni
#synthesize mImageViewImmagine;
....
#synthesize mASIHTTPRequest;
- (void)viewDidLoad {
[super viewDidLoad];
//start fetching based on id_prodotti
[self startFetch:mId_prodotto];
}
- (void) startFetch:(NSString *) pId_prodotto{
//activate ASIHTTPDownloadCache
NSURL *url = [NSURL URLWithString:[JSON_DESCRIZIONE stringByAppendingString:mId_prodotto]];//JSON_DATA
mASIHTTPRequest = [ASIHTTPRequest requestWithURL:url];
[mASIHTTPRequest setDelegate:self];
[mASIHTTPRequest startAsynchronous];
}
- (void)loadDataWithOperation: (NSString *) responseString{
NSLog(#"load data with operation");
NSDictionary *tempDict = [[responseString JSONValue] objectForKey:#"descrizione_prodotto"];
NSLog(#"descrizione_prodotto: %#",tempDict);
[self.mTableView performSelectorOnMainThread:#selector(reloadData) withObject:nil waitUntilDone:YES];
NSLog(#"reloadData called");
}
//start
- (void)requestFinished:(ASIHTTPRequest *)request{
NSLog(#"SUCCESS Http fetching");
// Operation Queue init (autorelease)
NSOperationQueue *queue = [NSOperationQueue new];
// Create our NSInvocationOperation to call loadDataWithOperation, passing in nil
NSInvocationOperation *operation = [[NSInvocationOperation alloc] initWithTarget:self
selector:#selector(loadDataWithOperation:)
object:[request responseString]];
// Add the operation to the queue
[queue addOperation:operation];
[operation release];
}
- (void)requestFailed:(ASIHTTPRequest *)request
{
NSError *error = [request error];
NSLog(#"%#",[error localizedDescription]);
/*
NSLog(#"Error: %#",[error localizedDescription]);
UIAlertView *alert = [[UIAlertView alloc]
initWithTitle:#"DIUNAMAISHOP"
message:[error localizedDescription]
delegate:self
cancelButtonTitle:#"OK"
otherButtonTitles:nil];
[alert show];
[alert release];
*/
/*
//remove activity indicator
if (self.mActivityIndicator.mFlag == YES) {
[self.mActivityIndicator.view
performSelectorOnMainThread:#selector(removeFromSuperview)
withObject:nil waitUntilDone:YES];
}
*/
}
-(void) queueFinished:(ASIHTTPRequest *) queue{
//You could release the queue here if you wanted
NSLog(#"Queue finished");
}
// end
........
- (void)dealloc {
//safely dealllocate
[mASIHTTPRequest clearDelegatesAndCancel];
[mASIHTTPRequest release];
.....
[super dealloc];
NSLog(#"Informazioni deallocated");
}
#end
I simply pushed this view then pressing back will dealloc/release the viewcontroller..
- the problem is it crashes when i press back while it is fetching
- how can i overcome this any suggestion would do tnx

mASIHTTPRequest = [ASIHTTPRequest requestWithURL:url];
You're not retaining this request. You need to retain it to have a valid reference reference to then be able to cancel and release it. Either add a retain, or use self.mASIHTTPRequest.

Related

Using AFNetworking and HTTP Basic Authentication

The following code successfully connects to my Ruby on Rails API and returns JSON using AFNetworking. What do I need to do to edit this to pass in a username and password so my API can use HTTP Basic Authentication?
I've read their documentation, but I am new to both Objective-C and AFNetworking and it isn't currently making sense.
NSURL *url = [[NSURL alloc] initWithString:#"http://localhost:3000/tasks.json"];
NSURLRequest *request = [[NSURLRequest alloc] initWithURL:url];
AFJSONRequestOperation *operation = [AFJSONRequestOperation
JSONRequestOperationWithRequest:request
success:^(NSURLRequest *request
, NSHTTPURLResponse *response
, id JSON) {
self.tasks = [JSON objectForKey:#"results"];
[self.activityIndicatorView stopAnimating];
[self.tableView setHidden:NO];
[self.tableView reloadData];
NSLog(#"JSON");
} failure:^(NSURLRequest *request
, NSHTTPURLResponse *response
, NSError *error
, id JSON) {
NSLog(#"Request Failed with Error: %#, %#", error, error.userInfo);
}];
[operation start];
Answer updated for AFNetworking 2.x
For AFNetworking 2.x:
In 2.x, they did away with AFHTTPClient, so you'll need to extend AFHTTPRequestOperationManager with your own class. Then, you can call that class from other code. For example, here's a sample class that extends the AFHTTPRequestOperationManager:
SBAPIManager.h:
#import "AFHTTPRequestOperationManager.h"
#interface SBAPIManager : AFHTTPRequestOperationManager
- (void)setUsername:(NSString *)username andPassword:(NSString *)password;
+ (SBAPIManager *)sharedManager;
#end
SBAPIManager.m:
#import "SBAPIManager.h"
#import "AFNetworkActivityIndicatorManager.h"
#implementation SBAPIManager
#pragma mark - Methods
- (void)setUsername:(NSString *)username andPassword:(NSString *)password
{
[self.requestSerializer clearAuthorizationHeader];
[self.requestSerializer setAuthorizationHeaderFieldWithUsername:username password:password];
}
#pragma mark - Initialization
- (id)initWithBaseURL:(NSURL *)url
{
self = [super initWithBaseURL:url];
if(!self)
return nil;
self.requestSerializer = [AFJSONRequestSerializer serializer];
[[AFNetworkActivityIndicatorManager sharedManager] setEnabled:YES];
return self;
}
#pragma mark - Singleton Methods
+ (SBAPIManager *)sharedManager
{
static dispatch_once_t pred;
static SBAPIManager *_sharedManager = nil;
dispatch_once(&pred, ^{ _sharedManager = [[self alloc] initWithBaseURL:[NSURL URLWithString:#"http://localhost:3000"]]; }); // You should probably make this a constant somewhere
return _sharedManager;
}
#end
Then, in your code, you can call it like this:
[[SBAPIManager sharedManager] setUsername:yourUsernameVariableHere andPassword:yourPasswordVariableHere];
[[SBAPIManager sharedManager] GET:#"/tasks.json" parameters:nil success:^(AFHTTPRequestOperation *operation, id responseObject) {
self.tasks = [responseObject objectForKey:#"results"];
[self.activityIndicatorView stopAnimating];
[self.tableView setHidden:NO];
[self.tableView reloadData];
NSLog(#"JSON");
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
// error stuff here
}];
For AFNetworking 1.x:
The best practice for this in AFNetworking is to extend the AFHTTPClient with your own class. Then, you can call that class from other code. For example, here's a sample class that extends the AFHTTPClient:
SBAPIManager.h:
#import "AFNetworking/AFHTTPClient.h"
#interface SBAPIManager : AFHTTPClient
- (void)setUsername:(NSString *)username andPassword:(NSString *)password;
+ (SBAPIManager *)sharedManager;
#end
SBAPIManager.m:
#import "SBAPIManager.h"
#import "AFJSONRequestOperation.h"
#import "AFNetworkActivityIndicatorManager.h"
#implementation SBAPIManager
#pragma mark - Methods
- (void)setUsername:(NSString *)username andPassword:(NSString *)password
{
[self clearAuthorizationHeader];
[self setAuthorizationHeaderWithUsername:username password:password];
}
#pragma mark - Initialization
- (id)initWithBaseURL:(NSURL *)url
{
self = [super initWithBaseURL:url];
if(!self)
return nil;
[self registerHTTPOperationClass:[AFJSONRequestOperation class]];
[self setDefaultHeader:#"Accept" value:#"application/json"];
[self setParameterEncoding:AFJSONParameterEncoding];
[[AFNetworkActivityIndicatorManager sharedManager] setEnabled:YES];
return self;
}
#pragma mark - Singleton Methods
+ (SBAPIManager *)sharedManager
{
static dispatch_once_t pred;
static SBAPIManager *_sharedManager = nil;
dispatch_once(&pred, ^{ _sharedManager = [[self alloc] initWithBaseURL:[NSURL URLWithString:#"http://localhost:3000"]]; }); // You should probably make this a constant somewhere
return _sharedManager;
}
#end
Then, in your code, you can call it like this:
[[SBAPIManager sharedManager] setUsername:yourUsernameVariableHere andPassword:yourPasswordVariableHere];
[[SBAPIManager sharedManager] getPath:#"/tasks.json" parameters:nil success:^(AFHTTPRequestOperation *operation, id responseObject) {
self.tasks = [responseObject objectForKey:#"results"];
[self.activityIndicatorView stopAnimating];
[self.tableView setHidden:NO];
[self.tableView reloadData];
NSLog(#"JSON");
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
// error stuff here
}];

iOS 5 NSURLConnection with NSOperationQueue - Providing UI Feedback

I need to make multiple NSURLConnections to a JSON Web Service. I would like each WS call to keep in UI informed, probably with a UIActivityIndicatorView and label. So far I've created a NSURLConnection helper class to handle the connection and placed the URL delegates in the View. This works great for updating the UI with a single WS call.
For multiple calls, I'm trying to use an NSOperationQueue. I'd like to setMaxConcurrentOperationCount to one on the queue so that each Operation executes one at a time. Here's the relevant code on my View Controller:
ViewController.m
#import "URLOperationHelper.h"
#implementation ViewController
- (IBAction)showPopup:(id)sender
{
// Dictonary holds POST values
NSMutableDictionary *reqDic = [NSMutableDictionary dictionary];
// Populate POST key/value pairs
[reqDic setObject:#"pw" forKey:#"Password"];
[reqDic setObject:#"ur" forKey:#"UserName"];
operationQueue = [[NSOperationQueue alloc] init];
[operationQueue setMaxConcurrentOperationCount:1];
[operationQueue cancelAllOperations];
[operationQueue setSuspended:YES];
URLOperationHelper *wsCall1 = [[URLOperationHelper alloc] initWithURL:#"urlString1" postParameters:reqDic urlDelegate:self];
URLOperationHelper *wsCall2 = [[URLOperationHelper alloc] initWithURL:#"urlString2" postParameters:reqDic urlDelegate:self];
[operationQueue addOperation:wsCall1];
[operationQueue addOperation:wsCall2];
}
// Did the URL Connection receive a response
-(void) connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
NSLog(#"Did receive response: %#", response);
NSHTTPURLResponse* httpResponse = (NSHTTPURLResponse*)response;
int code = [httpResponse statusCode];
// Handle status code here
webData = [[NSMutableData alloc]init];
}
// Did the URL Connection receive data
-(void) connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
NSLog(#"Did receive data: %#", [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]);
assert(webData != nil);
[webData appendData:data];
}
// Did the connection fail with an error?
-(void) connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
NSLog(#"%#", error);
}
// Executes after a successful connection and data download
-(void) connectionDidFinishLoading:(NSURLConnection *)connection
{
NSLog(#"Connection finished");
}
#end
And here is my URLOperationHelper.m
#implementation URLHelper
- (id)initWithURL:(NSString *)urlPath
postParameters:(NSMutableDictionary *)postParameters
urlParentDelegate:(id) pDelegate
{
if(self = [super init])
{
connectionURL = urlPath;
postParams = postParameters;
parentDelegate = pDelegate;
}
return self;
}
- (void)done
{
// Cancel the connection if present
if(urlConnection)
{
[urlConnection cancel];
urlConnection = nil;
}
// Alert
[self willChangeValueForKey:#"isExecuting"];
[self willChangeValueForKey:#"isFinished"];
executing = NO;
finished = YES;
[self willChangeValueForKey:#"isFinished"];
[self willChangeValueForKey:#"isExecuting"];
}
- (void)cancel
{
// Possibly add an NSError Property
[self done];
}
- (void)start
{
// Make sure this operation starts on the main thread
if(![NSThread isMainThread])
{
[self performSelectorOnMainThread:#selector(start) withObject:nil waitUntilDone:NO];
return;
}
// Make sure that the operation executes
if(finished || [self isCancelled])
{
[self done];
return;
}
[self willChangeValueForKey:#"isExecuting"];
executing = YES;
[self main];
[self willChangeValueForKey:#"isExecuting"];
}
- (void)main
{
NSError *error = nil;
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:postParams options:NSJSONWritingPrettyPrinted error:&error];
// Convert dictionary to JSON
NSString *requestJSON = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
NSLog(#"JSONRequest: %#", requestJSON);
// Declare Webservice URL, request, and return data
url = [[NSURL alloc] initWithString:connectionURL];
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:url];
NSData *requestData = [NSData dataWithBytes:[requestJSON UTF8String] length:[requestJSON length]];
// Build the request
[request setHTTPMethod:#"POST"];
[request setValue:[NSString stringWithFormat:#"%d", [requestData length]] forHTTPHeaderField:#"Content-Length"];
[request setValue:#"application/json" forHTTPHeaderField:#"Content-Type"];
[request setHTTPBody:requestData];
// Connect to Webservice
// Responses are handled in the delegates below
urlConnection = [[NSURLConnection alloc] initWithRequest:request delegate:parentDelegate startImmediately:YES];
}
- (BOOL)isConcurrent
{
return YES;
}
- (BOOL)isExecuting
{
return executing;
}
-(BOOL)isFinished
{
return finished;
}
#end
The problem that I'm having is the Start method for the URLOperation is never called. The OperationQueue is created and the Operations are called, but nothing happens after that, execution or thread wise.
Also, is this a correct line of thinking to provide UI feedback using NSOperationQueues like this? I.E. calling the NSURLDelegates from the Operation?
If you set setSuspended to YES before adding the Operations then your Operations will be queued into a suspended queue.. i suggest not to suspend the queue at
furthermore, your operation never ends anyway. You need to assign the operation itself as the delegate and implement all necessary delegate methods. In these methods you can forward the messages to your parentDelegate and decide when you are finished and call your done method when appropriate (i suggest connection:didFailWithError: and connectionDidFinishLoading:)
There is a good tutorial here: http://blog.9mmedia.com/?p=549
You are also not completely implementing key-value-coding compilant properties correct. Whenever you call willChangeValueForKey: you also need to call didChangeValueForKey afterwards:
- (void)start
{
...
[self willChangeValueForKey:#"isExecuting"];
executing = YES;
[self didChangeValueForKey:#"isExecuting"];
[self main];
}
and:
- (void)done
{
...
// Alert
[self willChangeValueForKey:#"isExecuting"];
[self willChangeValueForKey:#"isFinished"];
executing = NO;
finished = YES;
[self didChangeValueForKey:#"isFinished"];
[self didChangeValueForKey:#"isExecuting"];
}
See this Q/A for KVC: when to use "willChangeValueForKey" and "didChangeValueForKey"?

NSArray with multiple nested requests

I have an app that uses a segmentedControl. First item is an "All" item, where the rest is created from an array based on result from webservice. When "All" is selected I want to request all the request.
How can I go about this,
NSArray *urls = [NSArray arrayWithObjects:#"http://service/group/1/",
#"http://service/group/2/", nil];
I want to collect all result from the calls into a collection and display it in a UITableView when the "All" item is selected and probably in viewDidLoad.
For the other segments only one of the request is issued and callback with an array that then is used in:
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
I have tried to look at this example for making the request from the array MultipleDownloads
Thanks,
The method in my viewController to initiate the multiple download:
- (void)requestChildrenInBackground {
queue = [[NSOperationQueue alloc] init];
//Todo remove hard coded and get from previous request respons
NSArray *urls = [NSArray arrayWithObjects: #"http://service/1/children",
#"http://service/2/children",
#"http://service/3/children", nil];
NSLog(#"%#", urls);
for (NSString * url in urls)
{
GetSchedule *operation =
[GetSchedule urlDownloaderWithUrlString:url];
[queue addOperation:operation];
}
}
This is how the multiple request gets handled:
#import "GetSchedule.h"
#import "JSON.h"
#import "Authentication.h"
#import "AttendanceReportViewController.h"
#interface GetSchedule ()
- (void)finish;
#end
#implementation GetSchedule
#synthesize appDelegate;
#synthesize username;
#synthesize password;
#synthesize authenticationString;
#synthesize encodedLoginData;
#synthesize schedulesArray;
#synthesize url = _url;
#synthesize statusCode = _statusCode;
#synthesize data = _data;
#synthesize error = _error;
#synthesize isExecuting = _isExecuting;
#synthesize isFinished = _isFinished;
+ (id)urlDownloaderWithUrlString:(NSString *)urlString {
NSURL * url = [NSURL URLWithString:urlString];
GetSchedule *operation = [[self alloc] initWithUrl:url];
return [operation autorelease];
}
- (id)initWithUrl:(NSURL *)url {
self = [super init];
if (self == nil)
return nil;
_url = [url copy];
_isExecuting = NO;
_isFinished = NO;
return self;
}
- (void)dealloc
{
[username release];
[password release];
[encodedLoginData release];
[_url release];
[_connection release];
[_data release];
[_error release];
[super dealloc];
}
- (BOOL)isConcurrent
{
return YES;
}
- (void)start
{
if (![NSThread isMainThread])
{
[self performSelectorOnMainThread:#selector(start) withObject:nil waitUntilDone:NO];
return;
}
self.username = appDelegate.username;
self.password = appDelegate.password;
Authentication *auth = [[Authentication alloc] init];
authenticationString = (NSMutableString*)[#"" stringByAppendingFormat:#"%#:%#", username, password];
self.encodedLoginData = [auth encodedAuthentication:authenticationString];
[auth release];
NSLog(#"operation for <%#> started.", _url);
[self willChangeValueForKey:#"isExecuting"];
_isExecuting = YES;
[self didChangeValueForKey:#"isExecuting"];
// Setup up the request with the url
NSMutableURLRequest *request = [[NSMutableURLRequest alloc]
initWithURL:_url];
[request setHTTPMethod:#"GET"];
[request setValue:[NSString stringWithFormat:#"Basic %#", encodedLoginData] forHTTPHeaderField:#"Authorization"];
_connection = [[NSURLConnection alloc] initWithRequest:request
delegate:self];
if (_connection == nil)
[self finish];
else {
_data = [[NSMutableData alloc] init];
}
}
- (void)finish
{
NSLog(#"operation for <%#> finished. "
#"status code: %d, error: %#, data size: %u",
_url, _statusCode, _error, [_data length]);
[_connection release];
_connection = nil;
[self willChangeValueForKey:#"isExecuting"];
[self willChangeValueForKey:#"isFinished"];
_isExecuting = NO;
_isFinished = YES;
[self didChangeValueForKey:#"isExecuting"];
[self didChangeValueForKey:#"isFinished"];
}
#pragma mark -
#pragma mark NSURLConnection delegate
- (void)connection:(NSURLConnection *)connection
didReceiveResponse:(NSURLResponse *)response
{
//[_data release];
//_data = [[NSMutableData alloc] init];
[_data setLength:0];
NSHTTPURLResponse * httpResponse = (NSHTTPURLResponse *)response;
_statusCode = [httpResponse statusCode];
}
- (void)connection:(NSURLConnection *)connection
didReceiveData:(NSData *)data
{
[_data appendData:data];
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
// Parse the responseData of json objects retrieved from the service
SBJSON *parser = [[SBJSON alloc] init];
NSString *jsonString = [[NSString alloc] initWithData:_data encoding:NSUTF8StringEncoding];
NSDictionary *jsonData = [parser objectWithString:jsonString error:nil];
NSMutableArray *array = [jsonData objectForKey:#"Children"];
schedulesArray = [NSMutableArray array];
[schedulesArray addObject:array];
// Callback to AttendanceReportViewController that the responseData finished loading
[attendanceReportViewController loadSchedule];
[self finish];
}
- (void)connection:(NSURLConnection *)connection
didFailWithError:(NSError *)error
{
_error = [error copy];
[self finish];
}
#end
When all data is received I want to call back to my ViewController and get an array with all data from all request made.
Create a downloader
Create a downloader class using NSURLConnection.
Keep a member variable called downloaderObjectId.
Write a delegate method for this object. This method will pass the downloaded data and downloaderObjectId back to the delegate.
In the delegate.
Create multiple downloader objects(As per your ncessity) with unique value for the downloaderObjectId.
Store these objects in a NSMutableDictionary
Key for each object will be downloaderObjectId. so that when the delegate method is called after download you take the exact object back from the NSMutableDictionary using this key.
Main point.
Each time delegate is called. You should remove the object from dictionary(The object who is done with the download and called his delgate. You can identify this object by the key downloaderObjectId he holds. )
Then check the count of dictionary. If it is zero you can make sure that your downloads are completed. So you can call your viewcontroller.

How to use the JSON Parsing?

I am a fresher. I don't know how to use JSON for Parsing .I am really very confuse because the tutorial i have read are out dated because apple has deprecated all the API's and documents .Thats what i found .So anyone can give me the start to play with JSON?
You can use SBJSON
You can find code at GITHUB
Here's some links on "Picking the best JSON library":
Comparison of JSON Parser for Objective-C (JSON Framework, YAJL, TouchJSON, etc)
Best JSON library to use when developing an iPhone application?
And now for the shameless plug for my own JSON parsing solution, JSONKit:
What's the most efficient way of converting a 10 MB JSON response into an NSDictionary?
Cocoa JSON parsing libraries, part 2
You need to use third-party code to parse JSON. Three popular libraries/frameworks are:
SBJSON, aka json-framework
TouchJSON
yajl-objc
Choose one of them, download its source code and add it do your project.
You can use your custom framwork for it just as below
#import <Foundation/Foundation.h>
#import "SVProgressHUD.h"
#protocol JsonDataDelegate <NSObject>
#required
- (void) JsonprocessSuccessful: (NSString *)receivedData;
-(void) JsonprocessFail;
#end
#interface JsonRest : NSObject
{
id <JsonDataDelegate> delegate;
NSURLConnection *theConnection;
NSMutableData *webData;
BOOL HadGotResponse;
BOOL HasFailedConnection;
UIAlertView *alert;
}
#property (retain) id delegate;
#property(nonatomic,retain) NSURLConnection *theConnection;
#property (nonatomic)BOOL HadGotResponse;
#property (nonatomic)BOOL HasFailedConnection;
-(void)GetServiceCall:(NSString *)url Paraqmeter:(NSString*)parameter;
-(void)Set2Defaults;
#end
#import "JsonRest.h"
#define BASE_URL #"http://www.abc.com"
#define DOMAIN #"GETLIST"
#implementation JsonRest
#synthesize delegate,HadGotResponse,HasFailedConnection,theConnection;
- (id)init
{
if (self)
{
// Initialization code.
//appdel = (ReachCastAppDelegate*)[[UIApplication sharedApplication]delegate];
}
return self;
}
-(void)GetServiceCall:(NSString *)url Paraqmeter:(NSString*)parameter
{
[SVProgressHUD startActivity : #"Loading..."];
NSString *strUrl=[NSString stringWithFormat:#"%#%#?%#",BASE_URL,url,parameter];
NSURL *url1=[NSURL URLWithString:strUrl];
NSLog(#"domainURL :: %#",strUrl);
NSMutableURLRequest *req = [NSMutableURLRequest requestWithURL:url1];
[req setTimeoutInterval:60.0];
[req setHTTPMethod:#"GET"];
// if([HttpMethod isEqualToString:#"GET"])
// {
// [req setHTTPMethod:HttpMethod];
//
// }
// else if([HttpMethod isEqualToString:#"PUT"])
// {
// NSData *requestData = [NSData dataWithBytes: [BodyString UTF8String] length: [BodyString length]];
//
// [req setValue:valueforput forHTTPHeaderField:#"Content-type"];
// [req setHTTPMethod:HttpMethod];
// [req setHTTPBody: requestData];
//
// }
// else if ([HttpMethod isEqualToString:#"POST"]){
//
// NSData *requestData = [NSData dataWithBytes: [BodyString UTF8String] length: [BodyString length]];
//
// [req setValue:valueforput forHTTPHeaderField:#"Content-type"];
// [req setHTTPMethod:HttpMethod];
// [req setHTTPBody: requestData];
//
// }
if(theConnection)
[self Set2Defaults];
theConnection=[[NSURLConnection alloc]initWithRequest:req delegate:self];
if(theConnection)
webData=[[NSMutableData data]retain];
else
NSLog(#"Connection Failed !!!");
NSLog(#"Has got response");
}
-(void)Set2Defaults {
if (webData != nil){
[webData release];
webData = nil;
}
if (theConnection != nil) {
[theConnection release];
if (theConnection != nil)
theConnection = nil;
}
}
#pragma mark -
#pragma mark NSURL Connection Delegate methods
-(void) connection:(NSURLConnection *) connection didReceiveResponse:(NSURLResponse *) respons{
[webData setLength: 0];
NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)respons;
int statusCode = [httpResponse statusCode];
NSLog(#"statusCode ---- >> %d",statusCode);
if (200 != statusCode) {
// if (401 == statusCode) {
}
}
-(void) connection:(NSURLConnection *) connection didReceiveData:(NSData *) data {
[webData appendData:data];
}
-(void) connection:(NSURLConnection *) connection didFailWithError:(NSError *) error {
[SVProgressHUD stopActivity];
[self Set2Defaults];
self.HadGotResponse=NO;
self.HasFailedConnection=YES;
// txtWindSpeed.text = #"";
[[self delegate] JsonprocessFail];
NSLog(#"Connection Failed!!!");
//[self HideLoadingDialogue];
alert = [[[UIAlertView alloc] initWithTitle:#"ERROR" message:#"Internet Connection Failed.Please try again." delegate:self cancelButtonTitle:nil otherButtonTitles:nil] autorelease];
//alert.frame=CGRectMake(alert.frame.origin.x, alert.frame.origin.y, alert.frame.size.width, 130);
NSLog(#"%F",alert.frame.origin.y);
[alert show];
alert.frame=CGRectMake(alert.frame.origin.x, alert.frame.origin.y+25, alert.frame.size.width, 130);
//[noConnect release];
[NSTimer scheduledTimerWithTimeInterval:2 target:self selector:#selector(timerCall) userInfo:nil repeats:NO];
}
-(void)timerCall
{
[alert dismissWithClickedButtonIndex:0 animated:TRUE];
}
-(void)connectionDidFinishLoading:(NSURLConnection *)connection
{
[SVProgressHUD stopActivity];
self.HasFailedConnection=NO;
NSString *theXML;
theXML = [[NSString alloc] initWithBytes: [webData mutableBytes] length:[webData length] encoding:NSASCIIStringEncoding];
//NSLog(#"theXML Values : %#", theXML);
//self.ResponseDict = [theXML JSONValue];
[[self delegate] JsonprocessSuccessful:theXML];
[theXML release];
}
-(void)dealloc
{
if (webData != nil){
[webData release];
webData = nil;
}
if (theConnection != nil) {
[theConnection release];
if (theConnection != nil)
theConnection = nil;
}
[super dealloc];
// [ResponseDict release];
}
#end
You can use this using below
-(void)getJsonCalling
{
#try {
NSString *strParameter=[NSString stringWithFormat:#"param1=%#&param2=%#",param1,param2];
objJsonRest=[[JsonRest alloc]init];
[objJsonRest setDelegate:self];
[objJsonRest GetServiceCall:DOMAIN Paraqmeter:strParameter];
[objJsonRest release];
}
#catch (NSException *exception) {
NSLog(#"Exception in %s %#",__FUNCTION__,exception);
}
}
- (void) JsonprocessSuccessful: (NSString *)receivedData
{
}
-(void) JsonprocessFail;
{
NSLog(#"FAIL");
}

How do I do an Asynchronous NSURLConnection inside an NSOperation?

I want to do an Asynchrous NSURLConnection inside of an NSOperation on a background thread.
(it is because I'm doing some very expensive operations on the data as they come back that want to be done as the data comes in and in background)
Here is my first attempt:
IN my AppDelegate:
// create the opperation and add it to the queue:
self.sharedOperationQueue = [[[NSOperationQueue alloc] init] autorelease];
LibXMLOperation *op = [[[LibXMLOperation alloc] init] autorelease];
[self.sharedOperationQueue addOperation:op];
Here is my operation:
#interface EbirdLibXMLOperation : NSOperation {
#private
NSURLConnection *urlConnection;
// Overall state of the parser, used to exit the run loop.
BOOL done;
// properties to maintain the NSOperation
BOOL finished;
BOOL executing;
}
- (void)downloadAndParse:(NSURL *)url;
- (void)start;
- (BOOL)isConcurrent;
- (BOOL)isFinished;
- (BOOL)isExecuting;
#property BOOL done;
#property (nonatomic, retain) NSURLConnection *ebirdConnection;
// The autorelease pool property is assign because autorelease pools cannot be retained.
#property (nonatomic, assign) NSAutoreleasePool *downloadAndParsePool;
#end
#implementation LibXMLOperation
#synthesize urlConnection, done;
- (void)start{
if (![self isCancelled]) {
[self willChangeValueForKey:#"isExecuting"];
executing = YES;
//set up the thread and kick it off...
[[NSURLCache sharedURLCache] removeAllCachedResponses];
NSURL *url = [NSURL URLWithString:#"http://google.com"];
[NSThread detachNewThreadSelector:#selector(downloadAndParse:) toTarget:self withObject:url];
[self didChangeValueForKey:#"isExecuting"];
} else {
// If it's already been cancelled, mark the operation as finished.
[self willChangeValueForKey:#"isFinished"];
finished = YES;
[self didChangeValueForKey:#"isFinished"];
}
}
- (BOOL)isConcurrent {
return YES;
}
- (BOOL)isExecuting {
return executing;
}
- (BOOL)isFinished {
return finished;
}
- (void)downloadAndParse:(NSURL *)url {
self.downloadAndParsePool = [[NSAutoreleasePool alloc] init];
done = NO;
self.characterBuffer = [NSMutableData data];
[[NSURLCache sharedURLCache] removeAllCachedResponses];
NSURLRequest *theRequest = [NSURLRequest requestWithURL:url];
urlConnection = [[NSURLConnection alloc] initWithRequest:theRequest delegate:self];
if (urlConnection != nil) {
do {
[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
} while (!done);
}
[self willChangeValueForKey:#"isFinished"];
[self willChangeValueForKey:#"isExecuting"];
finished = YES;
executing = NO;
// Clean up.
self.urlConnection = nil;
[downloadAndParsePool release];
NSLog(#"download and parse cleaning up");
self.downloadAndParsePool = nil;
[self didChangeValueForKey:#"isExecuting"];
[self didChangeValueForKey:#"isFinished"];
}
#pragma mark NSURLConnection Delegate methods
// Disable caching so that each time we run this app we are starting with a clean slate.
- (NSCachedURLResponse *)connection:(NSURLConnection *)connection willCacheResponse:(NSCachedURLResponse *)cachedResponse {
return nil;
}
// Forward errors to the delegate.
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
done = YES;
}
// Called when a chunk of data has been downloaded.
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
// Process the downloaded chunk of data.
NSLog(#"Did received %i bytes", [data length]);
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
// Set the condition which ends the run loop.
done = YES;
}
#end
When this runs, I see the following message in my log:
2009-08-20 15:18:48.858 App[1001:3e03]*** _NSAutoreleaseNoPool(): Object 0x1126a20 of class NSCFArray autoreleased with no pool in place - just leaking
Stack: (0x305a2e6f 0x30504682 0x3057deba 0x305ced09 0x30577ddf 0x3056b43e 0x3050764a 0x58fc3 0x3050a79d 0x3050a338 0x94568155 0x94568012)
This event happens at the very last [self didChangeValueForKey:#"isFinished"]; which suggests to me that I'm setting up the NSOperation wrong.
Move the lines:
[downloadAndParsePool release];
self.downloadAndParsePool = nil;
to the end of the -downloadAndParse: method.