How to check how much data send to server with three20? - iphone

I want make some progress bar in my application with three20 library when sending data to server. Can someone help me with this?
I am using
- (void)requestDidStartLoad:(TTURLRequest*)request
and
- (void)requestDidFinishLoad:(TTURLRequest*)request

You can implement
- (void)requestDidUploadData:(TTURLRequest *)request
and check the totalBytesLoaded and totalBytesExpected properties, per http://api.three20.info/protocol_t_t_u_r_l_request_delegate-p.php#a9c831806650a4b887f5cf963f6bbba1c.

I have found solution.
You must call
[request send];
to call this delegate function:
- (void)requestDidUploadData:(TTURLRequest *)request
{
float progress = request.totalBytesLoaded / (float)request.totalBytesExpected;
HUD.progress = progress;
HUD.labelText = [NSString stringWithFormat:#"Progress %d%%", (int)(progress*100)];
}
if you call sendSynchronously data will send but you can't get totalBytesLoaded.

Related

Multipeer Connectivity - State Not Changing

I'm working on an app the uses the Multipeer Conectivity Framework. So far everything is going great, I've implemented programmatic browsing and invitations.
My issue is when the user accepts the invitation the Browser is not receiving the state change - thereby not creating the session.
This is the advertiser did receive invitation method i have created using an action sheet integrated with blocks.
- (void)advertiser:(MCNearbyServiceAdvertiser *)advertiser
didReceiveInvitationFromPeer:(MCPeerID *)peerID
withContext:(NSData *)context
invitationHandler:(void(^)(BOOL accept, MCSession *session))invitationHandler
{
[UIActionSheet showInView:self.view
withTitle:[[NSString alloc]initWithFormat:#"%# would like to share %# information with you.",peerID.displayName, (NSString *)context]
cancelButtonTitle:#"Cancel"
destructiveButtonTitle:#"Deny"
otherButtonTitles:#[#"Accept"]
tapBlock:^(UIActionSheet *actionSheet, NSInteger buttonIndex) {
NSLog(#"%i",buttonIndex==1?true:false);
MCSession *newSession=[[MCSession alloc]initWithPeer:[[MCPeerID alloc] initWithDisplayName:#"CRAP23456"]];
[newSession setDelegate: self];
NSLog(#"button index %i ",buttonIndex==1?true:false);
invitationHandler(buttonIndex==1?YES:NO,newSession);
}];
}
The above method is being called and the invitation handler is returning the correct value.
My implementation from the browser side is very simple - and this is the method that should be called when the user either accepts/declines the method. However, it's only being called when the user declines the invite:
- (void)session:(MCSession *)session peer:(MCPeerID *)peerID didChangeState:(MCSessionState)state
{
NSLog(#"%d",state);
NSLog(#"%ld",(long)MCSessionStateConnected);
}
Thanks in advance.
James.
I hope one of these will help:
Implement session:didReceiveCertificate:fromPeer:certificateHandler:
I read here that this is necessary.
Keep browsing and advertising between two peers a one-way deal; that is, don't accept invitations on both ends if both are browsing as well (at least don't accept an invitation and pass same session you're browsing with in invitationHandler()).
Wrap your code in the didChangeState in a block like this:
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(#"%d",state);
NSLog(#"%ld",(long)MCSessionStateConnected);
});
I ran into this issue too. My code on the browser side looked like this:
MCSession *session = [[MCSession alloc] initWithPeer:[self peerID]];
session.delegate = self;
[browser invitePeer:peerID toSession:session withContext:nil timeout:30.0f];
The issue with this is that the browser does not retain a reference to the session and so ARC comes around and cleans it up before the other end had the opportunity to accept.
Changing it to the following fixed the issue:
_session = [[MCSession alloc] initWithPeer:[self peerID]];
_session.delegate = self;
[browser invitePeer:peerID toSession:_session withContext:nil timeout:30.0f];
.. where _session is an ivar on my class.
HTH

how can I show Progress Bar in my iPhone view while data is downloading from the server [duplicate]

I want to show up an progress bar while a download with NSURLConnection is happening. As I am getting data from the server, I could update the UI for every received package. But the problem is: How do I figure out how much data I have already, and how much data has to be downloaded? Probably in bytes... And then I have to do some math to get the percentage?
In your NSURLConnection delegate, implement something like this to find out the total content length. The server has to support this, but it will most likely work fine with static content:
- (void)connection: (NSURLConnection*) connection didReceiveResponse: (NSHTTPURLResponse*) response
{
statusCode_ = [response statusCode];
if (statusCode_ == 200) {
download_.size = [response expectedContentLength];
}
}
And then update progress like this:
- (void) connection: (NSURLConnection*) connection didReceiveData: (NSData*) data
{
[data_ appendData: data];
download_.progress = ((float) [data_ length] / (float) download_.size);
// Broadcast a notification with the progress change, or call a delegate
}
In my case I have a download instance that has size and progress properties. They are owned by a global DownloadManager object that will take care of notifying interested parties of the download progress or state changes.

how to use the progress bar in the iphone app

In my iPhone app I am downloading some data from an FTP server. To show the action I am using UIActivityIndicator. If I put UIProgressView there instead of UIActivityIndicator, it will be more appropriate. How do I use UIProgressView while downloading some data? Can anybody give me a tutorial link or example code? Thanks in advance.
first you create IBOutlet in .h file
IBOutlet UIProgressView * threadProgressView;
Then in .m file in viewdidload first set progress to 0.0 and then call makeMyProgressMoving method
threadProgressView.progress = 0.0;
[self performSelectorOnMainThread:#selector(makeMyProgressBarMoving) withObject:nil waitUntilDone:NO];
then add below method
- (void)makeMyProgressBarMoving {
float actual = [threadProgressView progress];
if (actual < 1) {
threadProgressView.progress = actual + ((float)recievedData/(float)xpectedTotalSize);
[NSTimer scheduledTimerWithTimeInterval:0.05 target:self selector:#selector(makeMyProgressBarMoving) userInfo:nil repeats:NO];
}
else{
}
}
also give your review for answer. is it useful to you?
It is quite simple. You just need to set appropriate value of property progress of UIProgressView.
In delegate of NSURLConnection you should receive the amount of data you are waiting to download and update the progress during downloading. Progress is represented by a floating-point value between 0.0 and 1.0, inclusive, where 1.0 indicates the completion of the task.
You can display progress of progress bar with these line of code
-(void) connection:(NSURLConnection *) connection
didReceiveData:(NSData *) data {
if (file)
{
[file seekToEndOfFile];
progressView.progress = ((float)recievedData / (float) xpectedTotalSize);
}
[file writeData:data];
recievedData += data.length;
NSLog(#"Receiving Bytes: %d", recievedData);
}
One of the option is AFNetworking.
AFURLConnectionOperation also allows you to easily stream uploads and downloads, handle authentication challenges, monitor upload and download progress, and control the caching behavior or requests.
noted: self.progressionBalance.progress = 5.0/10.0;
you must set decimal.

How to track the progress of a download using ASIHTTPRequest (ASYNC)

I am currently using an asynchronous call to my API (I setup) on my site. I am using ASIHTTPRequest's setDownloadProgressDelegate with a UIProgressView. However I don't know how I can call a selector (updateProgress) which will set a CGFloat 'progress' to the progressView's progress. I tried the following, but both the progresses were zero. Please can you tell me how I can get this working?
(in some method)
ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:[NSURL URLWithString:[url stringByAppendingFormat:#"confidential"]]];
[request setDownloadProgressDelegate:progressView];
[NSTimer scheduledTimerWithTimeInterval:1.0f/60.0f target:self selector:#selector(updateProgress:) userInfo:nil repeats:YES];
[request setCompletionBlock:^{~100 lines of code}];
[request setFailedBlock:^{~2 lines of code :) }];
[request startAsynchronous];
- (void) updateProgress:(NSTimer *)timer {
if (progressView.progress < 1.0) {
currentProgress = progressView.progress;
NSLog(#"currProg: %f --- progressViewProg: %f", currentProgress, progressView.progress);
}
else {
[timer invalidate];
}
return;
}
For people still finding this answer: Please note ASI is highly deprecated, you should use NSURLSession or ASIHTTPRequest instead.
One way to achieve what you want would be to set the downloadProgressDelegate to be your own class and implement setProgress:. In this implementation, update your progress variable and then call [progressView setProgress:];
Or in code, set up the request's download progress delegate:
[request setDownloadProgressDelegate:self];
and then add the method to your class:
- (void)setProgress:(float)progress
{
currentProgress = progress;
[progressView setProgress:progress];
}
Try to add in to your request:
[request setShowAccurateProgress:YES];
It won't help you to call updateProgress, ASIHTTPRequest will change progress indicator itself.
BTW: NS*Connection appears to be quite a bit faster than ASI* when downloading stuff.
In any case, the example on this page implies that you don't need to manually "copy" the value from the the download object to the progress view object.
In fact, your timer based code is getting the progress from the progress view which should be showing the progress already. There should be no need for a timer in this code at all, if I understand ASIHTTP* correctly.

How to pause/stop function until SOAP request is complete

EDIT: The problem i am having is that i am using the TapKu calendar, so i am relying on the provided delegates. Here is the problm:
- (NSArray*) calendarMonthView:(TKCalendarMonthView*)monthView marksFromDate:(NSDate*)startDate toDate:(NSDate*)lastDate{
//SOAP Request has NSURLConnection which runs asychonrous delegate methods.
//SOAP Request will return before the data array has been populated
[self SOAPRequest:startDate];
//i need to do something like this, however the SOAPRequest will return and get stuck into the loop instead of the asychronos delegates firing
//therefore i can never set bGettingData to NO.
int iWait;
while (bGettingData) {
iWait++;
}
return dataArray;
}
Hello,
In the app i am creating, i rely on SOAP requests to retrieve data, parse the XML and populate an array.
The problem i have, is that when i check the array it is empty, because the SOAP request has not completed. How do i stop my code from executing until the SOAP request is complete and resume the code? Can this be done through a callback or threading?
Thanks
Don't temporarily stop, sleep or wait, instead simply exit/quit/return from the current routine/function/method.
Break your current "stuff" into multiple fragments of code, each fragment in its own method.
Use subsequent method(s) to do whatever comes next, and have that method called by the completion routine of your async network/SOAP request.
Basically, your problem is that you are still thinking in terms of procedural coding. The proper paradigm is to use event driven coding: have the OS call your code, rather than having your code call the OS and waiting.
Yes,
start here: http://ondotnet.com/pub/a/dotnet/2005/08/01/async_webservices.html
You want indeed to wait for the answer to be complete - a callback is usually easiest. Exactly how depends on the programming library/language you are using (is above in javascript, objectiveC, did you hand code or start with an example).
Check out the answers to Iphone SOAP request step by step tutorial - such as http://macresearch.org/interacting-soap-based-web-services-cocoa-part-1 and http://brismith66.blogspot.com/2010/05/iphone-development-accesing-soap.html. Or follow https://developer.omniture.com/node/321 - which simply waits until the answer has fully arrived.
Unfortunately when using the TapKu calendar, you can not asynchronously load from a database via SOAP. You must synchronously load the calendar, because their is not way to refresh the calendar view once the data has finished loading. If you have 40+ records per month, this will create a huge 5-6 second delay.
This is indeed possible, as an example for the day calendar view, modify _refreshDataPageWithAtIndex to be like this:
- (void) _refreshDataWithPageAtIndex:(NSInteger)index{
UIScrollView *sv = self.pages[index];
TKTimelineView *timeline = [self _timelineAtIndex:index];
CGRect r = CGRectInset(self.horizontalScrollView.bounds, HORIZONTAL_PAD, 0);
r.origin.x = self.horizontalScrollView.frame.size.width * index + HORIZONTAL_PAD;
sv.frame = r;
timeline.startY = VERTICAL_INSET;
for (UIView* view in sv.subviews) {
if ([view isKindOfClass:[TKCalendarDayEventView class]]){
[self.eventGraveYard addObject:view];
[view removeFromSuperview];
}
}
if(self.nowLineView.superview == sv) [self.nowLineView removeFromSuperview];
if([timeline.date isTodayWithTimeZone:self.timeZone]){
NSDate *date = [NSDate date];
NSDateComponents *comp = [date dateComponentsWithTimeZone:self.timeZone];
NSInteger hourStart = comp.hour;
CGFloat hourStartPosition = hourStart * VERTICAL_DIFF + VERTICAL_INSET;
NSInteger minuteStart = round(comp.minute / 5.0) * 5;
CGFloat minuteStartPosition = roundf((CGFloat)minuteStart / 60.0f * VERTICAL_DIFF);
CGRect eventFrame = CGRectMake(self.nowLineView.frame.origin.x, hourStartPosition + minuteStartPosition - 5, NOB_SIZE + self.frame.size.width - LEFT_INSET, NOB_SIZE);
self.nowLineView.frame = eventFrame;
[sv addSubview:self.nowLineView];
}
if(!self.dataSource) return;
timeline.events = [NSMutableArray new];
[self.dataSource calendarDayTimelineView:self eventsForDate:timeline.date andEvents:timeline.events success:^{
[timeline.events sortUsingComparator:^NSComparisonResult(TKCalendarDayEventView *obj1, TKCalendarDayEventView *obj2){
return [obj1.startDate compare:obj2.startDate];
}];
[self _realignEventsAtIndex:index];
if(self.nowLineView.superview == sv)
[sv bringSubviewToFront:self.nowLineView];
}];
}
and then change your eventsForDate function to look like this:
- (void) calendarDayTimelineView:(TKCalendarDayView*)calendarDayTimeline eventsForDate:(NSDate *)eventDate andEvents:(NSMutableArray *)events success:(void (^)())success {
[Model doSomethingAsync andSuccess:^(NSArray *classes) {
// .. Add stuff to events..
success();
}];
}
I'm assuming the pattern for the other controls is very similar. The premise is you're waiting to continue the formatting/layout flow til you get your data.