More than once I came across a situation where a UIView (subclass) ends at a fractional offset, for example. because its dimensions are odd and centered, or because its location is based on the center of the container with an odd size.
This results in blurry text (or images) because iOS will try to display the view (and subitems) at half pixel offsets. I feel that calling CGRectIntegral()for every frame change is not an ideal solution.
I am looking for the best way to easily detect these situations. When writing this question, I came up with a rather radical approach, which showed more than in my current project than I could imagine.
So this is for sharing. Comments and suggestions on better or less decisive alternatives are more than welcome.
main.m
#import <objc/runtime.h>
#import "UIViewOverride.h"
int main(int argc, char *argv[]) {
#ifdef DEBUGVIEW
Method m1,m2;
IMP imp;
m1 = class_getInstanceMethod([UIView class], @selector(setFrame:));
m2 = class_getInstanceMethod([UIViewOverride class], @selector(setFrameOverride:));
imp = method_getImplementation(m2);
class_addMethod([UIView class], @selector(setFrameOverride:), imp, method_getTypeEncoding(m1));
m2 = class_getInstanceMethod([UIView class], @selector(setFrameOverride:));
method_exchangeImplementations(m1,m2);
m1 = class_getInstanceMethod([UIView class], @selector(setCenter:));
m2 = class_getInstanceMethod([UIViewOverride class], @selector(setCenterOverride:));
imp = method_getImplementation(m2);
class_addMethod([UIView class], @selector(setCenterOverride:), imp, method_getTypeEncoding(m1));
m2 = class_getInstanceMethod([UIView class], @selector(setCenterOverride:));
method_exchangeImplementations(m1,m2);
#endif
UIViewOverride.m
This is implemented as a subclass of UIView, which avoids throws and / or compiler warnings.
#define FRACTIONAL(f) (fabs(f)-floor(fabs(f))>0.01)
@implementation UIViewOverride
#ifdef DEBUGVIEW
-(void)setFrameOverride:(CGRect)newframe
{
if ( FRACTIONAL(newframe.origin.x) || FRACTIONAL(newframe.origin.y) )
{
[self setBackgroundColor:[UIColor redColor]];
[self setAlpha:0.2];
NSLog(@"fractional offset for %@",self);
}
[self setFrameOverride:newframe];
}
-(void)setCenterOverride:(CGPoint)center
{
[self setCenterOverride:center];
if ( FRACTIONAL(self.frame.origin.x) || FRACTIONAL(self.frame.origin.y) )
{
[self setBackgroundColor:[UIColor greenColor]];
[self setAlpha:0.2];
NSLog(@"fractional via center for %@",self);
}
}
#endif
Problem representations generate log messages and become transparent and red or green.
-DDEBUGVIEWwhich should be set as the compiler flag in debug mode.