DownLoad Data from server with "Pause" and "Resume" functionality - ios

I want to download a file with pause/resume functionality. I read apple documents, there I got NSUrldownload which supports the same but it is not available for iOS. I was trying with NSUrlconnection, but not working. I don't want to use any third party libraries, I want to implement it by myself, below is the code snippet which I tried.
NSString *fileName = [NSString stringWithFormat:#"~%#",[[url componentsSeparatedByString:#"/"] lastObject]];
int dataLength = [[self checkDocDirectoryforFileName:fileName] length];
//dataLength = 0;
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:url]];
[request setValue:#"audio/mpeg" forHTTPHeaderField:#"Content-Type"];
[request setValue:#"bytes" forHTTPHeaderField:#"Accept-Ranges"];
[request setValue:#"Keep-Alive" forHTTPHeaderField:#"Connection"];
[request setValue:[NSString stringWithFormat:#"%d",dataLength] forHTTPHeaderField:#"Content-Length"];
NSLog(#"Request header %#", [request allHTTPHeaderFields]);
NSURLConnection *conn = [NSURLConnection connectionWithRequest:request delegate:self];

Please check it out this:
https://developer.apple.com/library/ios/documentation/Cocoa/Conceptual/URLLoadingSystem/Tasks/UsingNSURLDownload.html#//apple_ref/doc/uid/20001839-SW2
Hope, May it will help you,
:)

iOS 7.0 and above
NSURLSession especially NSURLSessionDownloadTask provides this functionality.
The NSURLSession API provides status and progress properties, in
addition to delivering this information to delegates. It supports
canceling, restarting or resuming, and suspending tasks, and it
provides the ability to resume suspended, canceled, or failed
downloads where they left off.
Take a look to the docs.
iOS 5.0 and above
I would use AFDownloadRequestOperation for this. Take a look at this thread.
AFDownloadRequestOperation has
additional support to resume a partial download, uses a temporary
directory and has a special block that helps with calculating the
correct download progress.

Related

Using NSURLSession to POST, what is the correct way to post the variables?

I am following this tutorial: http://www.raywenderlich.com/2965/how-to-write-an-ios-app-that-uses-a-web-service. Trying to set up a basic web service. Seems like the tutorial is old material and ASIHTTPRequest is no longer continued. I have been trying to use NSURLRequest instead. First question, is NSURLRequest a pretty standard way to be doing this? I just want something for basic GET, POST etc, should I be doing it a different way?
My code is:
-(BOOL)textFieldShouldReturn:(UITextField *)textField{
NSLog(#"We want to unlock for the code %#",self.textField.text);
//Get a device ID, (actually can't do this aymore)
NSString *uniqueIdentifier = #"My iPhone";
NSString *code = self.textField.text;
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:#"http://www.madasd.co/promos/"]];
request.HTTPMethod=#"POST";
//Set the header fields
[request setValue:#"application/xml; charset=utf-8" forHTTPHeaderField:#"Content-Type"];
NSString *myString = [NSString stringWithFormat:#"rw_app_id=1&code=%#&device_id=%#",code,uniqueIdentifier];
NSLog(#"%#",myString);
NSData *requestBodyData = [myString dataUsingEncoding:NSUTF8StringEncoding];
request.HTTPBody=requestBodyData;
//Create url and fire request
NSURLConnection *conn = [[NSURLConnection alloc] initWithRequest:request delegate:self startImmediately:NO];
[conn start];
return TRUE;
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data{
NSString *string = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSLog(#"%#",string);
}
Second question, I have tested the backend using curl so I know it works fine, however the response I get is "Invalid Request", I think this is because the string I am sending is not correct. Am I doing this correct using the var names and & operators? Any pointers on this would be great! thanks. (Running a LAMP server on Linode!)
EDIT:
Also tried sending as JSON:
[request addValue:#"application/json" forHTTPHeaderField:#"Content-Type"];
[request addValue:#"application/json" forHTTPHeaderField:#"Accept"];
NSDictionary *mapData = [[NSDictionary alloc]initWithObjectsAndKeys:#"1",#"rw_app_id",code,#"code",uniqueIdentifier,#"device_id", nil];
NSError *error = nil;
NSData *requestBodyData = [NSJSONSerialization dataWithJSONObject:mapData options:0 error:&error];
request.HTTPBody=requestBodyData;
Still getting the same error.
A couple of thoughts:
Don't use NSURLConnection. It is deprecated as of iOS 9. Use NSURLSession. See Using NSURLSession in the URL Loading System Programming Guide.
Decide what type of request you need to prepare. You specified application/xml in your header, but are creating a application/x-www-form-urlencoded request. Your Content-Type header must match how you're building the HTTPBody.
What type of request does your server require? x-www-form-urlencoded? XML? JSON?
Also, what type of response does your server provide?
If building a application/x-www-form-urlencoded request (as suggested by the body of your request), you are not properly percent escaping the values (see https://stackoverflow.com/a/20398755/1271826).
If you use delegate based NSURLConnection or NSURLSession, you should not just grab the results in didReceiveData. What you need to do is
Instantiate a NSMutableData before starting the request;
Have didReceiveData merely append to that NSMutableData;
Only when connectionDidFinishLoading: (in NSURLConnection) or URLSession:task:didCompleteWithError: (in NSURLSession) is called, should you then use the NSMutableData.
Alternatively, if using the block-based NSURLSession, this concern is completely eliminated (since you're not implementing any delegate methods). Using completionHandler-based methods of NSURLSession is much easier.
If all of this is too complicated, you might consider using AFNetworking's AFHTTPSessionManager (but not AFHTTPRequestOperationManager) to build your requests. It gets you out of the weeds of properly building requests, implementing delegate methods, etc.
You might need to wrap the strings into a dictionary and get the NSData object from a call to NSJSONSerialization. Though it depends on the form expected by the server.

set flag before connection start

in viewDidLoad I want to call webservice for several times.
So my code in viewDidLoad is as follows
//Webservice call for industry list
NSURL *aUrl = [NSURL URLWithString:[NSString stringWithFormat:#"%#index.php/industry/industrylist",baseurl]];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:aUrl
cachePolicy:NSURLRequestUseProtocolCachePolicy
timeoutInterval:60.0];
[request setHTTPMethod:#"POST"];
[request setHTTPBody:[#"emailid=b#b.com&password=1234" dataUsingEncoding:NSUTF8StringEncoding]];
NSURLConnection *connection= [[NSURLConnection alloc] initWithRequest:request delegate:self];
//set flag for industryList
flag = #"industry";
[connection start];
//Webservice call for function list
NSURL *bUrl = [NSURL URLWithString:[NSString stringWithFormat:#"%#index.php/functionmdl/allFunctionlist",baseurl]];
NSMutableURLRequest *requestb = [NSMutableURLRequest requestWithURL:bUrl
cachePolicy:NSURLRequestUseProtocolCachePolicy
timeoutInterval:60.0];
[requestb setHTTPMethod:#"POST"];
[requestb setHTTPBody:[#"" dataUsingEncoding:NSUTF8StringEncoding]];
NSURLConnection *connectionb = [[NSURLConnection alloc] initWithRequest:requestb delegate:self];
//set flag for industryList
flag = #"functionmdl";
[connectionb start];
But the value of flag is always set to functionmdl because i have assigned the flag with the string at the just previous line of the last line in the above code. I know that i am setting the flag in wrong way. So, please let me know how can i set flag here. Basically i want to use these flag in connectionDidFinishLoading method.
i have to differentiate the webservice response data according to webservice call.
Please help me to resolve this.
I think you can use the connection.currentRequest.URL to distinguish the request.
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
NSString *strUrl = [connection.currentRequest.URL absoluteString] ;
// compare to the url of your request to distinguish them
}
There are several approaches here (none involve a flag).
The easiest is typically to use [NSURLConnection sendAsynchronousRequest:queue:completionHandler]. Then you can put your connectionDidFinishLoading code right here, specific to each request.
That doesn't work if you need more advanced features of NSURLConnectionDelegate (like responding to authentication requests). In that case, I usually recommend that you wrap up the connection and delegate into a separate object, and instantiate one for each connection. That way each object is only delegate for a single connection.
In a small number of cases, this still isn't appropriate, and in those cases you can check the connection's request in the delegate (connection.currentRequest) to determine which one you're being called about. In some cases, I've created a mutable dictionary property mapping NSURLRequest information to some other piece of metadata I wanted in the handlers.
And in the most fancy (and therefore least-often used) case, you can attach metadata (such as an identifier) to your connection using objc_setAssociatedObject, but this is seldom necessary.
But I'd look at [NSURLConnection sendAsynchronousRequest:queue:completionHandler]. It's the simplest to use and addresses the most common cases easily.

Run the ASIHTTPRequest in background when View reloads

I am developing a application which uses ASIHTTPRequest to download the content from server. When downloading if I move from Portrait to Landscape mode the downloads process is going to stop. I need the download process still to be continued.
I have searched for the solution in stackoverflow but no useful.
How can I solve this problem...
This is the piece of code i am using to download.
NSURL *downloadURL = [publisher contentURLForIssueWithName:issueTitle];
if (!networkQueue) {
networkQueue = [[ASINetworkQueue alloc] init];
}
if(!downloadURL) return;
[self performSelectorInBackground:#selector(read) withObject:nil];
request = [ASIHTTPRequest requestWithURL:downloadURL];
[request setDelegate:self];
[request setDownloadProgressDelegate:progressView];
[request setShowAccurateProgress:YES];
request.shouldContinueWhenAppEntersBackground=YES;
request.allowResumeForFileDownloads=YES;
[request startAsynchronous];
Any help to be appreciated..

NSURLConnectionDelegate callback in one function

I'm trying to make my own Request class I intend to use throughout my app. Here is the code I've been coming up with so far.
-(IIWRequest *)initAndLaunchWithDictionnary:(NSDictionary *)dictionnary
{
self=[super init];
if (self) {
// Create the request.
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:#"http://xxxxx.com/app/"]];
// Convert data
SBJsonWriter *jsonWriter = [[SBJsonWriter alloc] init];
NSString *jsonData = [jsonWriter stringWithObject:dictionnary];
NSLog(#"jsonData : %#",jsonData);
NSData *requestData = [jsonData dataUsingEncoding: NSUTF8StringEncoding];
request.HTTPBody = requestData;
// This is how we set header fields
[request setHTTPMethod:#"POST"];
[request setValue:#"application/json" forHTTPHeaderField:#"Accept"];
[request setValue:#"application/json" forHTTPHeaderField:#"Content-Type"];
[request setValue:[NSString stringWithFormat:#"%d", [requestData length]] forHTTPHeaderField:#"Content-Length"];
[request setHTTPBody: requestData];
// Create url connection and fire request
NSURLConnection *connection = [NSURLConnection connectionWithRequest:request delegate:self];
[self activateNetworkActivityIndicator];
if (connection) {
NSLog(#"Connection");
} else {
NSLog(#"No connection");
}
}
return self;
}
I have included NSURLConnectionDelegate. I'd like to fire the connection callbacks such as did finished or did fail back to the function mentioned before. The goal of all that is to get only one method to call in the end looking like :
-(IIWRequest *)initAndLaunchWithDictionnary:(NSDictionary *)dictionary inBackgroundWithBlock:^(BOOL succeeded){}
Any idea ? Thanks !
Use block method of NSURLConnection class it will reduced your functionality as well sendAsynchronousRequest:queue:completionHandler:
Read this doc.
I would hardly suggest you to use one of the currently existing libraries for calling URLs. One of the best I know is AFNetworking https://github.com/AFNetworking/AFNetworking. There is lot of examples and its easy to use and I am sure you should go with it.
Anyway, if you want to build your own class I would suggest you to read post written by Kazuki Sakamoto here NSURLConnection and grand central dispatch.
Regards
If you are using the iOS 7, I recommend A LOT you to use NSURLSession classes, this new network api is really amazing and simple.
Anyway, to answer your question, you just need to hold the reference of callback in your class and call it when you receive some response from the server.
To hold the reference, you can do something like this:
// in your .h file
typedef void (^ResponseBlock)(BOOL success);
// in your .m, create a class extension and put declare the block to use it for callback
#interface MyClass ()
{
ResponseBlock callback;
}
// You can store reference using equal like this
- (void)myMethodRequestWithResponseBlock:(ResponseBlock)responseBlock
{
callback = responseBlock;
// statements
}
// And finally, you call back block simple like this:
callback(success);
Again, use NSURLSession api if you can, you will simplify your work.
I hope this may help you.
Cheers!

How to upload images in a scrollview onto a web server?

I have an iOS app that has a series of images in a scrollview (camera pictures). I want to be able to post these on to a url individually or collectively as a group.
Can someone point me to an example or some sample code that would get me started?
Much appreciated
in that case if you if you set up your server (how do this i don`t now, because i used quickblox - ready-made solution) try send GET-request to the server. You can try this like this:
(source - How to send a Get request in iOS? )
NSString *getString = [NSString stringWithFormat:#"parameter=%#",yourvalue];
NSData *getData = [getString dataUsingEncoding:NSASCIIStringEncoding allowLossyConversion:YES];
NSString *getLength = [NSString stringWithFormat:#"%d", [getData length]];
NSMutableURLRequest *request = [[[NSMutableURLRequest alloc] init] autorelease];
[request setURL:[NSURL URLWithString:#"https:yoururl"]];
[request setHTTPMethod:#"GET"];
[request setValue:postLength forHTTPHeaderField:#"Content-Length"];
[request setValue:#"application/x-www-form-urlencoded" forHTTPHeaderField:#"Content-Type"];
[request setHTTPBody:getData];
self.urlConnection = [[[NSURLConnection alloc] initWithRequest:request delegate:self] autorelease];
NSAssert(self.urlConnection != nil, #"Failure to create URL connection.");
// show in the status bar that network activity is starting
[UIApplication sharedApplication].networkActivityIndicatorVisible = YES;
For more advanced preferences I would advise you try learn http://allseeing-i.com/ASIHTTPRequest/
For this you can create file server or use other maded. Look this: http://quickblox.com/ - they has blobs and ios api for their server, so download|upload files simple implemented in code.
First, you need register your account and then register your app.( https://admin.quickblox.com/signin ) (it's not difficult, few minuts)
Then, using instructions from site added Quickblox auth to your app and then use QBBlobs for dowload photo. Good luck!

Resources