Ну, я не намного ближе к знанию алгоритма, но теперь у меня есть представление о том, что он делает , а не . Прошлой ночью у меня было немного времени, чтобы подготовить тестовую программу для сравнения методов, и результаты оказались довольно удивительными.
Самым быстрым методом было предварительное преобразование точки в координаты окна, а затем преобразование в каждое целевое представление. Что было удивительно, так это насколько быстрее это было: примерно в 25-27 раз быстрее! И вдобавок ко всему, выполнение двухэтапного преобразования каждый раз (сначала в координаты окна, а затем в отдельный вызов для преобразования в целевое представление) было все еще более чем в 10 раз быстрее, чем одиночный вызов convertPoint:fromView:
с ноль посмотреть аргумент. Я действительно не могу объяснить это. Я мог бы ожидать, что один метод будет в два раза быстрее, но на самом деле не должно быть быстрее сделать два преобразования, чем сделать один напрямую! (Я также пробовал тесты в разных порядках, чтобы убедиться, что это не влияет на время).
Вот результаты (для 1 миллиона конверсий, запущенных на 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
Я опубликую приведенный ниже код для проверки, но если эти результаты верны, я могу только предположить, что код преобразования высоко оптимизирован для преобразования в и из координат окна / экрана и использует некоторый (гораздо более медленный) метод преобразовывать напрямую между двумя системами координат представления, если задан аргумент, отличный от нуля. Возможно, есть условия, в которых несоответствие не так велико (например, когда происходят преобразования, не связанные с идентичностью), но для того, что я ожидаю, это общий случай, кажется, что было бы намного лучше сделать это -переходное преобразование сначала в координаты окна, а затем в другое представление.
Опять же, вероятно, есть несколько обстоятельств, когда это окажет заметное влияние на программу, но об этом следует помнить, если вам когда-либо придется совершать многократные вызовы convertPoint:toView:
или convertPoint:fromView:
.
Вот мой код, если кто-нибудь захочет проверить его на наличие ошибок или запустить его самостоятельно:
@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
Я также протестировал его с 100 подподвидовами, каждый раз выбирая другое на случай, если произойдет какое-то кэширование, и единственное отличие, вероятно, может быть объяснено дополнительными издержками поиска в массиве.
Итак, я не уверен, что с этим делать, но я знаю, как я собираюсь использовать convertPoint:fromView:
в будущем! : -)