My app is downloading a file from the internet using NSURLConnection.
Two problems are happening:
1) [connection didReceiveData] is never called
2) When [connection didFinishDownloading] is called, my self.currentData is empty
What am I doing wrong?
My header looks like this:
#interface DIFileDownloader : NSObject <NSURLConnectionDelegate> {
NSMutableData *currentData;
}
#property (nonatomic, assign) id <DIFileDownloaderDelegate> delegate;
#property (nonatomic, retain) NSMutableArray *supportedFormats;
#property (nonatomic, retain) NSMutableData *currentData;
#property (nonatomic, retain) NSURLConnection *downloadAgent;
#property (nonatomic) long long expectedContentSize;
#property (nonatomic) float currentDownloadProgress;
#property (nonatomic, getter = isRunning) BOOL running;
-(instancetype)initWithSupportedFormats:(NSArray *)extensions;
-(void)downloadFileAtURL:(NSURL *)url;
-(NSString *)documentsDirectoryPath;
#end
And my implementation file:
-(instancetype)initWithSupportedFormats:(NSArray *)extensions {
self.supportedFormats = [[NSMutableArray alloc] initWithArray:extensions];
self.running = NO;
}
-(void)downloadFileAtURL:(NSURL *)url {
NSString *fileExtension = [url pathExtension];
if ([self.supportedFormats containsObject:fileExtension]) {
self.downloadAgent = [[NSURLConnection alloc] initWithRequest:[NSURLRequest requestWithURL:url] delegate:self];
[self.downloadAgent start];
NSLog(#"Beginning download at URL:%#", url.absoluteString);
}
else {
}
}
-(void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
NSLog(#"Connection recieved response with size: %f", (float)[response expectedContentLength]);
self.expectedContentSize = (float)[response expectedContentLength];
self.running = YES;
NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse*)response;
NSLog(#"%i", [httpResponse statusCode]);
/*
if ([httpResponse statusCode] >= 200 && [httpResponse statusCode] <= 299) {
}
*/
}
-(void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
NSLog(#"%f", (float)[data length]);
[currentData appendData:data];
self.currentDownloadProgress = ((float)[data length] / self.currentDownloadProgress);
NSLog(#"Connection recieved data. New progress is: %f", self.currentDownloadProgress);
if ([self.delegate respondsToSelector:#selector(downloader:progressChanged:)]) {
[self.delegate downloader:self progressChanged:self.currentDownloadProgress];
}
}
-(void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
NSLog(#"Connection failed");
if ([self.delegate respondsToSelector:#selector(downloader:failedToDownloadFileAtURL:reason:)]) {
[self.delegate downloader:self failedToDownloadFileAtURL:connection.originalRequest.URL reason:error];
}
}
-(void)connectionDidFinishDownloading:(NSURLConnection *)connection destinationURL:(NSURL *)destinationURL {
NSLog(#"Connection finished downloading with size: %f", (float)[currentData length]);
self.running = NO;
NSString *filename = [destinationURL.absoluteString lastPathComponent];
NSString *docPath = [self documentsDirectoryPath];
NSString *pathToDownloadTo = [NSString stringWithFormat:#"%#/%#", docPath, filename];
NSError *error = nil;
[currentData writeToFile:pathToDownloadTo options:NSDataWritingAtomic error:&error];
if (error != nil) {
NSLog(#"DIFileDownloader: Failed to save the file because: %#", [error description]);
if ([self.delegate respondsToSelector:#selector(downloader:failedToDownloadFileAtURL:reason:)]) {
[self.delegate downloader:self failedToDownloadFileAtURL:connection.originalRequest.URL reason:error];
}
}
else {
if ([self.delegate respondsToSelector:#selector(downloader:finishedDownloadingFileNamed:atPath:)]) {
[self.delegate downloader:self finishedDownloadingFileNamed:filename atPath:pathToDownloadTo];
}
}
}
- (NSString *)documentsDirectoryPath {
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectoryPath = [paths objectAtIndex:0];
return documentsDirectoryPath;
}
#end
As mentioned in others and in my comment, there are a few bugs in your code which you need to fix.
But there is also one big misconception - stemming from the former awful documentation of NSURLConnection:
connectionDidFinishDownloading:destinationURL: is NOT a delegate method of the two delegates of NSURLConnection namely, NSURLConnectionDelegate and NSURLConnectionDataDelegate which you are supposed to implement in your case.
The minimal set of delegate methods you need to implement are:
For the NSURLConnectionDelegate:
(void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error;
then for the NSURLConnectionDataDelegate:
(void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response;
(void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data;
(void)connectionDidFinishLoading:(NSURLConnection*)connection;
If you don't mind, I've put a sample of a minimal implementation on Gist: SimpleGetHTTPRequest which should give you a jump start do implement your own HTTP request class.
Related
I am developing a framework which requires error callbacks. I have used delegate methods to give error callbacks to the users(developer) of the framework. Can I use NSError to indicate error details in the delegate method or simply use NSDictionary instead ? Are there any memory issues concerned here?
Instead of delegate methods, you should use blocks with proper error handling, something like this:
Interface:
typedef void(^ResultBlock)(id result, NSError *error);
extern NSString * const DummyErrorDomain;
enum{
DummyErrorReason1,
DummyErrorReason2
};
#interface Dummy : NSObject
-(void)doSomething:(ResultBlock)resultBlock;
#end
Implementation with async NSURLConnection:
NSString * const DummyErrorDomain = #"DummyErrorDomain";
#interface Dummy ()
#property (strong) ResultBlock resultBlock;
#property NSURLConnection *connection;
#property NSMutableData *responseData;
#end
#implementation Dummy
-(void)doSomething:(ResultBlock)resultBlock
{
self.resultBlock = resultBlock;
self.responseData = [[NSMutableData alloc] init];
NSURLRequest *request = [[NSURLRequest alloc] initWithURL:[NSURL URLWithString:#"dummyURL"]];
self.connection = [[NSURLConnection alloc]initWithRequest:request delegate:self];
}
-(void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error{
self.resultBlock(nil,error);
}
-(void)connectionDidFinishLoading:(NSURLConnection *)connection{
self.resultBlock(self.responseData, nil);
}
-(void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data{
[self.responseData appendData:data];
}
#end
Usage:
-(void)usage
{
Dummy *dummy = [[Dummy alloc] init];
[dummy doSomething:^(id result, NSError *error) {
if(result){
// everything went fine
}else{
// error handling
}
}];
}
I am writing a simple code, in which I am using Google API for translation services, but I am getting the following error:
Connection failed: Error Domain=NSURLErrorDomain Code=-1000 "bad URL" UserInfo=0x176c80a0 {NSUnderlyingError=0x175c8d00 "bad URL", NSLocalizedDescription=bad URL}
This is the code I have written:
#import "ViewController.h"
#import"SBJson.h"
#interface ViewController ()
#property (strong, nonatomic) IBOutlet UITextField *textfield;
#property (strong, nonatomic) IBOutlet UIButton *go;
#property (strong, nonatomic) IBOutlet UITextView *textview;
- (IBAction)translate:(id)sender;
#property (strong, nonatomic) NSMutableArray *translations;
#property (strong, nonatomic)NSString *_lastText;
#property (nonatomic, copy) NSString * lastText;
#end
#implementation ViewController
#synthesize lastText = _lastText;
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
//Initializing the translation array
_translations = [[NSMutableArray alloc] init];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (void)performTranslation {
responseData = [[NSMutableData data] init ];
NSString *langString = #"en|ja";
NSString *textEscaped = [_lastText
stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
NSString *langStringEscaped = [langString
stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
//My_Key=Google generated key
NSString *url = [NSString stringWithFormat:#"https://www.googleapis.com/language/translate/v2?
key={My_key}&source=en&target=de&q=%#",textEscaped];
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:url]];
[[NSURLConnection alloc] initWithRequest:request delegate:self];
}
- (IBAction)translate:(id)sender {
[_translations removeAllObjects];
[_textfield resignFirstResponder];
_go.enabled=NO;
self.lastText = _textfield.text;
[_translations addObject:_lastText];
_textview.text = _lastText;
[self performTranslation];
}
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
[responseData setLength:0];
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
[responseData appendData:data];
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
_textview.text = [NSString stringWithFormat:#"Connection failed: %#", [error description]];
_go.enabled = YES;
NSLog([NSString stringWithFormat:#"Connection failed: %#", [error description]]);
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
NSString *responseString = [[NSString alloc] initWithData:responseData
encoding:NSUTF8StringEncoding];
NSMutableDictionary *luckyNumbers = [responseString JSONValue];
if (luckyNumbers != nil) {
NSDecimalNumber * responseStatus = [luckyNumbers objectForKey:#"responseStatus"];
if ([responseStatus intValue] != 200) {
_go.enabled = YES;
return;
}
NSMutableDictionary *responseDataDict = [luckyNumbers objectForKey:#"responseData"];
if (responseDataDict != nil) {
NSString *translatedText = [responseDataDict objectForKey:#"translatedText"];
[_translations addObject:translatedText];
self.lastText = translatedText;
_textview.text = [_textview.text stringByAppendingFormat:#"\n%#", translatedText];
_go.enabled = YES;
}
}
}
#end
The problem is like it says. The URL has been generated incorrectly. Try:
NSString * source = #"en";
NSString * target = #"ja";
NSString * key = #"YOUR-KEY";
NSString * url = [NSString stringWithFormat:#"https://www.googleapis.com/language/translate/v2?key=%#&source=%#&target=%#",key,source,target];
and see what response you get.
You can just use FGTranslator. Simple.
FGTranslator *translator = [[FGTranslator alloc] initWithGoogleAPIKey:#"your_google_key"];
[translator translateText:#"Bonjour!"
completion:^(NSError *error, NSString *translated, NSString *sourceLanguage)
{
if (error)
NSLog(#"translation failed with error: %#", error);
else
NSLog(#"translated from %#: %#", sourceLanguage, translated);
}];
I am calling the webservice string using the NSURLConnection , I am getting wrong data in response in success method of NSURLConnection , But if i load same URL in browser i am getting correct response. I am using below code .
NSData *mydata=[srtRes dataUsingEncoding:NSUTF8StringEncoding];
NSError *e;
NSMutableArray *returnArry =[[NSMutableArray alloc]init];
returnArry = [NSJSONSerialization JSONObjectWithData:mydata options:NSJSONReadingMutableContainers error:&e];
How to resolve this issue. Kindly give suggestion and answers.
Try this one :
// In .h class
#property (nonatomic,retain) NSMutableData *responseData;
#property (nonatomic, retain) NSMutableArray *temp_arr;
// In .m class
#synthesize responseData;
#synthesize temp_arr;
- (void)viewDidLoad
{
NSString *urlString=#"http://your urls";
self.responseData=[NSMutableData data];
NSURLConnection *connection=[[NSURLConnection alloc]initWithRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:urlString]] delegate:self];
NSLog(#"connection====%#",connection);
}
Delegate Method of JSON Parsing :
-(void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
[self.responseData setLength:0];
}
-(void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
[self.responseData appendData:data];
}
-(void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
self.responseData=nil;
}
-(void)connectionDidFinishLoading:(NSURLConnection *)connection
{
NSArray * returnArry = [NSJSONSerialization JSONObjectWithData:self.responseData options:kNilOptions error:nil];
NSDictionary *nameDic = nil;
for (int i = 0 ; i < [returnArry count]; i++)
{
nameDic = [returnArry objectAtIndex:i];
[self.temp_arr addObject:[nameDic objectForKey:#"name"]]; // According your key you have to save data in temp_arr.
}
}
Please follow this , if any doubt let me know :)
I am parsing 5 urls here using NSURLConnection delegate which retrieves json from mysql db & inserts into core data to DB while user logs in. But the code is taking too much time,how can I reduce time here please help.
dispatch_queue_t myBackgroundQueue;
myBackgroundQueue = dispatch_queue_create("loginTask", NULL);
dispatch_async(myBackgroundQueue, ^(void){
// code for parsing 5 urls
json_parser *obj= [[json_parser alloc]init];
[obj parseUrl:#"myurl"];
});
#interface json_parser () {
NSMutableArray *array;
NSMutableData *mdata;
NSURLConnection *conn;
}
#end
#implementation json_parser
- (void)parseUrl:(NSString *)baseUrl
{
NSURL *url=[NSURL URLWithString:baseUrl];
NSURLRequest *request=[NSURLRequest requestWithURL:url];
conn=[NSURLConnection connectionWithRequest:request delegate:self];
if(conn) {
mdata=[[NSMutableData alloc]init];
}
}
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
[mdata setLength:0];
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
[mdata appendData:data];
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
NSDictionary *allData=[NSJSONSerialization JSONObjectWithData:mdata options:0 error:nil];
for (NSDictionary *dict in allData)
{
masterGeneric *masterObj=[[masterGeneric alloc]init];//this is nsobject type class
masterObj.masterId=[dict objectForKey:#"id"];
masterObj.genericname=[dict objectForKey:#"genericname"];
masterObj.salient_features=[dict objectForKey:#"salient_features"];
masterObj.bioactivity_group=[dict objectForKey:#"bioactivity_group"];
masterObj.therapy_group=[dict objectForKey:#"therapy_group"];
masterObj.dosage_information=[dict objectForKey:#"dosage_information"];
masterObj.indications=[dict objectForKey:#"indications"];
masterObj.food=[dict objectForKey:#"food"];
masterObj.interaction=[dict objectForKey:#"interaction"];
masterObj.side_effects=[dict objectForKey:#"side_effects"];
masterObj.precautions=[dict objectForKey:#"precautions"];
masterObj.warnings=[dict objectForKey:#"warnings"];
masterObj.advice_to_patients=[dict objectForKey:#"advice_to_patients"];
masterObj.route_of_administration=[dict objectForKey:#"route_of_administration"];
masterObj.available_form=[dict objectForKey:#"available_form"];
}
}
I'm trying to get token with the help of given link. Please go through this link http://www.stevesaxon.me/posts/2011/window-external-notify-in-ios-uiwebview/
What is _data here? How to declare that?
-(void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
if(_data)
{
[_data release];
_data = nil;
}
}
-(void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
if(!_data)
{
_data = [data mutableCopy];
}
else
{
[_data appendData:data];
}
}
-(void)connectionDidFinishLoading:(NSURLConnection *)connection
{
if(_data)
{
NSString* content = [[NSString alloc] initWithData:_data
encoding:NSUTF8StringEncoding];
[_data release];
_data = nil;
// prepend the HTML with our custom JavaScript
content = [ScriptNotify stringByAppendingString:content];
[_webView loadHTMLString:content baseURL:_url];
}
}
Its NSMutablData Object which holds the response Data which you receive from your Request to Webservice
Declare this in #interface of .h file
NSMutableData *_data;
#property (nonatomic, retain) NSMutableData *_data;
and #synthesize _data; in .m file after #implementation line