URL
Image
|
Modified: |

Downloads
UIImageDelegate example
Overview
Images can be downloaded by URL and displayed in the UI.
- Can download on the UI thread, easy but bad idea.
- Can download using delegates with most work executed off the UI thread, much better idea.
On the UI thread
Easy but can cause the UI to be unresponsive.
myImage should be connected to a UIImageView object.
#import <UIKit/UIKit.h>
@interface HW3ViewController : UIViewController {
IBOutlet UIImageView * myImage;
}
@end
|
#import "URLImageUIThread.h"
@implementation URLImageUIThread
- (void)viewDidLoad{
[super viewDidLoad];
NSString * myURL = @"http://java.sogeti.nl/JavaBlog/wp-content/uploads/2009/04/android_icon_256.png";
UIImage *image = [UIImage imageWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:myURL]]];
myImage.image = image;
}
@end
|
Blocking calls on Main Loop
Most method calls block execution until the call is complete.
The operation to download the image executes a blocking method call:
UIImage *image = [UIImage imageWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:myURL]]];
is followed by the statement that uses the image.
myImage.image = image
which cannot execute until the blocking call executes. So there is sequential execution within the same thread, in this case, the main loop.
Problems in the Event Loop
The previous example works but hogs the event loop for the duration of the download.
The diagram at right illustrates processing events in event loop. The main idea is that each event results in calling iOS and a call-back from iOS.
- UI event occurs (user touches a button).
- Executes an iOS function.
- Places event in queue.
- Event passed to main run loop.
- Application object (button) code executes, perhaps to handle Touch up Inside.
- Calls core object (where button is implemented).
- Core object calls iOS function.
- iOS function updates UI.
The key points are:
- A long execution can hog the main loop.
- After the call-back, other events have a chance to execute.
Delegates
Delegate methods can often be used to break up one long-running execution into several, shorter ones.
NSURLConnection executes most of the background work on a separate thread.
NSURLConnection executes call-backs to delegate methods when work for the delegate:
- (void)connection:(NSURLConnection *)theConnection didReceiveData:(NSData *)incrementalData when data is received.
- (void)connectionDidFinishLoading:(NSURLConnection*)theConnection when all data received and the connection closes.
These methods execute on the delegate's own thread.
Using delegates
The following app is a delegate of NSURLConnection.
#import <UIKit/UIKit.h>
@interface UIImageLoadViewController : UIViewController{
IBOutlet UIImageView * myImage;
NSURLConnection* connection;
NSMutableData* data;
}
@end
|
#import "UIImageLoadViewController.h"
@implementation UIImageLoadViewController
- (void)viewDidLoad {
[super viewDidLoad];
NSString * myURL =
@"http://java.sogeti.nl/JavaBlog/wp-content/uploads/2009/04/android_icon_256.png";
NSURLRequest* request = [NSURLRequest requestWithURL:[NSURL URLWithString: myURL ]
cachePolicy:NSURLRequestUseProtocolCachePolicy
timeoutInterval:60.0];
connection = [[NSURLConnection alloc] initWithRequest:request delegate: self];
}
- (void)connection:(NSURLConnection *)theConnection
didReceiveData:(NSData *)incrementalData {
if (data==nil) data = [[NSMutableData alloc] initWithCapacity:2048];
[data appendData:incrementalData];
}
- (void)connectionDidFinishLoading:(NSURLConnection*)theConnection {
[connection release];
connection=nil;
myImage.image = [UIImage imageWithData:data];
[data release];
data=nil;
}
@end
|
Writing delegate class - AsyncImage implementation
To understand how delegates work, the following re-implements the image download by creating our own delegate class.
AsyncImage class downloads an image through the NSURLConnection call-backs above.
AsyncImage is a delegate of NSURLConnection.
connection = [[NSURLConnection alloc] initWithRequest:request delegate: self ]; AsyncImage is initialized with a delegate and runs on the delegate's thread, in this case the UI thread.
asyncImage = [[AsyncImage alloc] initWithURL:[NSURL URLWithString: myURL ] delegate: self ]; When the image data is downloaded completely, AsyncImage makes a call-back to pass a UIImage of the data to its delegate.
[delegate imageDownLoaded: [UIImage imageWithData:data]]; The delegate can then update the UI with the image.
-(void) imageDownLoaded: (UIImage *) image {
myImage.image = image;
[asyncImage release];
}Is this a good idea, given that NSURLConnection generates call-back events to the NSURLConnection methods implemented in delegate AsyncImage?
The answer has to do with whose thread is executing the delegate methods and how much time is spent in executing those methods.
Delegate methods are expected to execute in the delegate's thread, so we would expect NSURLConnection methods to execute in whatever thread was executing AsyncImage.
When the time spent in each execution of a delegate method is small and the number of executions is few, the main or UI thread could handle the executions without unreasonable delays.
When the time spent in each execution of a delegate method is large or the number of executions is many, the main or UI thread may not handle the executions without unreasonable delays. A separate thread should be execute the delegate methods.
NSURLConnection runs on its own thread, handling the relatively slow Internet download.
When NSURLConnection executes a call-back to AsyncImage, execution takes place on the UI thread that initialized AsyncImage.
Each call-back is completed fairly quickly in AsyncImage and the UI thread continues.
Though slightly more effort, delegate makes the app more responsive uses delegates.
- myImage should be connected to a UIImageView object.
- [[AsyncImage alloc] initWithURL:[NSURL URLWithString: myURL ] delegate: self]; starts loading an image from myURL and initializes the calling class object as the delegate.
- -(void) imageDownLoaded: (UIImage *) image; must be implemented by the delegate class loading the image.
#import <UIKit/UIKit.h>
@interface URLImageDelegate : UIViewController {
IBOutlet UIImageView * myImage;
}
-(void) imageDownLoaded: (UIImage *) image;
@end
|
#import "URLImageDelegate.h"
@interface AsyncImage : NSObject {
NSURLConnection* connection;
NSMutableData* data;
id delegate;
}
-(void)loadImageFromURL:(NSURL*)url;
-(AsyncImage *) initWithURL: (NSURL *) url delegate: (id) d;
@end
@implementation AsyncImage
-(AsyncImage *) initWithURL: (NSURL *) url delegate: (id) d {
delegate = d;
[self loadImageFromURL: url];
return self;
}
- (void) loadImageFromURL:(NSURL*)url {
if (connection!=nil) [connection release];
if (data!=nil) [data release];
NSURLRequest* request = [NSURLRequest requestWithURL:url
cachePolicy:NSURLRequestUseProtocolCachePolicy
timeoutInterval:60.0];
}
- (void)connection:(NSURLConnection *)theConnection didReceiveData:(NSData *)incrementalData {
if (data==nil)
data = [[NSMutableData alloc] initWithCapacity:2048];
[data appendData:incrementalData];
}
- (void)connectionDidFinishLoading:(NSURLConnection*)theConnection {
[connection release];
connection=nil;
[data release];
data=nil;
}
- (void)dealloc {
[connection cancel];
[connection release];
[data release];
[super dealloc];
}
@end
|
||
|
@implementation URLImageDelegate AsyncImage * asyncImage; - (void)viewDidLoad{ [super viewDidLoad]; NSString * myURL = @"http://java.sogeti.nl/JavaBlog/wp-content/uploads/2009/04/android_icon_256.png";
}
@end |
Is Main Loop Executing?
The operation to download the image:
asyncImage = [[AsyncImage alloc] initWithURL:[NSURL URLWithString: myURL ] delegate: self]; is not followed by the statement that uses the image.
myImage.image = image; // Display image Execution must flow through delegate methods so there is not sequential execution within the same thread, in this case, the main loop.
While downloading the image, the main loop is executed through two call-backs:
- (void)connection:(NSURLConnection *)theConnection didReceiveData:(NSData *)incrementalData;
- (void)connectionDidFinishLoading:(NSURLConnection*)theConnection;