2015-06-19 2 views
8

На данный момент я создаю некоторые переходы и преобразую через CGAffineTransform для панорамирования, и я столкнулся с проблемами из-за производительности преобразования под iOS 7 и iPhone 4.Производительность CGAffineTransforms очень медленная на iOS 7

Я погрузился в Istruments и зарегистрировал материал, и тяжелый подъем выполняется, когда я применяю свои преобразования к виду.

Текущая реализация

func handlePan(recognizer : UIPanGestureRecognizer) { 

     let drawerLocation = recognizer.locationInView(drawerView!) 
     let locationInView = recognizer.locationInView(containerView!) 
     let progressMax = containerView!.frame.height - 40 - 20 

     if(recognizer.state == .Changed) { 

      let offsetDrag = dragStartPosition.y - locationInView.y 
      let progress = Float(offsetDrag/progressMax) 

      if(offsetDrag >= 0) { 

       let positionTransform = CGAffineTransformMakeTranslation(0, -((containerView!.bounds.height - 40 - 20) * CGFloat(normalizedProgress))) 
       viewWithTransform.transform = positionTransform // really bad performance here 
      } else { 
       // reset the transition 
      }  
    } 
} 

Обход прошивкой 7

func handlePan(recognizer : UIPanGestureRecognizer) { 

     let drawerLocation = recognizer.locationInView(drawerView!) 
     let locationInView = recognizer.locationInView(containerView!) 
     let progressMax = containerView!.frame.height - 40 - 20 

     if(recognizer.state == .Changed) { 

      let offsetDrag = dragStartPosition.y - locationInView.y 
      let progress = Float(offsetDrag/progressMax) 

      if(offsetDrag >= 0) { 
       if UIDevice.currentDevice().systemMajorVersion() > 7 { 
        let positionTransform = CGAffineTransformMakeTranslation(0, -((containerView!.bounds.height - 40 - 20) * CGFloat(progress))) 
        viewWithTransform.transform = positionTransform // really bad performance here 
       } else { 
        viewWithTransform.frame = CGRectMake(0, -((containerView!.bounds.height - 40 - 20) * CGFloat(progress)), drawerView!.frame.size.width, drawerView!.frame.size.height); // works like a charm on iOS 7 
       } 

      } else { 
       // reset the transition 
      }  
    } 
} 

Вопрос

Почему производительность так плохо на прошивкой 7 и мой iPhone 4 с CGAffineTransforms ? Потому что он делает то же самое со смещением, а затем с настройкой рамки в обходном пути. Когда я использую UIView.animateWithDuration() с преобразованием, он выполняет 60 кадров в секунду. Что я могу сделать, чтобы не переписать всю реализацию на моем iOS 7?

ОБНОВЛЕНИЕ 28 июля Обнаружил, что в этом вопросе может участвовать AutoLayout. Вот TimeProfiler Стек из моих текущих вызовов:

Time Profiler

Теперь я столкнулся с большой проблемой в моей текущей реализации, потому что я полагаюсь на AutoLayout. Какое самое простое решение для решения этой проблемы на iOS 7?

+0

Is 'viewWithTransform.translate =' что-то пользовательское или предполагается, что оно 'viewWithTransform.transform ='? Вы (намеренно или непреднамеренно) используете автоматическую компоновку? Профилируете ли вы с помощью релизов? –

ответ

4

В то время как вы правы, что они делают то же самое, под капотом это не так просто - есть матричные умножения, идущие повсеместно. More on that can be found here.

Странно, что если вы делаете именно это, это влияет на вашу производительность - но я предполагаю, что ваш макет сложный, и поэтому для повторного рендеринга требуется много времени; Я на самом деле была такая же проблема, как и неделю назад, так вот что помогло мне:

  • удаление AutoLayout из этой конкретной точки зрения по какой-то причине очень помогает
  • манипуляции с рамкой следует использовать, когда вы не вращаются/масштабирование. Это действительно становится необходимостью, когда вы их используете.
  • удаления тени и полупрозрачные вид, особенно если Eсть больше их друг за другом, на самом деле падает FPS при преобразовании используется

Кроме того, вы можете попробовать назначить, что преобразование в асинхронном вызове и увидеть если это помогает:

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), {() -> Void in 
     dispatch_async(dispatch_get_main_queue(), {() -> Void in 
      // Transform view 
     }) 
    }) 

И если вы действительно хотите быть фантазии, использовать POP Framework from Facebook. Это здорово, что вы хотите, и это позволяет сделать некоторые модные вещи, как рикошет, и т.д. пружинистость Вот как вы можете использовать его:

// Create spring animation (there are more types, if you want) 
let animation = POPSpringAnimation(propertyNamed: kPOPViewCenter) 

// Configure it properly 
animation.autoreverses = false 
animation.removedOnCompletion = true 
animation.fromValue = view.center 
animation.toValue = finalPositionPoint 

// Add new animation to your view - animation key can be whatever you like, serves as reference 
view.pop_addAnimation(animation, forKey: "YourAnimationKey") 

Edit: Если вы двигаетесь вид вокруг, использовать ,центр, а не кадр. Это поможет вам снова определить высоту/ширину и дать более четкое представление о ваших намерениях.

+0

Я пробую вещь dispatch_async. Это очень легко. Я нахожусь в main_queue и отправляю преобразование в следующую runloop в главной очереди. Звучит просто. Я знаю POP из facebook, но есть ли возможность использовать это при обработке жесты? Я имею в виду, что это называется много;) – mariusLAN

+0

Для жесты pan, я предлагаю вам создать одну анимацию весны для вашего элемента и установить свойство removedOnCompletion = false. Таким образом, он будет работать неопределенно, даже после того, как он достигнет своего «toValue». Когда вы панорамируете, просто измените значение .Value, и он снова начнет оживлять. –

+0

@mariusLAN вам удалось решить вашу проблему, используя мое решение? –

Смежные вопросы