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