Skip to content

Instantly share code, notes, and snippets.

@leovandriel
Last active October 12, 2015 13:19
Show Gist options
  • Star 5 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save leovandriel/3923434 to your computer and use it in GitHub Desktop.
Save leovandriel/3923434 to your computer and use it in GitHub Desktop.
An iOS view controller for trying out different UIImage preloading strategies
// ImagePreloadingViewController - An iOS view controller for trying out different
// UIImage preloading strategies. Results for 1 MB png on iPhone 4S:
// - No preload: drawing the image right away (80 ms)
// - Header preload: getting the width (10 ms) and then drawing (100 ms)
// - Data preload: getting the data (110 ms) and then drawing (75 ms)
// - Draw preload: drawing it once (100 ms) and then again (20 ms)
// In short: preload a UIImage by drawing it.
// License: BSD
// Author: Leonard van Driel, 2012
@interface ImagePreloadingViewController : UIViewController
@end
@implementation ImagePreloadingViewController {
UITextView *output;
}
- (void)viewDidLoad
{
[super viewDidLoad];
for (NSUInteger i = 0; i < 4; i++) {
UIButton *button = [UIButton buttonWithType:UIButtonTypeRoundedRect];
button.frame = CGRectMake(10, 10 + 50 * i, self.view.bounds.size.width - 20, 40);
[button addTarget:self action:@selector(run:) forControlEvents:UIControlEventTouchUpInside];
switch (i) {
case 0: [button setTitle:@"No preload" forState:UIControlStateNormal]; break;
case 1: [button setTitle:@"Header preload" forState:UIControlStateNormal]; break;
case 2: [button setTitle:@"Data preload" forState:UIControlStateNormal]; break;
case 3: [button setTitle:@"Draw preload" forState:UIControlStateNormal]; break;
}
button.tag = i;
[self.view addSubview:button];
}
output = [[UITextView alloc] init];
output.frame = CGRectMake(10, 210, self.view.bounds.size.width - 20, self.view.bounds.size.height - 270);
[self.view addSubview:output];
}
#pragma mark - Timing
- (void)run:(UIButton *)button
{
NSUInteger index = button.tag;
[self preload:index];
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, .1 * NSEC_PER_SEC);
dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
[self load:index];
});
}
- (void)preload:(NSUInteger)index
{
NSString *name = [NSString stringWithFormat:@"%i.png", index];
double time = CFAbsoluteTimeGetCurrent();
switch (index) {
case 0: break;
case 1: [self header:[UIImage imageNamed:name]]; break;
case 2: [self data:[UIImage imageNamed:name]]; break;
case 3: [self draw:[UIImage imageNamed:name]]; break;
}
output.text = [output.text stringByAppendingFormat:@"%i: %4.0f ms preload", index, (CFAbsoluteTimeGetCurrent() - time) * 1000];
}
- (void)load:(NSUInteger)index
{
NSString *name = [NSString stringWithFormat:@"%i.png", index];
double time = CFAbsoluteTimeGetCurrent();
[self draw:[UIImage imageNamed:name]];
output.text = [output.text stringByAppendingFormat:@" .. %4.0f ms draw\n", (CFAbsoluteTimeGetCurrent() - time) * 1000];
}
#pragma mark - Preload types
- (void)header:(UIImage *)image
{
CGImageRef ref = image.CGImage;
CGImageGetWidth(ref);
}
- (void)data:(UIImage *)image
{
CGImageRef ref = image.CGImage;
CGDataProviderRef provider = CGImageGetDataProvider(ref);
CGDataProviderCopyData(provider);
}
- (void)draw:(UIImage *)image
{
CGImageRef ref = image.CGImage;
size_t width = CGImageGetWidth(ref);
size_t height = CGImageGetHeight(ref);
CGColorSpaceRef space = CGColorSpaceCreateDeviceRGB();
CGContextRef context = CGBitmapContextCreate(NULL, width, height, 8, width * 4, space, kCGBitmapAlphaInfoMask & kCGImageAlphaPremultipliedFirst);
CGColorSpaceRelease(space);
CGContextDrawImage(context, CGRectMake(0, 0, width, height), ref);
CGContextRelease(context);
}
@end
@versluis
Copy link

That's a great way of preloading images - it's solved one of those big mysteries for me. Thank you!

I go get a warning though in line 93: Implicit conversion from enumeration type 'enum CGImageAlphaInfo' to different enumeration type 'CGBitmapInfo' (aka 'enum CGBitmapInfo')

Sadly I don't know enough about what either enumeration does, hence it's leaving me clueless. It's only happening in Xcode 5.x, Xcode 4.6.3 seems to be happy and doesn't throw the warning.

@leovandriel
Copy link
Author

Thanks Jay pointing out the warning, it should be fixed now.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment