I'm having a very puzzling issue with NSURLConnection. It is returning the data in another thread or something, things are not working in the proper order. I'm supposed to receive the json data then parse it, but the data is actually being received after the parser fails. Here is the log.
2013-09-22 14:44:40.454 WebServiceExample[39306:a0b] Parsing Error: Error Domain=NSCocoaErrorDomain Code=3840 "The operation couldn’t be completed. (Cocoa error 3840.)" (No value.) UserInfo=0xa0b47e0 {NSDebugDescription=No value.}
2013-09-22 14:44:41.312 WebServiceExample[39306:a0b] Succeeded! Received 112 bytes of data
I'm making a small framework to ease my life to connect to rails API, I'm calling it objective rails OR, but I already spent the entire weekend trying to figure out what I'm doing wrong. Here's the code:
#interface ORObject : NSObject
#property (nonatomic, retain) NSMutableDictionary *properties;
#property (nonatomic, retain) ORWebManager *webManager;
#property (nonatomic, retain) NSString *route;
#property (nonatomic, retain) NSString *singularClassName;
- (id) initWithRoute:(NSString *) route webManager:(ORWebManager *) webManager;
- (id) initWithRoute:(NSString *) route;
- (ORObject *) find:(NSInteger) identifier;
#end
Here is the implementation of find:
- (ORObject *) find:(NSInteger) identifier
{
NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:#"%#/%#/%ld.%#", [ ORConfig sharedInstance].baseURL, self.route, (long)identifier, self.webManager. parser.contentType]];
ORObject *object = [self.webManager httpGet:url];
if (object) {
object.route = self.route;
object.webManager = self.webManager;
}
return object;
}
Here is the httpGet method of the ORWebManager class
- (ORObject *) httpGet:(NSURL *)url
{
ORGetRequester *requester = [[ORGetRequester alloc] init];
NSMutableData *data = [requester request:url];
return [self.parser toObject:data];
}
The superclass of ORGetRequester is ORHTTPRequester and it implements the NSURLConnectionDelegate protocol methods
#interface ORHTTPRequester : NSObject<NSURLConnectionDelegate>
#property (nonatomic, retain) NSMutableData *receivedData;
#property (nonatomic, retain) NSMutableURLRequest *req;
#property (nonatomic, retain) NSURLConnection *connection;
#end
#implementation ORHTTPRequester
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse
[self.receivedData setLength:0];
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
[self.receivedData appendData:data];
}
- (void)connection:(NSURLConnection *)connection
didFailWithError:(NSError *)error
{
NSLog(#"Connection failed! Error - %# %#",
[error localizedDescription],
[[error userInfo] objectForKey:NSURLErrorFailingURLStringErrorKey]);
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
NSLog(#"Succeeded! Received %d bytes of data",[self.receivedData length]);
}
#end
And finally here is ORGetRequester, this is where the "magic" happens.
#interface ORGetRequester : ORHTTPRequester
- (NSMutableData *) request:(NSURL *)url;
#end
#implementation ORGetRequester
- (NSMutableData *) request:(NSURL *)url
{
self.req = [NSMutableURLRequest requestWithURL:url
cachePolicy:NSURLRequestUseProtocolCachePol icy
timeoutInterval:60.0];
self.receivedData = [[NSMutableData alloc] init];
self.connection = [[NSURLConnection alloc] initWithRequest:self.req delegate:self];
if (!self.connection) {
NSLog(#"Connection Failed");
}
return self.receivedData;
}
#end
self.connection = [[NSURLConnection alloc] initWithRequest:self.req delegate:self];
returns immediately because it starts an async operation. You need to parse the data when connectionDidFinishLoading: is called.
Or consider using:
+ (void)sendAsynchronousRequest:(NSURLRequest *)request queue:(NSOperationQueue *)queue completionHandler:(void (^)(NSURLResponse*, NSData*, NSError*))handler
The completion block will be called when the http operations is complete. Process the data in the completion block and notify any object that needs the data. This is probably a good bet if you do not need the other delegate methods.
Related
I have created a class that will collect data from url data asynchronously, however my understanding of callbacks or whatever is not clear and I'm trying to find a simple way to reuse my class by having the calling method wait for data to be returned or set within the ApiManager class. I just need something to wakeup in another class when that process has been completed. Some processes have single request and others have multiple, why you will notice that I'm using [connection description] within the ApiManager class.
ApiManager.h
#import <UIKit/UIKit.h>
#import <Foundation/Foundation.h>
#interface ApiManager : NSObject<NSURLConnectionDelegate>
{
NSMutableDictionary *_dataDictionary;
}
- (void)urlRequest:(NSURLRequest *)url;
#property (strong, nonatomic) NSMutableArray *results;
#end
ApiManager.m
#import "ApiManager.h"
#implementation ApiManager
- (void)urlRequest:(NSURLRequest *)url {
[[NSURLConnection alloc] initWithRequest:url delegate:self];
}
// basic connection classes
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
NSMutableData *responceOjb = _dataDictionary[ [connection description] ];
[_dataDictionary setObject:responceOjb forKey:[connection description]];
}
// append any data we find
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
NSMutableData *responceOjb = _dataDictionary[ [connection description] ];
[responceOjb appendData: data];
[_dataDictionary setObject:responceOjb forKey:[connection description]];
}
// --
- (NSCachedURLResponse *)connection:(NSURLConnection *)connection
willCacheResponse:(NSCachedURLResponse*)cachedResponse {
// Return nil to indicate not necessary to store a cached response for this connection
return nil;
}
// wrap up and close the connect, move objects over to results or something
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
[_results addObject:[connection description]];
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
// The request has failed for some reason!
// Check the error var
NSLog(#"%#",error);
}
#end
The main View Controller test:
#import "ViewController.h"
#import "ApiManager.h"
#interface ViewController ()
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
[self DoThisTest];
}
-(void)DoThisTest {
ApiManager *api = [[ApiManager alloc] init];
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:[NSString stringWithFormat:#"%#",#"http://google.com"]]];
[api urlRequest:request];
if([api results]) {
NSLog(#"GOT DATA");
}
}
Well, there are a few options. You could add a block property onto your ApiManager class:
#property (copy, nonatomic) void (^doneHandler)();
And then invoke that block like so:
self.doneHandler();
You would invoke the block when you deem it appropriate (say, in your connectionDidFinishLoading: method).
With this approach, the definition of the block (callback) would happen in your view controller and look something like:
ApiManager *apiManager = [[ApiManager alloc] init];
apiManager.doneHandler = ^{
// Do whatever you need to do here.
};
Alternatively, you could add a method to your ApiManager with a signature like this:
- (void)sendRequestWithURL:(NSURL*)url completion:(void(^)())completion;
And use NSURLConnection's (or, better, NSURLSession's) block-based APIs. Those APIs have callbacks built in and you would simply invoke completion(); inside of the completion block of -[NSURLSession sendAsynchronousRequest:completion:].
Finally, you could define an ApiManagerDelegate protocol.
- (void)apiManagerDidFinishReceivingData:(ApiManager*)sender;
And add a delegate property to your ApiManager class.
#property (weak, nonatomic) id<ApiManagerDelegate>delegate;
Assign the delegate of your ApiManager in your ViewController:
ApiManager *apiManager = [[ApiManager alloc] init];
apiManager.delegate = self;
Call the delegate method inside of your implementation of NSURLConnectionDelegate's callbacks in ApiManager like so:
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
[_results addObject:[connection description]];
[self.delegate apiManagerDidFinishReceivingData:self];
}
And implement the delegate method in ViewController:
- (void)apiManagerDidFinishReceivingData:(ApiManager*)sender {
// Do what you want to.
}
As an addendum, there are networking libraries available that do a lot of the heavy lifting and busy-work for you, most notably AFNetworking, if you're just trying to get stuff done. And, even if this is more of an academic exercise where you're trying to understand the patterns, looking at AFNetworking's APIs and implementation (it's open source) would be highly instructive.
Cheers
I decided to go with an embedded API call within a view controller, and I'm having trouble with the data reaching out before the API returns with the information.
How do I wait for the data to be returned before the view controller displays all the values as nulls?
Thanks for any help.
#import "BDChangeApproveController.h"
#import "BDItemChangeDetailAPI.h"
#interface BDChangeApproveController () <NSURLSessionDelegate>
#property (nonatomic, strong) NSURLSession *session;
#property (nonatomic, copy) NSArray *APIItem;
#end
#implementation BDChangeApproveController
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)fetchFeedAPIChangeDetail
{
NSURLSessionConfiguration *config = [NSURLSessionConfiguration defaultSessionConfiguration];
_session = [NSURLSession sessionWithConfiguration:config
delegate:nil
delegateQueue:nil];
NSString *requestString = #"http://URL.com";
NSURL *url = [NSURL URLWithString:requestString];
NSURLRequest *req = [NSURLRequest requestWithURL:url];
NSURLSessionDataTask *dataTask =
[self.session dataTaskWithRequest:req
completionHandler:
^(NSData *data, NSURLResponse *response, NSError *error){
NSDictionary *jsonObject1 = [NSJSONSerialization JSONObjectWithData:data
options:0
error:nil];
//NSLog(#"%#", jsonObject1);
self.APIItem = jsonObject1[#"CoDetail"];
NSLog(#"%#", self.APIItem);
}];
[dataTask resume];
}
//API authentication
- (void) URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task
didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge
completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition, NSURLCredential *))completionHandler
{
NSURLCredential *cred =
[NSURLCredential credentialWithUser:#"demouser"
password:#"secret"
persistence:NSURLCredentialPersistenceForSession];
completionHandler(NSURLSessionAuthChallengeUseCredential, cred);
}
- (void)viewDidLoad
{
[super viewDidLoad];
[self fetchFeedAPIChangeDetail];
self.title = #"Action";
self.coNumberLabel.text = self.itemAPI.changeOrder;
//self.recipeImageView.image = [UIImage imageNamed:self.recipe.image];
NSLog(#"testtttt");
NSMutableString *coDetailsText = [NSMutableString string];
coDetailsText =
[[NSMutableString alloc] initWithFormat:#"Review Change Order details bellow\n====================\n%# \n================== \nPlanned Start %#\n==================\nSubcategory: %#\n==================\nService: %#\n==================\nAssociated CIs: %#\n==================\nEnvironment CI: %#\n==================\nApproval Group: %#\n==================\nInitiator : %#\n==================\nCoordinator : %#\n==================\nRisk Level : %#\n==================\nPerforming Group : %#\n==================\nImplementation Plan : %#\n==================\nStatus : %#\n==================\nRecovery Plan : %#\n==================\n",
/*
self.item.title,
self.item.changeOrder,
self.item.subcategory,
self.item.assignmentGroup,
self.item.changeOrder,
self.item.subcategory,
self.item.assignmentGroup,
self.item.approverEid,
self.item.approverEid,
self.item.subcategory,
self.item.assignmentGroup,
self.item.title,
self.item.title,
self.item.title
*/
self.itemAPI.title,
self.itemAPI.plannedStart,
self.itemAPI.subcategory,
self.itemAPI.service,
self.itemAPI.associatedCi,
self.itemAPI.environment,
self.itemAPI.assignmentGroup,
self.itemAPI.initiator,
self.itemAPI.coordinator,
self.itemAPI.riskLevel,
self.itemAPI.performingGroup,
self.itemAPI.implementationPlan,
self.itemAPI.status,
self.itemAPI.recoveryScope
// self.item.valueInDollars,
// self.item.dateCreated,
// self.item.subcategory,
// self.item.service,
// self.item.associatedCIs,
// self.item.environment,
// self.item.approvalGroup,
// self.item.initiator,
// self.item.coordinator,
// self.item.riskLevel,
// self.item.performingGroup,
// self.item.implementationPlan,
// self.item.validationPlan,
//self.item.recoveryScope
];
self.coDetailsTextView.text = coDetailsText;
NSLog(#"overrrr");
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#end
// Adding File
#import <Foundation/Foundation.h>
#import "BDItemChangeDetailAPI.h"
#interface BDChangeApproveController : UIViewController
#property (weak, nonatomic) IBOutlet UILabel *coNumberLabel;
#property (weak, nonatomic) IBOutlet UITextView *coDetailsTextView;
#property (nonatomic, strong) BDItemChangeDetailAPI *itemAPI;
#end
Looks like you're doing something asynchronously and expecting it to act synchronously.
Look at the below piece of code you're using in viewDidLoad:
[self fetchFeedAPIChangeDetail]; // this takes some time to complete
self.title = #"Action"; // this happens immediately after the above starts, not ends
self.coNumberLabel.text = self.itemAPI.changeOrder; // so does this, so at this point itemAPI is probably nil
fetchFeedAPICheckDetail is an asynchronous process, so it might take a few seconds to complete, whereas setting the title and coNumberLabel happens immediately after, so you don't yet have the itemAPI information from the URL Session. Your code doesn't wait for fetchFeedAPIChangeDetail to be done with the request before continuing onto the next line.
Declare a function
-(void)refreshTextView
{
// set your text view text with the api result here
self.coNumberLabel.text = self.itemAPI.changeOrder;
}
Call this method in at the end of your request block after NSLog(#"%#", self.APIItem);
Like this
[self performSelectorOnMainThread:#selector(refreshTextView) withObject:nil waitUntilDone:NO];
When you will call this method in the block it will be called and will update the textview text with the api results. The block is asynchronous and so when you update your textview later it doesn't gets updated because the block has not yet completed its function and the array is still nil but calling this method in the block would assure that the result gets assigned and updated in the textview.
UPDATE
and you do have a typo here
#property (nonatomic, copy) NSArray *APIItem;
you are naming it with the class name thats a conflict.
Name it something else like #property (nonatomic, copy) NSArray *apiItem; Actually u have a class name APIItem declared because of which a conflict occurs and that is the very reason it is marked blue in xcode. look all class names are marked blue in your code. Like NSArray , NSURLSession etc –
I want to log all the NSURLRequests which are initiated from within my app and response for those requests. I wrote a custom NSURLProtocol to achieve this. I was able to trap all the request but not the response.
In canInitWithRequest method I can log all the requests regardless of method returns YES/NO.
Right now I am returning YES in hope the of actual response.
In -startLoading method I am supposed to inform NSURLProtocolClient with response and progress. I am not interested in modifying/creating my own response instead I am interested in actual response and want to log it. When and where would I find actual response for the request?
I am not interested in modifying URL loading behavior.
Am I on the right track with custom protocol or is there something else I need to do to log all the requests and responses?
#implementation TestURLProtocol
+(BOOL)canInitWithRequest:(NSURLRequest *)request
{
//here i can log all the requests
NSLog(#"TestURLProtocol : canInitWithRequest");
return YES;
}
+(NSURLRequest *)canonicalRequestForRequest:(NSURLRequest *)request
{
return request;
}
-(void)startLoading
{
// I don't want to create or modify response.
//I have nothing todo with response instead I need actual response for logging purpose.
NSURLResponse * response = [[NSURLResponse alloc] initWithURL:[self.request URL] MIMEType:#"text/html" expectedContentLength:-1 textEncodingName:#"utf8"];
[[self client] URLProtocol:self didReceiveResponse:response cacheStoragePolicy:NSURLCacheStorageNotAllowed];
[[self client] URLProtocolDidFinishLoading:self];
}
-(void)stopLoading
{
}
#end
Well, I dropped the idea of custom NSURLProtocol. I wrote a class which confirms to NSURLConnectionDelegate, NSURLConnectionDataDelegate etc as per your need. This class serves as a common delegate to all NSURLConnection instances. It has a property of type id(depend upon requirements), this property holds the object which is creating NSURLConnection and interested in delegate callbacks as well.
URLRequestLogger instance serves as a common delegate to all NSURLConnection instances.
Each NSURLConnection has a URLRequestLogger instance as a delegate.
#import <Foundation/Foundation.h>
#interface URLRequestLogger : NSObject<NSURLConnectionDataDelegate>
-(id)initWithConnectionDelegate:(id<NSURLConnectionDataDelegate>)connectionDelegate;
#end
implementation file
#import "URLRequestLogger.h"
#interface URLRequestLogger ()
#property(nonatomic, assign) id<NSURLConnectionDataDelegate> connectionDelegate;
#end
#implementation URLRequestLogger
-(id)initWithConnectionDelegate:(id<NSURLConnectionDataDelegate>)connectionDelegate
{
self = [super init];
if (self)
{
_connectionDelegate = connectionDelegate;
}
return self;
}
//one can implement all the delegates related to NSURLConnection as per need
-(void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
//log reponse info
if ([response isKindOfClass:[NSHTTPURLResponse class]])
{
NSHTTPURLResponse * httpResponse = (NSHTTPURLResponse *)response;
NSDictionary * responseHeaders = [httpResponse allHeaderFields];
NSInteger statusCode = [httpResponse statusCode];
//save as many info as we can
}
//if connectionDelegate is interested in it, inform it
if ([self.connectionDelegate respondsToSelector:#selector(connection:didReceiveResponse:)])
{
[self.connectionDelegate connection:connection didReceiveResponse:response];
}
}
-(void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
//log the error and other info
//if connectionDelegate is interested in it, inform it
if ([self.connectionDelegate respondsToSelector:#selector(connection:didFailWithError:)])
{
[self.connectionDelegate connection:connection didFailWithError:error];
}
}
-(void)connectionDidFinishLoading:(NSURLConnection *)connection
{
//log the connection finish info
//response time and download time etc
//if connectionDelegate is interested in it, inform it
if ([self.connectionDelegate respondsToSelector:#selector(connectionDidFinishLoading:)])
{
[self.connectionDelegate connectionDidFinishLoading:connection];
}
}
#end
MyViewController creates an NSURLConnection and is interested in delegate methods as well. At the same time we want to log all the details about request and response.
#import <UIKit/UIKit.h>
#interface MyViewController : UIViewController<NSURLConnectionDataDelegate>
#end
implementation file
#import "MyViewController.h"
#import "URLRequestLogger.h"
#implementation MyViewController
//MyViewController class creates a request and interested in connection delegate callbacks
//MyViewController confirms to NSURLConnectionDelegate.
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
[self sendRequest];
}
-(void)sendRequest
{
/*
connection delegate here would be our URLRequestLogger class instance which holds MyViewController instance
to return the callbacks here after logging operations are finished
*/
URLRequestLogger * requestLogger = [[URLRequestLogger alloc] initWithConnectionDelegate:self];
[NSURLConnection connectionWithRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:#"http://www.example.org"]] delegate:requestLogger];
}
#pragma mark - NSURLConnection delegate methods
-(void)connectionDidFinishLoading:(NSURLConnection *)connection
{
//this callback is received from URLRequestLogger after logging operation is completed
//do something. Update UI etc...
}
-(void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
//this callback is received from URLRequestLogger after logging operation is completed
//do something. Update UI etc...
}
#end
Better solution with custom NSURLProtocol:
One can log all outgoing URL request and alter request properties, response and do other things like loading encrypted html files from disk into webview etc.
.h file
#import <Foundation/Foundation.h>
#interface URLRequestLoggerProtocol : NSURLProtocol
#end
.m file
#import "URLRequestLoggerProtocol.h"
#interface URLRequestLoggerProtocol ()<NSURLConnectionDelegate,NSURLConnectionDataDelegate>
#property(nonatomic, strong) NSURLConnection * connection;
#end
#implementation URLRequestLoggerProtocol
#synthesize connection;
+(BOOL)canInitWithRequest:(NSURLRequest *)request
{
//logging only HTTP and HTTPS requests which are not being logged
NSString * urlScheme = request.URL.scheme;
if (([urlScheme isEqualToString:#"http"] || [urlScheme isEqualToString:#"https"]) && ![[NSURLProtocol propertyForKey:#"isBeingLogged" inRequest:request] boolValue])
{
return YES;
}
return NO;
}
+(NSURLRequest *)canonicalRequestForRequest:(NSURLRequest *)request
{
return request;
}
-(void)startLoading
{
NSMutableURLRequest * newRequest = [self.request mutableCopy];
[NSURLProtocol setProperty:[NSNumber numberWithBool:YES] forKey:#"isBeingLogged" inRequest:newRequest];
self.connection = [NSURLConnection connectionWithRequest:newRequest delegate:self];
}
-(void)stopLoading
{
[self.connection cancel];
}
#pragma mark - NSURLConnectionDelegate methods
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
//log all things along with error and finally inform URL client that you are done
[self.client URLProtocol:self didFailWithError:error];
}
#pragma mark - NSURLConnectionDataDelegate methods
-(NSURLRequest *)connection:(NSURLConnection *)connection willSendRequest:(NSURLRequest *)request redirectResponse:(NSURLResponse *)response
{
//start logging a request properties from here
return request;
}
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
//log the response and other things and inform client that you are done.
[self.client URLProtocol:self didReceiveResponse:response cacheStoragePolicy:NSURLCacheStorageAllowed];
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
//log the data and other things and inform client that you are done.
[self.client URLProtocol:self didLoadData:data];
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
//log the finish info and other things and inform client that you are done.
[self.client URLProtocolDidFinishLoading:self];
}
#end
I have an NSObject class that contains 3 methods:
-(void)RequestForData
{
#pragma Mark - ASIHTTPRequest
NSURL *url=[NSURL URLWithString:#"http://srv2.vitaminas.it/pdv"];
ASIHTTPRequest *request=[ASIHTTPRequest requestWithURL:url];
[request setDelegate:self];
[request startSynchronous];
}
pragma Mark - HTTP Delegate
- (NSData*)requestFinished:(ASIHTTPRequest *)request
{
NSData *responseData = [request responseData];
return responseData;
}
- (void)requestFailed:(ASIHTTPRequest *)request
{
NSError *error = [request error];
NSLog(#"%#",error);
}
I have one view controller class, from viewDidLoad method of viewcontroller class call -RequestForData method of NSObject class,
WebServiceMethods *web=[[WebServiceMethods alloc]init];
[web RequestForData];
arr_JsonData=[NSJSONSerialization JSONObjectWithData:web options:NSUTF8StringEncoding error:Nil];
NSLog(#"%#",arr_JsonData);
[self.tableView reloadData];
But I want to use NSData that are returned from NSObject class (i.e return responsedata; ) into view controller class.
I want that NSData into arr_JsonData ( NSMutuableArray )
What can I do ?
Make responseData as class level variable. Do not create local instance of it in requestFinished method.
Your problem is callbacks. You should put your viewController as a delegate of WebServiceMethods ( or using blocks is better) to be informed when the request has finished and the populate your arr_JsonData
#protocol WebServiceMethodsDelegate
- (void)webServiceMethodsDidFinishWithSucess:(NSString *)response; // give this méthode an appropriate name.
- (void)webServiceMethodsDidFailWithError:(NSError *)error;
#end
#interface WebServiceMethods : NSObject
#property (nonatomic,weak) id <WebServiceMethodsDelegate> delegate;
#end
#implemntation WebServiceMethods : NSObject
- (void)requestFinished:(ASIHTTPRequest *)request
{
NSString *responseString = [request responseString];
[self.delegate webServiceMethodsDidFinishWithSucess:responseString];
}
- (void)requestFailed:(ASIHTTPRequest *)request
{
NSError *error = [request error];
[self.delegate webServiceMethodsDidFailWithError:error];
}
#end
Put your viewController conform to the WebServiceMethodsDelegate protocol.
#interface yourViewController : UIViewController <WebServiceMethodsDelegate>
...
#end
and know in your the viewDidLoad of your viewController :
WebServiceMethods *web=[[WebServiceMethods alloc]init];
web.delegate = self;
[web RequestForData];
Put also the delegate methods in viewController.m
- (void)webServiceMethodsDidFinishWithSucess:(NSString *)response {
// here you can parse the response and reload your tableView
.....
[self.tableView reloadData];
}
- (void)webServiceMethodsDidFailWithError:(NSError *)error {
// handle the errors
}
PS : There are many problems with your code :
Don't use ASHTTPRequest, it's not maintained. You can use AFNetworking.AFNetworking
Put your WebServiceMethods as a shared instance.
....
Ey guys, here is my code:
#import <Foundation/Foundation.h>
#interface Updater : NSObject {
NSURLConnection *updateConnection;
NSURLDownload *downloadConnection; //error at this line
}
#end
This is the error I am getting at the marked line:
Updater.h:15: error: expected specifier-qualifier-list before 'NSURLDownload'
Any idea why I am getting this error message? I have included the Foundation Framework and am stumped as to why the compiler is complaining, especially considering it doesn't complain at all about NSURLConnection. Thanks!
NSURLDownload class is available on MacOS only, on iOS you should use NSURLConnection. From docs:
iOS Note: The NSURLDownload class is
not available in iOS, because
downloading directly to the file
system is discouraged. Use the
NSURLConnection class instead
If you have large chunk of data to download and want to avoid memory issues you can use NSFileHandle class in connection delegate to write received data directly to disk instead of keeping it in memory.
As you read in iOS Note: it's not possible to use NSURLDownload on ios yet, but the link provided below shows you a simple way to download whatever you want from the net to the application sand box. Hope you like it.
Cheers
http://www.ifans.com/forums/showthread.php?t=169611
------------ Below is the link ------------
//
// UIDownloadBar.h
// UIDownloadBar
//
// Created by John on 3/20/09.
// Copyright 2009 Gojohnnyboi. All rights reserved.
//
#import <UIKit/UIKit.h>
#class UIProgressView;
#protocol UIDownloadBarDelegate;
#interface UIDownloadBar : UIProgressView {
NSURLRequest* DownloadRequest;
NSURLConnection* DownloadConnection;
NSMutableData* receivedData;
NSString* localFilename;
id<UIDownloadBarDelegate> delegate;
long long bytesReceived;
long long expectedBytes;
float percentComplete;
}
- (UIDownloadBar *)initWithURL:(NSURL *)fileURL progressBarFrame:(CGRect)frame timeout:(NSInteger)timeout delegate:(id<UIDownloadBarDelegate>)theDelegate;
#property (nonatomic, readonly) NSMutableData* receivedData;
#property (nonatomic, readonly, retain) NSURLRequest* DownloadRequest;
#property (nonatomic, readonly, retain) NSURLConnection* DownloadConnection;
#property (nonatomic, assign) id<UIDownloadBarDelegate> delegate;
#property (nonatomic, readonly) float percentComplete;
#end
#protocol UIDownloadBarDelegate<NSObject>
#optional
- (void)downloadBar:(UIDownloadBar *)downloadBar didFinishWithData:(NSData *)fileData suggestedFilename:(NSString *)filename;
- (void)downloadBar:(UIDownloadBar *)downloadBar didFailWithError:(NSError *)error;
- (void)downloadBarUpdated:(UIDownloadBar *)downloadBar;
#end
//
// UIDownloadBar.m
// UIDownloadBar
//
// Created by John on 3/20/09.
// Copyright 2009 Gojohnnyboi. All rights reserved.
//
#import "UIDownloadBar.h"
#implementation UIDownloadBar
#synthesize DownloadRequest,
DownloadConnection,
receivedData,
delegate,
percentComplete;
- (UIDownloadBar *)initWithURL:(NSURL *)fileURL progressBarFrame:(CGRect)frame timeout:(NSInteger)timeout delegate:(id<UIDownloadBarDelegate>)theDelegate {
self = [super initWithFrame:frame];
if(self) {
self.delegate = theDelegate;
bytesReceived = percentComplete = 0;
localFilename = [[[fileURL absoluteString] lastPathComponent] copy];
receivedData = [[NSMutableData alloc] initWithLength:0];
self.progress = 0.0;
self.backgroundColor = [UIColor clearColor];
DownloadRequest = [[NSURLRequest alloc] initWithURL:fileURL cachePolicy:NSURLRequestReloadIgnoringLocalCacheData timeoutInterval:timeout];
DownloadConnection = [[NSURLConnection alloc] initWithRequest:DownloadRequest delegate:self startImmediately:YES];
if(DownloadConnection == nil) {
[self.delegate downloadBar:self didFailWithError:[NSError errorWithDomain:#"UIDownloadBar Error" code:1 userInfo:[NSDictionary dictionaryWithObjectsAndKeys:#"NSURLConnection Failed", NSLocalizedDescriptionKey, nil]]];
}
}
return self;
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
[self.receivedData appendData:data];
NSInteger receivedLen = [data length];
bytesReceived = (bytesReceived + receivedLen);
if(expectedBytes != NSURLResponseUnknownLength) {
self.progress = ((bytesReceived/(float)expectedBytes)*100)/100;
percentComplete = self.progress*100;
}
[delegate downloadBarUpdated:self];
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
[self.delegate downloadBar:self didFailWithError:error];
[connection release];
}
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
expectedBytes = [response expectedContentLength];
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
[self.delegate downloadBar:self didFinishWithData:self.receivedData suggestedFilename:localFilename];
[connection release];
}
- (void)drawRect:(CGRect)rect {
[super drawRect:rect];
}
- (void)dealloc {
[localFilename release];
[receivedData release];
[DownloadRequest release];
[DownloadConnection release];
[super dealloc];
}
#end