i have a connection use NSURLConnection, i want to draw a progress for this connection but when i try to print current received data and total data length, something went wrong ,response.expectedContentLength allway return -1, why and what happen with my connection, how can i fix it
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
receivedDataBytes += [data length];
NSLog(#"data: %f",receivedDataBytes);
[responseData appendData:data];
}
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
self.HTTPStatusCode = [(NSHTTPURLResponse *)response statusCode];
totalFileSize = response.expectedContentLength;
NSLog(#"total: %lf",totalFileSize);
}
output:
total: -1.000000
data: 1256.000000
total: -1.000000
data: 1034.000000
total: -1.000000
data: 1127.000000
Related
Background:
Please don't mark this as duplicate. I have tried every other related post and they didn't work for me. I have looked at countless examples (StackOverflow/MBProgressHUD Demo/etc.) trying to get this to work. I feel like most examples are outdated as some methods are deprecated. This is the closest I have got.
What I want the code to do:
The MBProgress HUD should display the default loading screen with "Preparing" before I start connecting to JSON. When I connect, I want the mode to change to AnnularDeterminate when I receive a response. Once it's finished loading, I want the progress bar to display my progress of adding the data to a dictionary. Once that is done, change the mode to CustomView displaying a checkmark image and "Completed".
The Issue:
The MBProgress HUD will display. However, it only shows the default loading screen with "Preparing..." underneath it and then it will say "Completed" with the checkmark custom view after progress is at 1.0. There is no Determinate view with my updated progress in between.
My Code
- (void)viewDidLoad
{
buildingsDataArray = [[NSMutableArray alloc] init];
MBProgressHUD *HUD = [MBProgressHUD showHUDAddedTo:self.view animated:YES];
HUD.delegate = self;
HUD.label.text = NSLocalizedString(#"Preparing...", #"HUD preparing title");
[self connect];
NSLog(#"End of setup");
}
- (void)connect
{
NSURLRequest *request =[NSURLRequest requestWithURL:[NSURL URLWithString:buildingList]];
connection = [NSURLConnection connectionWithRequest:request delegate:self];
[connection start];
NSLog(#"End of connect");
}
// Connection delegate
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
NSLog(#"connection received response");
[MBProgressHUD HUDForView:self.view].mode = MBProgressHUDModeAnnularDeterminate;
NSLog(#"Changed mode");
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
[webData appendData:data];
NSLog(#"connection received data");
[MBProgressHUD HUDForView:self.view].progress = 0.0f;
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
NSLog(#"Fail with error - %# %#", [error localizedDescription], [[error userInfo] objectForKey:NSURLErrorFailingURLStringErrorKey]);
if ([[error localizedDescription] isEqualToString:#"The Internet connection appears to be offline."]) {
//do something
}
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
NSArray *allDataArray = [NSJSONSerialization JSONObjectWithData:webData options:0 error:nil];
float count = [allDataArray count];
float c=1;
if ([buildingsDataArray count]!=0)
[buildingsDataArray removeAllObjects];
for (NSDictionary *dataDict in allDataArray){ //from 1 to 6
if ([[dataDict objectForKeyedSubscript:#"id"] intValue] != 0)
[buildingsDataArray addObject:dataDict];
usleep(200000);
float p = c/count;
[MBProgressHUD HUDForView:self.view].progress = p;
NSLog(#"Progress: %f", [MBProgressHUD HUDForView:self.view].progress);
});
c++;
}
[MBProgressHUD HUDForView:self.view].customView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"Checkmark.png"]];
[MBProgressHUD HUDForView:self.view].label.text = NSLocalizedString(#"Completed", #"HUD done title");
[MBProgressHUD HUDForView:self.view].mode = MBProgressHUDModeCustomView;
[[MBProgressHUD HUDForView:self.view] hideAnimated:YES afterDelay:1.0f];
}
And here is my console output
End of connect
End of setup
connection received response
Changed mode
connection received data
connection finished loading
Progress: 0.166667
Progress: 0.333333
Progress: 0.500000
Progress: 0.666667
Progress: 0.833333
Progress: 1.000000
Additional comments
When I try adding
dispatch_async(dispatch_get_main_queue()
outside all of the MBProgress method calls inside my connection delegate,
I get the default loading screen again. But after progress reaches 1.0, the determinate loading screen view shows (fully loaded) with "Completed" and then disappears after delay 1.0. There is still no loading process in between. Also, the checkmark image never shows. I don't think this is the way to do it.
The output when I do this is:
End of connect
End of doSetup
connection received response
connection received data
connection finished loading
Changed mode
Progress: 0.166667
Progress: 0.333333
Progress: 0.500000
Progress: 0.666667
Progress: 0.833333
Progress: 1.000000
Here is a useful reference that touches base on UICalls on different threads:
Is there a way to make drawRect work right NOW?
This is what worked:
NSURLConnection was being called on the main thread. So all of my UI updates weren't occurring until after the connection delegate calls were finished.
So to fix this problem, I put the connection in a background thread.
- (void)viewDidLoad{
//...
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0),^{
NSURL *URL = [NSURL URLWithString:buildingList];
NSMutableURLRequest *request =[NSMutableURLRequest requestWithURL:URL];
connection = [[NSURLConnection alloc] initWithRequest:request delegate:self startImmediately:NO];
[connection setDelegateQueue:[[NSOperationQueue alloc] init]];
[connection start];
});
}
Inside the connection delegate methods, I surrounded each MBProgress call with
dispatch_async(dispatch_get_main_queue(), ^{
//...
}
Hope this helps others. I spent all day on this and it was such a simple misunderstanding...
My progress indicator is not working in cocoa webview I used this code -
-(void)download:(NSURLDownload *)download didReceiveResponse:(NSURLResponse *)response {
NSLog(#"downl didreceiveresponse here");
NSLog(#"Recieved reponse with expected length: %lli", [response expectedContentLength]);
payload=0;
[payload setLength:0];
[progrssbar setMaxValue:[response expectedContentLength]] ;
[self setProgrssbar:progrssbar];
}
- (void)connection:(NSURLConnection *)conn didReceiveData:(NSData *)data
{
NSLog(#"Recieving data. Incoming Size: %li Total Size: %li", (unsigned long)[data length], (unsigned long)[payload length]);
[payload appendData:data];
[progrssbar setDoubleValue:[payload length]];
}
- (void)download:(NSURLDownload *)download didReceiveDataOfLength:(unsigned)length
{
NSLog(#"downl receivedata here%i",length);
[progrssbar setHidden:NO];
[progrssbar setIndeterminate:NO];
[progrssbar startAnimation:self];
[progrssbar setDoubleValue:(double)length]; [progrssbar displayIfNeeded];
}
What exactly is payload declared as? I used a similar code where I declared NSMutableData *payload and then in -(void)download:(NSURLDownload *)download didReceiveResponse:(NSURLResponse *)response I used payload=[NSMutableData data] instead of your payload=0, maybe that is the problem?
I'm using
[NSURLConnection connectionWithRequest:req delegate:self];
and then I use
-(BOOL)connection:(NSURLConnection *)connection canAuthenticateAgainstProtectionSpace:(NSURLProtectionSpace *)protectionSpace;
-(void)connection:(NSURLConnection *)connection didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge;
-(void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error;
-(void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response;
-(void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data;
-(void)connectionDidFinishLoading:(NSURLConnection *)connection;
to handle data loading. Everything is ok and working fine but I don't like the beauty of this code )
I wish to use blocks, to make my code looks like this:
[myConnection sendData:data
successBlock:^(void){NSLog(#"success");}
errorBlock:^(NSError * error){NSLog(#"error.description: %#", error.description);}];
is it possible to use NSURLConnection with blocks?
I use this class:
The MyConnection.h
#import <Foundation/Foundation.h>
#interface MyConnection : NSObject <NSURLConnectionDelegate, NSURLConnectionDataDelegate> {
NSURLConnection * internalConnection;
NSMutableData * container;
}
-(id)initWithRequest:(NSURLRequest *)req;
#property (nonatomic,copy)NSURLConnection * internalConnection;
#property (nonatomic,copy)NSURLRequest *request;
#property (nonatomic,copy)void (^completitionBlock) (id obj, NSError * err);
-(void)start;
#end
And the MyConnection.m
#import "MyConnection.h"
static NSMutableArray *sharedConnectionList = nil;
#implementation MyConnection
#synthesize request,completitionBlock,internalConnection;
-(id)initWithRequest:(NSURLRequest *)req {
self = [super init];
if (self) {
[self setRequest:req];
}
return self;
}
-(void)start {
container = [[NSMutableData alloc]init];
internalConnection = [[NSURLConnection alloc]initWithRequest:[self request] delegate:self startImmediately:YES];
if(!sharedConnectionList)
sharedConnectionList = [[NSMutableArray alloc] init];
[sharedConnectionList addObject:self];
}
#pragma mark NSURLConnectionDelegate methods
-(void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
[container appendData:data];
}
//If finish, return the data and the error nil
-(void)connectionDidFinishLoading:(NSURLConnection *)connection {
if([self completitionBlock])
[self completitionBlock](container,nil);
[sharedConnectionList removeObject:self];
}
//If fail, return nil and an error
-(void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
if([self completitionBlock])
[self completitionBlock](nil,error);
[sharedConnectionList removeObject:self];
}
#end
to use it:
MyConnection * connection = [[MyConnection alloc]initWithRequest:req];
[connection setCompletitionBlock:^(id obj, NSError *err) {
if (!err) {
//It's ok, do domething with the response data (obj)
} else {
//There was an error
}
}];
[connection start];
It's based on the code, The Big Nerd Ranch uses on his book.
I hope it will be helpful.
[NSURLConnection sendAsynchronousRequest:request
queue:[NSOperationQueue mainQueue]
completionHandler:^(NSURLResponse * _Nullable response, NSData * _Nullable data, NSError * _Nullable connectionError) {
NSLog(#"%#", response);
NSLog(#"%#", data);
}];
I have implemented the NSCoding protocol for my classes, and I am using the following code in my NSDocument subclass to save and load:
- (NSData *)dataOfType:(NSString *)typeName error:(NSError **)outError {
[[record window] endEditingFor:nil];
return [NSKeyedArchiver archivedDataWithRootObject:self];
}
- (BOOL)readFromData:(NSData *)data ofType:(NSString *)typeName error:(NSError **)outError{
#try {
NSLog(#"Loading...");
self = [NSKeyedUnarchiver unarchiveObjectWithData:data];
}
#catch (NSException *exception) {
if (outError) {
NSDictionary *d = [NSDictionary dictionaryWithObject:#"The data is corrupted" forKey:NSLocalizedFailureReasonErrorKey];
*outError = [NSError errorWithDomain:NSOSStatusErrorDomain code:unimpErr userInfo:d];
}
}
NSLog(#"whiteMoves count: %ld",[whiteMoves count]);
}
It all seems to be working fine. I can save a file and when I open it and step through the code it all seems to unarchive and decode fine. However, on completion of the 'load event' my application always pops up an error window that says "The document "xxx.xxx" could not be loaded." I cannot find where this error is being triggered from nor any documentation on it.
Does any one know where it comes from or know where it might be documented?
Thanks
Lee
You don't appear to be returning YES or NO from readFromData:
- (BOOL)readFromData:(NSData *)data
ofType:(NSString *)typeName
error:(NSError **)outError
{
BOOL retval = YES;
#try
{
NSLog(#"Loading...");
self = [NSKeyedUnarchiver unarchiveObjectWithData:data];
NSLog(#"whiteMoves count: %ld",[whiteMoves count]);
}
#catch (NSException *exception)
{
if (outError != nil)
{
NSDictionary *d = [NSDictionary dictionaryWithObject:#"The data is corrupted" forKey:NSLocalizedFailureReasonErrorKey];
*outError = [NSError errorWithDomain:NSOSStatusErrorDomain code:unimpErr userInfo:d];
}
retval = NO;
}
return retval;
}
This looks chess-related; can I ask what you are writing?
When trying to compile an infinite while loop in xcode iphone view based application, it gives me an error that reads expected identifier or '(' before 'while'. I made it as simple as possible. Sorry about the picture. Code block was not working. If you want to see an image of the code, here is the link. http://www.freeimagehosting.net/uploads/931d5d8788.gif
#import "Lockerz_NotifierViewController.h"
#implementation Lockerz_NotifierViewController
NSMutableData *responseData;
while (1) {
NSURLRequest *theRequest = [NSURLRequest requestWithURL:[NSURL URLWithString:#"http://amicionline.me"]
cachePolicy:NSURLRequestUseProtocolCachePolicy
timeoutInterval:60.0];
// create a connection
NSURLConnection *theConnection=[[NSURLConnection alloc] initWithRequest:theRequest delegate:self];
if(theConnection) {
// create the datum
responseData=[[NSMutableData data] retain];
} else {
// code this later
}
}
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
[responseData setLength:0];
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
// make it work
NSLog(#"Succeeded! Received %d bytes of data:",[responseData length]);
// release it
[connection release];
[responseData release];
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
[responseData appendData:data];
}
What are you trying to do? You can't write code directly in an #implementation. You must put it inside a method, for example:
-(void)start {
while (1) {
...
}
}