Skip to content

Instantly share code, notes, and snippets.

@bstahlhood
Created September 13, 2012 00:51
Show Gist options
  • Save bstahlhood/3711077 to your computer and use it in GitHub Desktop.
Save bstahlhood/3711077 to your computer and use it in GitHub Desktop.
Swizzled UIImage imageNamed for iPhone 5
//
// UIImage+Retina4.h
// StunOMatic
//
// Created by Benjamin Stahlhood on 9/12/12.
// Copyright (c) 2012 DS Media Labs. All rights reserved.
//
#import <UIKit/UIKit.h>
@interface UIImage (Retina4)
@end
//
// UIImage+Retina4.m
// StunOMatic
//
// Created by Benjamin Stahlhood on 9/12/12.
// Copyright (c) 2012 DS Media Labs. All rights reserved.
//
#import "UIImage+Retina4.h"
#import <objc/objc-runtime.h>
static Method origImageNamedMethod = nil;
@implementation UIImage (Retina4)
+ (void)initialize {
origImageNamedMethod = class_getClassMethod(self, @selector(imageNamed:));
method_exchangeImplementations(origImageNamedMethod,
class_getClassMethod(self, @selector(retina4ImageNamed:)));
}
+ (UIImage *)retina4ImageNamed:(NSString *)imageName {
NSLog(@"Loading image named => %@", imageName);
NSMutableString *imageNameMutable = [imageName mutableCopy];
NSRange retinaAtSymbol = [imageName rangeOfString:@"@"];
if (retinaAtSymbol.location != NSNotFound) {
[imageNameMutable insertString:@"-568h" atIndex:retinaAtSymbol.location];
} else {
CGFloat screenHeight = [UIScreen mainScreen].bounds.size.height;
if ([UIScreen mainScreen].scale == 2.f && screenHeight == 568.0f) {
NSRange dot = [imageName rangeOfString:@"."];
if (dot.location != NSNotFound) {
[imageNameMutable insertString:@"-568h@2x" atIndex:dot.location];
} else {
[imageNameMutable appendString:@"-568h@2x"];
}
}
}
NSString *imagePath = [[NSBundle mainBundle] pathForResource:imageNameMutable ofType:@"png"];
if (imagePath) {
return [UIImage retina4ImageNamed:imageNameMutable];
} else {
return [UIImage retina4ImageNamed:imageName];
}
return nil;
}
@end
//
// UIImage+Retina4.h
// StunOMatic
//
// Created by Benjamin Stahlhood on 9/12/12.
// Copyright (c) 2012 DS Media Labs. All rights reserved.
//
#import <UIKit/UIKit.h>
@interface UIImage (Retina4)
@end
//
// UIImage+Retina4.m
// StunOMatic
//
// Created by Benjamin Stahlhood on 9/12/12.
// Copyright (c) 2012 DS Media Labs. All rights reserved.
//
#import "UIImage+Retina4.h"
#import <objc/runtime.h>
#import <objc/message.h>
static Method origImageNamedMethod = nil;
@implementation UIImage (Retina4)
+ (void)initialize {
origImageNamedMethod = class_getClassMethod(self, @selector(imageNamed:));
method_exchangeImplementations(origImageNamedMethod,
class_getClassMethod(self, @selector(retina4ImageNamed:)));
}
+ (UIImage *)retina4ImageNamed:(NSString *)imageName {
NSLog(@"Loading image named => %@", imageName);
NSMutableString *imageNameMutable = [imageName mutableCopy];
NSRange retinaAtSymbol = [imageName rangeOfString:@"@"];
if (retinaAtSymbol.location != NSNotFound) {
[imageNameMutable insertString:@"-568h" atIndex:retinaAtSymbol.location];
} else {
CGFloat screenHeight = [UIScreen mainScreen].bounds.size.height;
if ([UIScreen mainScreen].scale == 2.f && screenHeight == 568.0f) {
NSRange dot = [imageName rangeOfString:@"."];
if (dot.location != NSNotFound) {
[imageNameMutable insertString:@"-568h@2x" atIndex:dot.location];
} else {
[imageNameMutable appendString:@"-568h@2x"];
}
}
}
NSString *imagePath = [[NSBundle mainBundle] pathForResource:imageNameMutable ofType:@"png"];
if (imagePath) {
return [UIImage retina4ImageNamed:imageNameMutable];
} else {
return [UIImage retina4ImageNamed:imageName];
}
return nil;
}
@end
@0xced
Copy link

0xced commented Sep 14, 2012

By overriding the +initialize method in the Retina4 category, you just nuked the cache flushing mechanism since it’s setup in +[UIImage initialize].

@0xced
Copy link

0xced commented Sep 14, 2012

You should put the swizzle code in the +load method instead of the +initialize method. Also, this gist has UIImage+Retina4.h and UIImage+Retina4.m two times.

@steipete
Copy link

attribute((constructor)) is your friend :)

@0xced
Copy link

0xced commented Sep 14, 2012

I prefer +load over __attribute__((constructor)) but that’s really a matter of taste.

@artemstepanenko
Copy link

And what about this image name: @"MyBundle.bundle/picture.png"? In this case your code will try to insert @"-568h@2x" before the wrong dot.

@artemstepanenko
Copy link

This category won't work for image names which include extension.
You have to delete extension from imageNameMutable before 40'th line.

@rufferto
Copy link

How about not even swizzling this unless you know you are running on a retina4 device?

@artemstepanenko
Copy link

I think it's a good idea

@angelolloqui
Copy link

I rewrote the code to fix some of the commented issues. Check it out at: http://angelolloqui.com/blog/20-iPhone5-image-loading

@plenilune
Copy link

Apple rejects apps that use method swizzling http://stackoverflow.com/questions/7720947/method-swizzling-in-ios-5

@furkanmustafa
Copy link

Apple doesn't reject apps that use method swizzling. The rejected app in the provided link swizzles 'dealloc' method, and that's clearly mentioned in Apple's email there.

For this case it should be completely OK. I already have several apps in the store using method swizzling.

@pombredanne
Copy link

@bstahlhood thanks for this... what would be the license for these snippets?

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