I'm trying to compile application on my iPad. I'm using AFNetworking to get list of files on my FTP. Application works on simulator, but when i start it on iPad i get (null) content of file with list. Here's code:
- (void) getListOfFiles {
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:#"ftp://anonymous#ftphost/"]];
AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request];
NSString *path = [[[NSBundle mainBundle]resourcePath]stringByAppendingPathComponent:#"list"];
operation.outputStream = [NSOutputStream outputStreamToFileAtPath:path append:YES];
[operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, NSHTTPURLResponse *response) {
NSLog(#"Success %#",operation.response);
}
failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"Error: %#", [error localizedDescription]);
}];
[operation start];
NSString *content = [NSString stringWithContentsOfFile:path encoding:NSUTF8StringEncoding error:nil];
NSLog (#"%#",content);
}
So variable content = (null) only on iPad, and on Simulator everything is fine. Please help, i have lost any hope )
the AFHTTP*Operations are all asynchronous by default.
this is proper, since synchronous(blocking) calls block the main thread
you are starting the operation and take file content directly afterwards. This can't work reliably because the start call is ASYNC and only STARTS the op but doesnt wait for it
either wait for it ... which is BAD as it blocks the thread:
[operation start];
[operation waitUntilDone];
or MUCH BETTER modify getFiles to work asynchronously:
- (void) getListOfFiles {
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:#"URL"]];
AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request];
NSString *path = [[[NSBundle mainBundle]resourcePath]stringByAppendingPathComponent:#"list"];
operation.outputStream = [NSOutputStream outputStreamToFileAtPath:path append:YES];
[operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, NSHTTPURLResponse *response) {
NSLog(#"Success %#",operation.response);
NSString *content = [NSString stringWithContentsOfFile:path encoding:NSUTF8StringEncoding error:nil];
NSLog (#"%#",content);
}
failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"Error: %#", [error localizedDescription]);
}];
[operation start];
}
Ok, problem solved. I can't write to bundle directory, so i nee to use next code instead:
NSArray *paths = NSSearchPathForDirectoiesDomain(NSDocumentDirectory,NSCachesDirectory,YES);
NSString *path = [[paths objectAtIndex:0] stingByAppendingPathComponent:#"list"];
Related
unable to download file
getting this error "Client closed connection before receiving entire response"
the file which i am trying to download is just 266KB
for (NSString *downloadURL in arr) {
// NSString *downloadURL = [d objectForKey:#"url"];
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(#"URL for downloading : %#",downloadURL);
NSArray *pathArray = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask,YES);
NSString *documentsDirectory = [pathArray objectAtIndex:0];
NSString *downloadedZipPath = [documentsDirectory stringByAppendingPathComponent:TEMP_DICTIONARY];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:downloadURL]];
// [request addValue:#"bytes=x-" forHTTPHeaderField:#"Range"];
// [request setTimeoutInterval:20];
AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request];
operation.outputStream = [NSOutputStream outputStreamToFileAtPath:downloadedZipPath append:NO];
[operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
NSLog(#"Success");
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"Error: %#", error);
}];
[operation start];
});
tried to increase api request time out but still not working
Try setting it to more time
[request setTimeoutInterval:20];
I have some error like this. But I think it is not the AF faults. When the thing's content-type you request is different from it's original content type this error will come out.
For Example:
When you request a mp4 file, the server should set the content-type to video/mpeg4, or you can change your request type from GET to POST.
I'm doing a simple request in order to download PDF files and then write it to the file path.
Some of the PDF's are getting directed to the fail block.
The error code I'm getting is 200 and the error description is "transfer closed with 2231939 bytes remaining to read".
Below is the code snippet.
NSURLRequest *request = [NSURLRequest requestWithURL:url
cachePolicy:nil
timeoutInterval:120];
AFHTTPRequestOperation *downloadRequest = [[AFHTTPRequestOperation alloc] initWithRequest:request];
[downloadRequest setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
if (operation.response.statusCode != 200) {
NSLog(#"Error code(S): %d",[operation.response statusCode]);
}else{
NSData *data = [[NSData alloc] initWithData:responseObject];
[data writeToFile:filePath atomically:YES];
NSLog(#"successful download to %#", filePath);
[data release];
}
[self fetchComplete:operation type:type];
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"error code: %d",[operation.response statusCode]);
NSLog(#"error discreption: %#",[error localizedDescription]);
[self fetchFailed:operation];
}];
Please, try this example. Hope this help!
// Step 1: create NSURL with full path to downloading file
// for example try this: NSString *fileUrl = #"https://pbs.twimg.com/profile_images/2331579964/jrqzn4q29vwy4mors75s_400x400.png";
// And create NSURLRequest object with our URL
NSURL *URL = [NSURL URLWithString:fileUrl];
NSURLRequest *request = [NSURLRequest requestWithURL:URL];
// Step 2: save downloading file's name
// For example our fileName string is equal to 'jrqzn4q29vwy4mors75s_400x400.png'
NSString *fileName = [URL lastPathComponent];
// Step 3: create AFHTTPRequestOperation object with our request
AFHTTPRequestOperation *downloadRequest = [[AFHTTPRequestOperation alloc] initWithRequest:request];
// Step 4: set handling for answer from server and errors with request
[downloadRequest setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
// here we must create NSData object with received data...
NSData *data = [[NSData alloc] initWithData:responseObject];
// ... and save this object as file
// Here 'pathToFile' must be path to directory 'Documents' on your device + filename, of course
[data writeToFile:pathToFile atomically:YES];
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"file downloading error : %#", [error localizedDescription]);
}];
// Step 5: begin asynchronous download
[downloadRequest start];
I have an url request method, because each page will be used, I want to make it public.
(Poor standard of English, forgive me)
here is my class method:
- (void)httpRequest :(NSString *)url :(NSMutableArray *)array;
{
NSURL *myUrl = [NSURL URLWithString:url];
NSURLRequest *request = [[NSURLRequest alloc] initWithURL:myUrl cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:10];
AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request];
[operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject)
{
NSLog(#"请求完成");
NSArray *arr;
arr = [NSJSerialization JSONObjectWithData:operation.responseData options:NSJSONReadingAllowFragments error:NULL];
[array addObjectsFromArray:arr];
???????
}failure:^(AFHTTPRequestOperation *operation, NSError *error){
NSLog(#"请求失败: %#", error);
??????
}];
[operation start];
}
I know how to pass simple parameters,like array and url.But when I use this method,code in the question mark will be different everytime.What can I do to make it can be passed,like parameters.
Like: [myApple httpRequest :myurl :myarray : (susucess .....) : (failure......)];
the question mark can be filled in: mytableView reloadData or nslog...
I'm not sure if i explained my question clearly,i don't know if block can solve this,thanks,waiting for your help.
Firstly, note that all method parameters in Objective-C should be named. So instead of - (void)httpRequest :(NSString *)url :(NSMutableArray *)array;, you should have something like:
- (void)performHttpRequestWithURL:(NSString *)url resultsArray:(NSMutableArray *)array;
To answer your question, you could pass your own completion block into your method. You can then call this block once AFNetworking has completed its HTTP request.
- (void)performHTTPRequestWithURL:(NSString *)urlString completion:(void (^)(NSArray *results, NSError *error))completion
{
NSURL *url = [NSURL URLWithString:urlString];
NSURLRequest *request = [[NSURLRequest alloc] initWithURL:url
cachePolicy:NSURLRequestUseProtocolCachePolicy
timeoutInterval:10];
AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request];
[operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject)
{
NSLog(#"请求完成");
NSArray *results = [NSJSerialization JSONObjectWithData:operation.responseData options:NSJSONReadingAllowFragments error:nil];
if (completion)
completion(results, nil);
}
failure:^(AFHTTPRequestOperation *operation, NSError *error)
{
NSLog(#"请求失败: %#", error);
if (completion)
completion(nil, error);
}];
[operation start];
}
You could then call your method and pass in a block:
[self performHTTPRequestWithURL:#"http://www.example.com" completion:^(NSArray *results, NSError *error) {
if (error)
{
// handle error
}
else
{
// reload tableview or similar
}
}];
Take a look at Apple's Blocks Programming Guide for more information on blocks.
I create one application that has one page and in this page exist one button that downloaded file when click on.
I can download file with AFNetworking but in my has error ....
this is my code :
- (IBAction)downloads:(id)sender
{
NSLog(#"start downloads");
NSURLRequest *request = [NSURLRequest requestWithURL:
[NSURL URLWithString:
#"http://.../500x333xgalaxy-core-product-image-1tn.jpg,
q1367836642.pagespeed.ic.eafBYU8jUN.jpg"]];
AFURLConnectionOperation *operation = [[AFHTTPRequestOperation alloc]
initWithRequest:request];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,
NSUserDomainMask, YES);
NSString *path = [[paths objectAtIndex:0] stringByAppendingPathComponent
:#"filename.jpg"];
operation.outputStream = [NSOutputStream outputStreamToFileAtPath:path append:NO];
[operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation,
id responseObject) {
NSLog(#"Successfully downloaded file to %#", path);
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"Error: %#", error);
}];
}
this error is :
No visible #interface 'AFURLConnectionOpretion' declares the selector
'setCompletionBlockWithSuccess'
Use the following line to start the operation :
[operation start];
Here is my download code
AFHTTPRequestOperation *urlConnection;
urlConnection = [[AFHTTPRequestOperation alloc] initWithRequest:request];
urlConnection.outputStream = [NSOutputStream outputStreamToFileAtPath:outputPath append:NO];
[urlConnection setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
NSLog(#"Download Completed");
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"Error occured while downloading");
}];
[urlConnection setDownloadProgressBlock:^(NSInteger bytesRead, long long totalBytesRead, long long totalBytesExpectedToRead) {
}];
change "AFURLConnectionOperation *operation" to "AFHTTPRequestOperation *operation"
i think thats the issue
I am using the AFNetworking library. I can't figure out how to download a file and save it to the documents directory.
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:#"..."]];
AFHTTPRequestOperation *operation = [[[AFHTTPRequestOperation alloc] initWithRequest:request] autorelease];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *path = [[paths objectAtIndex:0] stringByAppendingPathComponent:#"filename"];
operation.outputStream = [NSOutputStream outputStreamToFileAtPath:path append:NO];
[operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
NSLog(#"Successfully downloaded file to %#", path);
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"Error: %#", error);
}];
[operation start];
I'm gonna bounce off #mattt's answer and post a version for AFNetworking 2.0 using AFHTTPRequestOperationManager.
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *path = [[paths objectAtIndex:0] stringByAppendingPathComponent:#"filename"];
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
AFHTTPRequestOperation *op = [manager GET:#"http://example.com/file/to/download"
parameters:nil
success:^(AFHTTPRequestOperation *operation, id responseObject) {
NSLog(#"successful download to %#", path);
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"Error: %#", error);
}];
op.outputStream = [NSOutputStream outputStreamToFileAtPath:path append:NO];
I'm talking about AFNetworking 2.0
[AFHTTPRequestOperationManager manager] creates manager object with default AFJSONResponseSerializer, and it performs content types restriction. Take a look at this
- (BOOL)validateResponse:(NSHTTPURLResponse *)response
data:(NSData *)data
error:(NSError * __autoreleasing *)error
So we need to create a none response serializer and use AFHTTPRequestOperationManager as normal.
Here is the AFNoneResponseSerializer
#interface AFNoneResponseSerializer : AFHTTPResponseSerializer
+ (instancetype)serializer;
#end
#implementation AFNoneResponseSerializer
#pragma mark - Initialization
+ (instancetype)serializer
{
return [[self alloc] init];
}
- (instancetype)init
{
self = [super init];
return self;
}
#pragma mark - AFURLResponseSerializer
- (id)responseObjectForResponse:(NSURLResponse *)response
data:(NSData *)data
error:(NSError *__autoreleasing *)error
{
return data;
}
#end
Usage
self.manager = [AFHTTPRequestOperationManager manager];
self.manager.responseSerializer = [AFNoneResponseSerializer serializer];
[self.manager GET:#"https://sites.google.com/site/iphonesdktutorials/xml/Books.xml"
parameters:parameters
success:^(AFHTTPRequestOperation *operation, id responseObject)
{
if (success) {
success(responseObject);
}
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
if (failure) {
failure(error);
}
}];
so that we can get the whole file without any serialization
Documentation page has example with section 'Creating a Download Task':
NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
AFURLSessionManager *manager = [[AFURLSessionManager alloc] initWithSessionConfiguration:configuration];
NSURL *URL = [NSURL URLWithString:#"http://example.com/download.zip"];
NSURLRequest *request = [NSURLRequest requestWithURL:URL];
NSURLSessionDownloadTask *downloadTask = [manager downloadTaskWithRequest:request progress:nil destination:^NSURL *(NSURL *targetPath, NSURLResponse *response) {
NSURL *documentsDirectoryURL = [[NSFileManager defaultManager] URLForDirectory:NSDocumentDirectory inDomain:NSUserDomainMask appropriateForURL:nil create:NO error:nil];
return [documentsDirectoryURL URLByAppendingPathComponent:[response suggestedFilename]];
} completionHandler:^(NSURLResponse *response, NSURL *filePath, NSError *error) {
NSLog(#"File downloaded to: %#", filePath);
}];
[downloadTask resume];
NB! Code work with iOS 7+ (tested with AFNetworking 2.5.1)
From AFNetworking docs.
Save to loaded file to your documents.
AFNetworking 3.0
NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
AFURLSessionManager *manager = [[AFURLSessionManager alloc] initWithSessionConfiguration:configuration];
NSURL *URL = [NSURL URLWithString:#"http://example.com/download.zip"];
NSURLRequest *request = [NSURLRequest requestWithURL:URL];
NSURLSessionDownloadTask *downloadTask = [manager downloadTaskWithRequest:request progress:nil destination:^NSURL *(NSURL *targetPath, NSURLResponse *response) {
NSURL *documentsDirectoryURL = [[NSFileManager defaultManager] URLForDirectory:NSDocumentDirectory inDomain:NSUserDomainMask appropriateForURL:nil create:NO error:nil];
return [documentsDirectoryURL URLByAppendingPathComponent:[response suggestedFilename]];
} completionHandler:^(NSURLResponse *response, NSURL *filePath, NSError *error) {
NSLog(#"File downloaded to: %#", filePath);
}];
[downloadTask resume];
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
manager.responseSerializer = [AFCompoundResponseSerializer serializer];
manager.responseSerializer.acceptableContentTypes = [NSSet setWithObject:#"application/octet-stream"];
AFHTTPRequestOperation *operation = [manager GET:url parameters:nil success:^(AFHTTPRequestOperation *operation, id responseObject) {
if (responseObject) {
// your code here
} else {
// your code here
}
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
}];
[operation start];
// manager.responseSerializer.acceptableContentTypes = [NSSet setWithObject: #"application/octet-stream"]; can vary depending on what you expect
Yes, it is better to use AFNetworking 2.0 way with AFHTTPRequestOperationManager. With old way my file did download but for some reason didn't update in file system.
Appending to swilliam's answer, to show download progress, in AFNetworking 2.0 you do similarly - just set download progress block after setting output stream.
__weak SettingsTableViewController *weakSelf = self;
operation.outputStream = [NSOutputStream outputStreamToFileAtPath:newFilePath append:NO];
[operation setDownloadProgressBlock:^(NSUInteger bytesWritten, long long totalBytesWritten, long long totalBytesExpectedToRead) {
float progress = totalBytesWritten / (float)totalBytesExpectedToRead;
NSString *progressMessage = [NSString stringWithFormat:#"%# \n %.2f %% \n %# / %#", #"Downloading ...", progress * 100, [weakSelf fileSizeStringWithSize:totalBytesWritten], [weakSelf fileSizeStringWithSize:totalBytesExpectedToRead]];
[SVProgressHUD showProgress:progress status:progressMessage];
}];
This is my method to create bytes string:
- (NSString *)fileSizeStringWithSize:(long long)size
{
NSString *sizeString;
CGFloat f;
if (size < 1024) {
sizeString = [NSString stringWithFormat:#"%d %#", (int)size, #"bytes"];
}
else if ((size >= 1024)&&(size < (1024*1024))) {
f = size / 1024.0f;
sizeString = [NSString stringWithFormat:#"%.0f %#", f, #"Kb"];
}
else if (size >= (1024*1024)) {
f = size / (1024.0f*1024.0f);
sizeString = [NSString stringWithFormat:#"%.0f %#", f, #"Mb"];
}
return sizeString;
}
In addition to the previous answers, with AFNetworking 2.5.0 and iOS7/8 I have found that that the extra step of opening the output stream is also needed to prevent the app from hanging (and eventually crashing from lack of memory).
operation.outputStream = [NSOutputStream outputStreamToFileAtPath:dest
append:NO];
[operation.outputStream open];
[operation start];