UIView如何在视图之间转换点?

时间:2011-05-16 22:56:33

标签: ios uikit

有没有人知道UIView的convertPoint:toView:convertPoint:fromView:方法使用的算法?特别是,你知道他们是先将点转换为窗口坐标然后再转换到目标视图的坐标系,还是可以采用捷径,因为“from”视图是“to”视图的祖先?

我问,因为我有一个循环测试一个点可能有大量的视图,我想知道在循环之前将该点转换为窗口坐标是否更有效(这也有利于不必将点的视图传递到循环中,无论它调用什么,知道我可以为“fromView”参数传递nil,或者保持相对于父视图的点。

差别可能很小但是,因为它对我的代码没什么影响,所以我宁愿使用系统而不是反对它。

1 个答案:

答案 0 :(得分:13)

嗯,我不太了解算法是什么,但我现在已经知道它不是做什么了。我昨晚有点时间来制作测试程序以比较方法,结果相当令人惊讶。

最快的方法是将点预转换为窗口坐标,然后转换为每个目标视图。令人惊讶的是它的速度是多少:大约快25-27倍!最重要的是,每次进行两阶段转换(首先是窗口坐标,然后单独调用以转换为目标视图)仍然比单次调用convertPoint:fromView:的速度快10倍以上非零视角论证。我真的无法解释这一点。我可能已经预料到一种方法可以达到两倍的速度,但是进行两次转换确实不应该比直接做一次更快! (我也尝试了各种顺序的测试,以确保不会影响时间。)

以下是结果(100万次转换,在iPad 1,iOS 4.3.3上运行):

convert from window point: 0.204297
two-step convert through window coordinates: 0.390832
convert from subview point: 5.020129

我将发布下面的代码供审阅,但如果这些结果是正确的,我唯一的猜测是转换代码高度优化,以转换到窗口/屏幕坐标和从窗口/屏幕坐标转换,并使用一些(慢得多)方法在给定非零视图参数时直接在两个视图坐标系之间转换。也许存在差异不是那么大的情况(例如涉及非身份转换的情况),但是对于我所期望的常见情况,看起来这样做会好得多。 -step首先转换为窗口坐标,然后转换到另一个视图。

同样,可能很少会出现这会对程序产生明显影响的情况,但如果您不得不重复拨打convertPoint:toView:或{{1},请注意这一点。 }。

这是我的代码,如果有人关心检查错误或自行运行:

convertPoint:fromView:

我还测试了100个子子视图,每次都选择不同的子视图,以防有一些缓存,并且唯一的区别可能是在数组查找的额外开销中。

所以,我不知道该怎么做,但我知道将来我将如何使用@implementation TestConvertPointViewController - (NSTimeInterval) timeForBlock:(void (^)())block { CFAbsoluteTime startTime = CFAbsoluteTimeGetCurrent(); block(); return CFAbsoluteTimeGetCurrent() - startTime; } - (void) millionTimes:(void (^)(NSUInteger))block { for (NSUInteger i = 0; i < 1000000; i++) { block(i); } } - (void)loadView { UIView* rootView = [[UIView alloc] initWithFrame:[[UIScreen mainScreen] applicationFrame]]; UIView* subview = [[UIView alloc] initWithFrame:CGRectMake(100, 100, 250, 500)]; UIView* subSubview = [[UIView alloc] initWithFrame:CGRectMake(20, 10, 130, 190)]; UIView* subSubSubview = [[UIView alloc] initWithFrame:CGRectMake(50, 10, 50, 100)]; [subSubview addSubview:subSubSubview]; [subview addSubview:subSubview]; [rootView addSubview:subview]; self.view = rootView; } - (void)test { UIView* subview = [[self.view subviews] objectAtIndex:0]; UIView* subSubview = [[subview subviews] objectAtIndex:0]; UIView* subSubSubview = [[subSubview subviews] objectAtIndex:0]; CGPoint testPoint = CGPointMake(10.0, 30.0); NSTimeInterval time; time = [self timeForBlock:^{ [self millionTimes: ^(NSUInteger i){ [subSubSubview convertPoint:testPoint fromView:nil]; } ]; } ]; NSLog(@"convert from window point: %f", time); time = [self timeForBlock:^{ [self millionTimes: ^(NSUInteger i){ CGPoint rootPoint = [subview convertPoint:testPoint toView:nil]; [subSubSubview convertPoint:rootPoint fromView:nil]; } ]; } ]; NSLog(@"two-step convert through window coordinates: %f", time); time = [self timeForBlock:^{ [self millionTimes: ^(NSUInteger i){ [subSubSubview convertPoint:testPoint fromView:subview]; } ]; } ]; NSLog(@"convert from subview point: %f", time); } - (void)viewDidLoad { [super viewDidLoad]; [self test]; } @end ! : - )