Shiim
Shiim

Reputation: 439

NSURLConnection delegate methods not executing

I'm trying to pull images from the server for the scrollview. After the user zooms the view in or out, the image should be downloaded:

- (void)scrollViewDidEndZooming:(UIScrollView *)scrollView withView:(UIView *)view atScale:(float)scale {

Ymin=365000+375000*_scrollView.contentOffset.x/(scale*1024);
Ymax=365000+375000*(_scrollView.contentOffset.x/scale+1024/scale)/1024;
Xmin=6635000-260000*(_scrollView.contentOffset.y/scale+748/scale)/748;
Xmax=6635000-260000*_scrollView.contentOffset.y/(scale*748);

[self looYhendus];  //Creates NSURLConnection and downloads the image according to scale, Ymin, Ymax, Xmin and Xmax values

UIImage *saadudPilt=_kaardiPilt;
imageView=[[UIImageView alloc] initWithImage:saadudPilt];
imageView.frame=CGRectMake(_scrollView.contentOffset.x,_scrollView.contentOffset.y,1024,748);
[_scrollView addSubview:imageView];

}

On some occasions (I can't figure out, on what conditions), it works, but on some occasions NSURLConnection delegate methods won't get fired and the image set as the subview is still the image that is initially downloaded (when the application launches). Then, only after I touch the screen again (the scrollview scrolls), the NSLog message shows that the image is downloaded. What could be the reason of this kind of a behaviour?

EDIT: Added the NSURLConnection delegate methods. I've tried a few other ways but they all end up not executing the delegate methods. Which made me think that it's not about NSURConnection but rather UIScrollView (obviously, I can be wrong about this).

- (void)looYhendus
{   
yhendused=CFDictionaryCreateMutable(
                                    kCFAllocatorDefault, 
                                    0,
                                    &kCFTypeDictionaryKeyCallBacks,
                                    &kCFTypeDictionaryValueCallBacks);

NSString *aadress = [NSString stringWithFormat:@"http://xgis.maaamet.ee/wms-pub/alus?version=1.1.1&service=WMS&request=GetMap&layers=MA-ALUSKAART&styles=default&srs=EPSG:3301&BBOX=%d,%d,%d,%d&width=%d&height=%d&format=image/png",Ymin,Xmin,Ymax,Xmax,512,374];
NSURL *url = [[NSURL alloc] initWithString:aadress];
NSMutableURLRequest *theRequest = [NSMutableURLRequest requestWithURL:url];
NSURLConnection *theConnection = [[NSURLConnection alloc] initWithRequest:theRequest delegate:self];

if( theConnection )
{
    andmedServerist = [NSMutableData data];
    CFDictionaryAddValue(
                         yhendused,
                         (__bridge void *)theConnection,
                         (__bridge_retained CFMutableDictionaryRef)[NSMutableDictionary
                                                                    dictionaryWithObject:[NSMutableData data]
                                                                    forKey:@"receivedData"]);
}
CFRunLoopRun();
}

-(void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
[andmedServerist setLength: 0];
}

-(void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
NSMutableDictionary *connectionInfo =
(NSMutableDictionary*)objc_unretainedObject(CFDictionaryGetValue(yhendused, (__bridge void *)connection));
[[connectionInfo objectForKey:@"receivedData"] appendData:data];

}

-(void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Ühenduse viga" message:@"Kõige tõenäolisemalt on kaardiserveril probleeme või puudub seadmel internetiühendus" delegate:self cancelButtonTitle:@"Sulge" otherButtonTitles:nil];
[alert show];
CFRunLoopStop(CFRunLoopGetCurrent());
}


-(void)connectionDidFinishLoading:(NSURLConnection *)connection
{
NSMutableDictionary *connectionInfo =
(NSMutableDictionary*)objc_unretainedObject(CFDictionaryGetValue(yhendused, (__bridge void *)connection));
[connectionInfo objectForKey:@"receivedData"];
andmedServerist=[connectionInfo objectForKey:@"receivedData"];

_kaardiPilt = [UIImage imageWithData: andmedServerist];
CFDictionaryRemoveValue(yhendused, (__bridge void *)connection);

CFRunLoopStop(CFRunLoopGetCurrent());

}

EDIT: added this:

- (void)viewDidLoad
{
[super viewDidLoad];
Ymin=365000;
Ymax=740000;
Xmin=6375000;
Xmax=6635000;
[self looYhendus];
UIImage *saadudPilt=_kaardiPilt;
imageView=[[UIImageView alloc] initWithImage:saadudPilt];
imageView.frame=CGRectMake(0,0,1024,748);
[_scrollView addSubview:imageView];
[_scrollView setContentSize: CGSizeMake(1024, 748)];
_scrollView.minimumZoomScale = 1.0;
_scrollView.maximumZoomScale = 50.0;
_scrollView.delegate = self;
}

Upvotes: 0

Views: 602

Answers (2)

AdamG
AdamG

Reputation: 3718

I had the same problem recently. The issue was that I was putting my connection in an asynchronous thread, when connections are already asynchronous.

I found the solution here: NSURLConnection delegate methods are not called

There are also a few links to other people who had similar issues in that thread.

If I were you though, I would try simply using [theConnection start] and initializing the request with a set timeout so you don't have to worry about the background thread shutting out before the image is downloaded.

For example:

[request setTimeoutInterval:30];

Upvotes: 1

0x8badf00d
0x8badf00d

Reputation: 6401

Why are you explicitly calling CFRunLoopRun(); and stopping it in connectionDidFinishLoading: or didFailWithError: methods ? (CFRunLoopStop(CFRunLoopGetCurrent());)

Assuming you are doing this on main thread. You are stopping mainthread's runloop. There can be timers, ScrollView uses events which stop responding because you stopped the main thread's runloop.

If you are calling NSURLConnection on the main thread you don't need to explicitly run it (or stop it). You can just schedule to run on current runloop which is main threads runloop. If you are doing it on a background thread, then your code seems valid (Although you shouldn't show UIAlertView in didFailWithError: if its called on separate thread).

Updated Answer(Based on @Shiim's comment):

In the viewDidLoad method you are calling [self looYhendus]; which returns immediately (as you are using Asynchronous URL Connection for the load). So its working as expected. Move [scrollView addSubview:imageView] to connectionDidFinishLoading: method which would add your downloaded imageView data to scrollView's subView once finished downloading it. Or you can consider using dispatch_queue's to create a thread and load the URL request synchronously then using dispatch_queue's main queue to dispatch drawing of imageView added as subView to ScrollView onto main thread.

My recommendation in your case would be redesigned approach using dispatch_queue's. Which would be give you better understanding of solving problem (in this scenario) and also improves your code readability.

Upvotes: 1

Related Questions