UIButton limiting number of presses - iphone

I got an issue with users rapidly pressing my UIButton causing multiple entries being placed in my database stored online. I have tried all sorts such as hiding the button when it the action is called and some sort of toggle, both have been unsuccessful. Is there anyway to limit the press to just one. the action is linked to the touch up inside reference on the button.
-(IBAction)postData:(id)sender
{
if(loginControl == 0)
{
if(nameIB.text.length && numberIB.text.length > 0)
{
loginControl = 1;
loginButton.hidden = YES;
NSMutableData *data = [NSMutableData data];
NSString *number = numberIB.text;
NSString *name = nameIB.text;
NSString *nameString = [[NSString alloc] initWithFormat:#"name=%#", name];
NSString *numberString = [[NSString alloc] initWithFormat:#"&number=%#", number];
NSString *genderString = [[NSString alloc] initWithFormat:#"&gender=%#", gender];
//NSLog(nameString);
//NSLog(numberString);
[data appendData:[nameString dataUsingEncoding:NSUTF8StringEncoding]];
[data appendData:[numberString dataUsingEncoding:NSUTF8StringEncoding]];
[data appendData:[genderString dataUsingEncoding:NSUTF8StringEncoding]];
NSURL *url = [NSURL URLWithString:#"http://www.blah.net/blah.php"];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
[request setHTTPMethod:#"POST"];
[request setHTTPBody:data];
NSURLResponse *response;
NSError *err;
NSData *responseData = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&err];
NSLog(#"responseData: %#", responseData);
userData = responseData;
[self startParsingUserId];
logoutButton.hidden = NO;
}
else {
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Text Fields Empty" message:#"One Or More Textfields Are Empty" delegate:self cancelButtonTitle:#"Cancel" otherButtonTitles:nil];
[alert show];
[alert release];
loginControl = 0;
}
}
}

You should immediately be setting the enabled or hidden property of the button to disable interaction.
HOWEVER that change will not take effect until the next turn of the runloop, when everything gets re-drawn. As your code stands, your code is hiding the button, doing stuff, and then unhiding the button, all before the button gets a chance to redraw.
What you should do is set the hidden property and then start the computation (preferably on a background thread). Once and only once the computation completes, you should signal the main thread to un-hide the button again.
If you are OK with having this only work on iOS 4.0+, you can easily accomplish this with Grand Central Dispatch:
- (IBAction)doStuff:(id)sender {
[button setEnabled:NO];
dispatch_async(dispatch_get_global_queue(0,0), ^{
// do all your computation/synchronous requesting here
// this will happen on a background thread
dispatch_async(dispatch_get_main_queue(), ^{
[button setEnabled:YES];
});
});
}

In the button's selector, use -performSelectorOnMainThread:withObject:waitUntilDone: to run a chunk of code that disables the button until the method's logic is complete.

Related

UIAlertView is showing up late

I am communicating with server in my ios app. I have following method in which I'm opening an alertview. I want to show a loading view while app is getting response from the server.
- (void) showDetailedQuestion:(id)sender
{
//loading view
self.loading_alert = [[UIAlertView alloc] initWithTitle:#"Loading\nPlease Wait..." message:nil delegate:self cancelButtonTitle:nil otherButtonTitles: nil];
[self.loading_alert show];
UIActivityIndicatorView *indicator = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhiteLarge];
// Adjust the indicator so it is up a few pixels from the bottom of the alert
indicator.center = CGPointMake(loading_alert.bounds.size.width / 2, loading_alert.bounds.size.height - 50);
[indicator startAnimating];
[self.loading_alert addSubview:indicator];
UIButton *btn = (UIButton*)sender;
int indx = btn.tag;
NSLog(#"tag:%d",indx);
answerAnQuestion *vc = [self.storyboard instantiateViewControllerWithIdentifier:#"Answer"];
vc.modalTransitionStyle = UIModalTransitionStyleFlipHorizontal ;
vc.que_id = [self.que_id valueForKey:[NSString stringWithFormat:#"%d",indx]];
vc.qid_list = self.que_id;
vc.crnt = indx;
[self presentViewController:vc animated:YES completion:nil];
[self.loading_alert dismissWithClickedButtonIndex:0 animated:YES];
}
and in another answerAnQuestion.m
- (void)viewDidLoad
{
NSString *address = [NSString stringWithFormat:#"%#%#%#%#%#%#%#", path,#"questions/",que_id,#"?token=",token,#"&user_id=",usrId];
NSURL *URL = [NSURL URLWithString:address];
NSLog(#"%#",address);
[NSURLRequest setAllowsAnyHTTPSCertificate:YES forHost:[URL host]];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:URL cachePolicy:NSURLCacheStorageAllowedInMemoryOnly
timeoutInterval:60.0];
[request setHTTPMethod:#"GET"];
responseData = [[NSMutableData alloc] init];
NSURLResponse *response = nil;
NSError *error = nil;
NSData *data = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
if (data)
{
NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse*) response;
//If you need the response, you can use it here
int statuscode = [httpResponse statusCode];
NSString *responseMsg = [NSHTTPURLResponse localizedStringForStatusCode:statuscode];
NSLog(#" Status code: %d",statuscode );
NSLog(#" Status msg: %#",responseMsg );
}
else
{
// Handle error by looking at response and/or error values
NSLog(#"%#",error);
}
}
My problem is alertview is only shown up for a moment when view is changing. It suppose to open when I click the button. What could be the reason? how to solve this?
EDIT 1:
If i make asynchronous request to server then i'm not able to set those data in my tableview. I can set those data in my tableview Only if send synchronous request,but it blocks the app. Why this is happening ?
Any help will be appreciated.
Thank you.
You are sending SynchronousRequest on main thread, so it is blocking your UI thread. Read multithreading you will get various tutorial on this. I can suggest you to go for GCD or NSOperation and NSOperationQueue. Google for any of the above and you will get various sample for the same.
Or you can send asynchronous request as follows...
[NSURLConnection sendAsynchronousRequest:request queue:[[NSOperationQueue alloc] init] completionHandler:^(NSURLResponse *response, NSData *data, NSError *error){
//Write code you want to call when data is received,
//Like dismissing loading view and populating UI.
}];
Updated:
//Display alert view, before sending your request..
[alertview show];
//send first request
[NSURLConnection sendAsynchronousRequest:request1 queue:[[NSOperationQueue alloc] init] completionHandler:^(NSURLResponse *response, NSData *data, NSError *error){
//Write code you want to call when data is received,
//send second request
[NSURLConnection sendAsynchronousRequest:request2 queue:[[NSOperationQueue alloc] init] completionHandler:^(NSURLResponse *response, NSData *data, NSError *error){
//Write code you want to call when data is received,
//send third request
[NSURLConnection sendAsynchronousRequest:request3 queue:[[NSOperationQueue alloc] init] completionHandler:^(NSURLResponse *response, NSData *data, NSError *error){
//Write code you want to call when data is received,
//dismiss alert view on main thread
dispatch_async(getmainqueue, ^(void) {
// dismiss alert view...
});
}];
}];
}];
I have worked with Nuzhat Zari code, and I thank him for it, but also have experienced some issues with some core data operations between nested "sendAsynchronousRequest" (getting some weird thread and memory errors) so, my solution was unnest the calls to "sendAsynchronousRequest" and use some main thread variable validation.
#interface myMainThreadClass
#property (nonatomic,assign) NSInteger *currentAsyncTasks;
#end
#implementation
// Use init or viewDidLoad to make "currentAsyncTasks=0"!!
-(void)method
{
[self showLoadingAlert]; //or some ui update function
currentAsyncTasks++;
[NSURLConnection sendAsynchronousRequest:urlRequest queue:[[NSOperationQueue alloc] init] completionHandler:^(NSURLResponse *response, NSData *data, NSError *error){
//do something with data
dispatch_async(dispatch_get_main_queue(), ^(void) {
[self dismissAlertInFinalTask]
});
}];
currentAsyncTasks++;
[NSURLConnection sendAsynchronousRequest:urlRequest2 queue:[[NSOperationQueue alloc] init] completionHandler:^(NSURLResponse *response, NSData *data, NSError *error){
//do something with data
dispatch_async(dispatch_get_main_queue(), ^(void) {
[self dismissAlertInFinalTask]
});
}];
currentAsyncTasks++;
[NSURLConnection sendAsynchronousRequest:urlRequest3 queue:[[NSOperationQueue alloc] init] completionHandler:^(NSURLResponse *response, NSData *data, NSError *error){
//do something with data
dispatch_async(dispatch_get_main_queue(), ^(void) {
[self dismissAlertInFinalTask]
});
}];
}
-(void)dismissAlertInFinalTask
{
currentNetworkTasks--;
if (currentNetworkTasks == 0)
{
[self dismissLoadingAlert];//or some ui update function;
}
}
#end
I also want to know if someone has managed to do multiple request using NSURLConnection delegate NSURLConnectionDataDelegate and ui calls.

how to show activity indicator in iphone application while uploading data

I am uploading data to server i want that when i click upload button then activity indicator should start and stop after the data is uploaded.
This is how i am uploading data but activity indicator not working.
-(IBAction)startSyncButtonAction{
[self startActivity];
CereniaAppDelegate *appDelegate = (CereniaAppDelegate *)[[UIApplication sharedApplication] delegate];
for (int i=0; i<[appDelegate.coffeeArray count]; i++) {
Coffee *coffeeObj = [appDelegate.coffeeArray objectAtIndex:i];
int mycount=[appDelegate.coffeeArray count];
NSLog(#"My Array count is %d",mycount);
NSString*device_Id=coffeeObj.device_Id;
NSString*R1=coffeeObj.R1;
NSString*R2=coffeeObj.R2;
NSString*R3=coffeeObj.R3;
NSString*R4=coffeeObj.R4;
NSString*R5=coffeeObj.R5;
NSString*R6=coffeeObj.R6;
NSString*R7=coffeeObj.R7;
NSString*R8=coffeeObj.R8;
NSString*R9=coffeeObj.R9;
NSString*R10=coffeeObj.R10;
NSString*R11=coffeeObj.R11;
NSString*R12=coffeeObj.R12;
NSString*R13=coffeeObj.R13;
NSString*R14=coffeeObj.R14;
NSString*update_date_time=coffeeObj.update_date_time;
NSString*teritory1=coffeeObj.teritory;
int mycount1=[appDelegate.coffeeArray count];
NSLog(#"My Array After delete is %d",mycount1);
NSLog(#"device_Id%#",device_Id);
NSLog(#"R1%#",R1);
NSLog(#"R2%#",R2);
NSLog(#"R3%#",R3);
NSLog(#"R4%#",R4);
NSLog(#"R4%#",R5);
NSLog(#"R4%#",R6);
NSLog(#"R4%#",R7);
NSLog(#"R4%#",R8);
NSLog(#"R4%#",R9);
NSLog(#"R4%#",R10);
NSLog(#"R4%#",R11);
NSLog(#"R4%#",R12);
NSLog(#"R4%#",R13);
NSLog(#"R4%#",R14);
NSLog(#"update_date_time%#",update_date_time);
NSString *post =[[NSString alloc] initWithFormat:#"device_Id=%#&R1=%#&R2=%#&R3=%#&R4=%#&R5=%#&R6=%#&R7=%#&R8=%#&R9=%#&R10=%#&R11=%#&R12=%#&R13=%#&R14=%#&update_date_time=%#&teritory1=%#",device_Id,R1,R2,R3,R4,R5,R6,R7,R8,R9,R10,R11,R12,R13,R14,update_date_time,teritory1];
NSLog(post);
NSURL *url=[NSURL URLWithString:#"http://celeritas-solutions.com/pah_brd_v1/pfizersurvey/SyncSurveySTD.php"];
NSData *postData = [post dataUsingEncoding:NSASCIIStringEncoding allowLossyConversion:YES];
NSString *postLength = [NSString stringWithFormat:#"%d", [postData length]];
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init] ;
[request setURL:url];
[request setHTTPMethod:#"POST"];
[request setValue:postLength forHTTPHeaderField:#"Content-Length"];
[request setValue:#"application/x-www-form-urlencoded" forHTTPHeaderField:#"Content-Type"];
[request setHTTPBody:postData];
NSError *error;
NSURLResponse *response;
NSData *urlData=[NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
NSString *data=[[NSString alloc]initWithData:urlData encoding:NSUTF8StringEncoding];
NSLog(#"%#",data);
}
for (int i=0; i<[appDelegate.coffeeArray count]; i++) {
Coffee *coffeeObj = [appDelegate.coffeeArray objectAtIndex:i];
[appDelegate removeCoffee:coffeeObj];
}
}
-(void)startActivity:(id)sender
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
activityImageView.hidden=NO;
activityView.hidden=NO;
[activityView startAnimating];
[pool release];
}
Try below code but I am giving example you should modify it & use according to your need:
alert= [[UIAlertView alloc] initWithTitle:#"Loading\nPlease Wait..." message:nil delegate:self cancelButtonTitle:nil otherButtonTitles: nil];
[alert show];
UIActivityIndicatorView *indicator = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhiteLarge];
indicator.center = CGPointMake(150, 100);
[indicator startAnimating];
[alert addSubview:indicator];
Use this line to dismiss indicator:
[alert dismissWithClickedButtonIndex:0 animated:YES];
Try. Best of luck.
For better user experience i will recommend you to use UIProgressHUD
UIProgressHUD* hud = [[UIProgressHUD alloc] initWithFrame:CGRectZero];
[hud setText:#"Loading, please wait."];
[hud showInView:someView];
...
[hud done];
...
[hud hide];
...
[hud release];
Are you 100% sure that activityView is not nil?? I don't see anywhere you set it to anything. Also, even it were not nil, have you added it to a view? activityView is just a regular UIView, it won't automatically appear in UIWindows.

iPhone/Objective-C: How to modify UILabel from timer

I have the following timer:
uploadGPS_timer=[NSTimer scheduledTimerWithTimeInterval:5.0 target:self selector:#selector(uploadGPS_tick:) userInfo:nil repeats:YES];
[self uploadGPS_tick:nil];
And here is the callback: uploadGPS_tick():
-(void)uploadGPS_tick:(NSTimer*)timer{
if(!lat || !lng){
//do nothing
}else{
NSString *urlStr=[[NSString alloc] initWithFormat:#"http://www.example.com/ajax/updateCoords.php"];
NSURL *url=[NSURL URLWithString:urlStr];
__block ASIFormDataRequest *request=[[ASIFormDataRequest alloc ]initWithURL:url];
[request setPostValue:lat forKey:#"lat"];
[request setPostValue:lng forKey:#"lng"];
NSLog(#"EOH: %#",lat);
[request setDelegate:self];
[request setCompletionBlock:^{
NSString *response=[request responseString];
NSLog(#"%#",response);
if([response isEqualToString:#"LO"]){
[self.navigationItem setBackBarButtonItem:nil];
DriverLogin *x= [[DriverLogin alloc] initWithNibName:nil bundle:nil];
[[self navigationController]pushViewController:x animated:NO];
}
SBJsonParser *parser=[[SBJsonParser alloc]init];
NSMutableDictionary *obj=[[NSMutableDictionary alloc]init ];
obj=[[parser objectWithString:[request responseString] error:nil]retain];
credits.text=[[obj objectForKey:#"credits"] stringValue]; //this won't show...
creditsUsed.text=[[obj objectForKey:#"creditsUsed"] stringValue]; //this won't show...
NSInteger timeLeftSecs=[[obj objectForKey:#"creditTimeLeft"] intValue];
NSInteger timeLeftMins=(int)(timeLeftSecs/60);
creditTimeLeft.text=[[NSString alloc]initWithFormat:#"%d",timeLeftMins]; //this won't show...
NSLog(#"xxx:%#",obj);
}];
[request setFailedBlock:^{
NSError *error =[request error];
NSLog(#"%#",error);
//do nothing
}];
[request startAsynchronous];
}
}
As you can see, every five seconds, a JSON object is sent from the server. This JSON object is then parsed and three UILabels are set based on this JSON data.
The trouble I'm having is that the UILabels aren't getting their text set! Even though I can clearly see NSLog(#"xxx:%#",obj); in the debugger. The UILabels are connected properly in the .xib.
Any help greatly appreciated.
You should do it from main thread. Replace the label text assignment with following code:
dispatch_async(dispatch_get_main_queue(), ^{
creditTimeLeft.text=[NSString stringWithFormat:#"%d",timeLeftMins];
});

UITabBar with UIWebView problem with switching views

I have an app which has UITabBar with 5 views, each attached to a different UIWebView. Each of the WebViews responds to:
webViewDidStartLoad:(UIWebView *)webView
webViewDidFinishLoad:(UIWebView *)webView
Those two are responsible for displaying a loading screen (separate image for each tab, toggled visible or not) and activity indicator.
It all works fine when the page is loaded to WebView. User taps a link on the page, loading image is displayed along with the activity indicator. When the page is loaded they both disappear and new website is presented.
The problem is when user taps on one of the TabBar items. App intercepts the event and launches a method in appropriate view, which is refreshing the page.
The problem: after the tap view changes immediately to the other WebView, however loading screen takes a long time to appear (from what I gather it only shows when the page passed to homeView starts loading) and I can't figure out why. Displaying loading items is the first thing the app should do after method is called.
Here is the code that calls a method from TabBar controller:
[hv performSelector:#selector(goToPage) withObject:nil afterDelay:0.0];
and here is the goToPage method:
- (void) goToPage
{
homeView.delegate = self;
self.showLoading;
NSURL *url = [NSURL URLWithString: [NSString stringWithFormat: #"%#/seed.php", appURL]];
NSString *body = [NSString stringWithFormat: #"uid=%#", uID];
NSData *data = [body dataUsingEncoding:NSUTF8StringEncoding];
NSMutableURLRequest *request = [[NSMutableURLRequest alloc]initWithURL:url];
[request setHTTPMethod: #"POST"];
[request setHTTPBody: data];
NSData *responseData = [NSURLConnection sendSynchronousRequest:request returningResponse:nil error:nil];
[request release];
NSString *seedString = [[NSString alloc] initWithData:responseData encoding:NSUTF8StringEncoding];
NSArray *seedArray = [seedString componentsSeparatedByString:#":::"];
NSString *eventNumber = [[seedArray objectAtIndex:0] retain];
NSString *passedSid = [[seedArray objectAtIndex:1] retain];
if (!seedString) {
// can't connect
NSLog(#"Can't connect.");
}else {
// connected
NSLog(#"Events: %#", eventNumber);
if(![evtNo isEqualToString:eventNumber]){
evtNo = eventNumber;
if(![evtNo isEqualToString:#"0"]){
AudioServicesPlaySystemSound (kSystemSoundID_Vibrate);
}
}
}
NSURL *urlView = [NSURL URLWithString: [NSString stringWithFormat: #"%#/index.php", appURL]];
NSString *bodyView = [NSString stringWithFormat: #"sid=%#", passedSid];
NSData *dataView = [bodyView dataUsingEncoding:NSUTF8StringEncoding];
NSMutableURLRequest *requestView = [[NSMutableURLRequest alloc]initWithURL:urlView];
[requestView setHTTPMethod: #"POST"];
[requestView setHTTPBody: dataView];
[homeView loadRequest: requestView];
if([evtNo isEqualToString:#"0"]){
// clearing badge
[[[[[self tabBarController] viewControllers] objectAtIndex: 0] tabBarItem] setBadgeValue: nil];
}else{
[[[[[self tabBarController] viewControllers] objectAtIndex: 0] tabBarItem] setBadgeValue: evtNo];
}
}
The goal I have is to display the loading image the moment user taps the TabBar item and remain visible until page stops loading.
The solution to this issue was to launch the method goToPage without the delay, display loading screen in goToPage and move the time consuming bits into another method inside that class, launched using persormSelector.

Uploading Video with iPhone

Is it possible to upload video to a server? I know that images are possible.
If someone can just point me in the right direction that would be awesome.
Thanks
Edited Aug 2015
This answer is now seriously out of date. At the time of writing there weren't to many options and videos were relatively small in size.
If you are looking at doing this now, I would use AFNetworking which makes this much simpler. It will stream the upload from file rather than holding it all in memory, and also supports the new Apple background upload Task.
Docs here: https://github.com/AFNetworking/AFNetworking#creating-an-upload-task
--
Yes this is possible and this is how i went about it.
Implement the following function which runs when the media picker is finished.
- (NSData *)generatePostDataForData:(NSData *)uploadData
{
// Generate the post header:
NSString *post = [NSString stringWithCString:"--AaB03x\r\nContent-Disposition: form-data; name=\"upload[file]\"; filename=\"somefile\"\r\nContent-Type: application/octet-stream\r\nContent-Transfer-Encoding: binary\r\n\r\n" encoding:NSASCIIStringEncoding];
// Get the post header int ASCII format:
NSData *postHeaderData = [post dataUsingEncoding:NSASCIIStringEncoding allowLossyConversion:YES];
// Generate the mutable data variable:
NSMutableData *postData = [[NSMutableData alloc] initWithLength:[postHeaderData length] ];
[postData setData:postHeaderData];
// Add the image:
[postData appendData: uploadData];
// Add the closing boundry:
[postData appendData: [#"\r\n--AaB03x--" dataUsingEncoding:NSASCIIStringEncoding allowLossyConversion:YES]];
// Return the post data:
return postData;
}
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info{
//assign the mediatype to a string
NSString *mediaType = [info objectForKey:UIImagePickerControllerMediaType];
//check the media type string so we can determine if its a video
if ([mediaType isEqualToString:#"public.movie"]){
NSLog(#"got a movie");
NSURL *videoURL = [info objectForKey:UIImagePickerControllerMediaURL];
NSData *webData = [NSData dataWithContentsOfURL:videoURL];
[self post:webData];
[webData release];
}
for the post function i had something like this which i got from somewhere else (sorry i dont know where i found it):
- (void)post:(NSData *)fileData
{
NSLog(#"POSTING");
// Generate the postdata:
NSData *postData = [self generatePostDataForData: fileData];
NSString *postLength = [NSString stringWithFormat:#"%d", [postData length]];
// Setup the request:
NSMutableURLRequest *uploadRequest = [[[NSMutableURLRequest alloc] initWithURL:[NSURL URLWithString:#"http://www.example.com:3000/"] cachePolicy: NSURLRequestReloadIgnoringLocalCacheData timeoutInterval: 30 ] autorelease];
[uploadRequest setHTTPMethod:#"POST"];
[uploadRequest setValue:postLength forHTTPHeaderField:#"Content-Length"];
[uploadRequest setValue:#"multipart/form-data; boundary=AaB03x" forHTTPHeaderField:#"Content-Type"];
[uploadRequest setHTTPBody:postData];
// Execute the reqest:
NSURLConnection *conn=[[NSURLConnection alloc] initWithRequest:uploadRequest delegate:self];
if (conn)
{
// Connection succeeded (even if a 404 or other non-200 range was returned).
NSLog(#"sucess");
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Got Server Response" message:#"Success" delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil];
[alert show];
[alert release];
}
else
{
// Connection failed (cannot reach server).
NSLog(#"fail");
}
}
The above snippet builds the http post request and submits it. You will need to modify it if you want decent error handling and consider using a library that allows async upload (theres one on github)
Also Notice the port :3000 on the server url above, I found it easy for bug testing to start a rails server on its default port 3000 in development mode so i could see the request parameters for debugging purposes
Hope this helps
Since iOS8 there is no need to use 3rd party libraries and you can stream video directly from the file which solves crucial OUT OF MEMORY ERROR when you try to upload bigger videos while loading them from file:
// If video was returned by UIImagePicker ...
NSURL *videoUrl = [_videoDictionary objectForKey:UIImagePickerControllerMediaURL];
NSMutableURLRequest *request =[[NSMutableURLRequest alloc] init];
[request setURL:[NSURL URLWithString:VIDEO_UPLOAD_LINK]];
[request addValue:#"video" forHTTPHeaderField: #"Content-Type"];
[request setHTTPMethod:#"POST"];
NSInputStream *inputStream = [[NSInputStream alloc] initWithFileAtPath:[videoUrl path]];
[request setHTTPBodyStream:inputStream];
self.uploadConnection = [[NSURLConnection alloc] initWithRequest:request delegate:self startImmediately:YES];
iOS7 also offers great NSURLSeession / NSURLSessionUploadTask combo solution, which not only let's you stream directly from the file, but can also delegate task to the iOS process, which will let upload to finish even when your app is closed.
It requires a bit more coding and I have no time to write it all here (you can Google it).
Here are the most crucial parts:
Confugure audio session in background support:
-(NSURLSession *)urlSession{
if (!_urlSession) {
NSDictionary *infoDict = [[NSBundle mainBundle] infoDictionary];
NSString *bundleId = infoDict[#"CFBundleIdentifier"];
NSString *label = [NSString stringWithFormat:#"ATLoggerUploadManager_%#", bundleId];
NSURLSessionConfiguration *conf = (floor(NSFoundationVersionNumber) > NSFoundationVersionNumber_iOS_7_1) ? [NSURLSessionConfiguration backgroundSessionConfigurationWithIdentifier:label] : [NSURLSessionConfiguration backgroundSessionConfiguration:label];
conf.allowsCellularAccess = NO;
_urlSession = [NSURLSession sessionWithConfiguration:conf delegate:self delegateQueue:self.urlSessionQueue];
_urlSession.sessionDescription = #"Upload log files";
}
return _urlSession;
}
Upload task method:
-(NSURLSessionUploadTask *)uploadTaskForFilePath:(NSString *)filePath session:(NSURLSession *)session{
NSFileManager *fm = [NSFileManager defaultManager];
NSError *error = nil;
// Consruct request:
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init];
[request setHTTPMethod:#"POST"];
NSString *finalUrlString = [self.uploadURL absoluteString];
if (self.uploadUserId) {
[request setValue:self.uploadUserId forHTTPHeaderField:#"X-User-Id"];
finalUrlString = [finalUrlString stringByAppendingFormat:#"?id=%#", self.uploadUserId];
}
[request setURL:[NSURL URLWithString:finalUrlString]];
/*
It looks like this (it only works if you quote the filename):
Content-Disposition: attachment; filename="fname.ext"
*/
NSString *cdh = [NSString stringWithFormat:#"attachment; filename=\"%#\"", [filePath lastPathComponent]];
[request setValue:cdh forHTTPHeaderField:#"Content-Disposition"];
error = nil;
unsigned long fileSize = [[fm attributesOfItemAtPath:filePath error:&error] fileSize];
if (!error) {
NSString *sizeInBytesAsString = [NSString stringWithFormat:#"%lu", fileSize];
[request setValue:sizeInBytesAsString forHTTPHeaderField:#"X-Content-Length"];
}
NSURL *fileUrl = [NSURL fileURLWithPath:filePath];
NSURLSessionUploadTask *uploadTask = [session uploadTaskWithRequest:request fromFile:fileUrl];
uploadTask.taskDescription = filePath;
return uploadTask;
}
Upload function:
[self.urlSession getTasksWithCompletionHandler:^(NSArray *dataTasks, NSArray *uploadTasks, NSArray *downloadTasks) {
NSMutableDictionary *tasks = [NSMutableDictionary new];
int resumed_running_count = 0;
int resumed_not_running_count = 0;
int new_count = 0;
// 1/2. Resume scheduled tasks:
for(NSURLSessionUploadTask *task in uploadTasks) {
//MILogInfo(#"Restored upload task %zu for %#", (unsigned long)task.taskIdentifier, task.originalRequest.URL);
if (task.taskDescription) {
[tasks setObject:task forKey:task.taskDescription];
}
BOOL isRunning = (task.state == NSURLSessionTaskStateRunning);
if (!isRunning) {
resumed_not_running_count++;
}else{
resumed_running_count++;
}
[task resume];
}
// 2/2. Add tasks / files not scheduled yet:
NSString *uploadFilePath = nil;
// already uploading:
if (![tasks valueForKey:uploadFilePath]) {
NSURLSessionUploadTask *uploadTask = [self uploadTaskForFilePath:uploadFilePath session:_urlSession];
new_count++;
[uploadTask resume];
}
}];
Background session requires UIApplecation delegate (AppDelegate callback implemented:
(void)application:(UIApplication *)application handleEventsForBackgroundURLSession:(NSString *)identifier completionHandler:(void (^)())completionHandler
{
NSLog(#"Background URL session needs events handled: %#", identifier);
completionHandler();
}
Have a look at the UIImagePickerController.
As of 3.0 you can allow the choose to shoot a video or pick an existing video. According to the docs you're limited to 10min max on the movie though:
http://developer.apple.com/IPhone/library/documentation/UIKit/Reference/UIImagePickerController_Class/UIImagePickerController/UIImagePickerController.html
NSURL *urlvideo = [info objectForKey:UIImagePickerControllerMediaURL];
NSString *urlString=[urlvideo path];
NSLog(#"urlString=%#",urlString);
NSString *str = [NSString stringWithFormat:#"you url of server"];
NSURL *url = [NSURL URLWithString:[str stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
ASIFormDataRequest *request = [ASIFormDataRequest requestWithURL:url];
[request setFile:urlString forKey:#"key foruploadingFile"];
[request setRequestMethod:#"POST"];
[request setDelegate:self];
[request startSynchronous];
NSLog(#"responseStatusCode %i",[request responseStatusCode]);
NSLog(#"responseStatusCode %#",[request responseString]);