Улучшение Производительности Рисования Изображения на iOS
Q: Что может я делать для улучшения моей производительности рисования изображения (CGContextDrawImage, UIImage/-drawInRect:, и т.д.)?
A: Что может я делать для улучшения моей производительности рисования изображения (CGContextDrawImage, UIImage/-drawInRect:, и т.д.)?
В целом независимо от того что iOS Вы предназначаетесь, необходимо избежать иметь частые вызовы к -drawRect:. Это особенно крайне важно для улучшения Вашей производительности приложения на iPhone 4, потому что у Вас есть четыре раза число пикселей для заполнения на iPhone 4 по сравнению с другими моделями iPhone.
Если Вы поражаете изображение, получающее проблемы производительности, то вероятно, что Вы рисуете изображения в своем представлении -drawRect: использование метода CGContextDrawImage или UIImage/-drawInRect:, и лишают законной силы и перерисовывают представление быстро или даже каждый кадр. Обратите внимание на то, что, из-за способа, которым касание/iPad iPhone/iPod обновляет свой экран, все представление будет перерисовано, если Вы вызовете -setNeedsDisplayInRect: или -setNeedsDisplay:.
Каждый UIView поддерживается a CALayer и изображения как содержание уровня остаются в памяти настолько же долго как CALayer остается в иерархии. Это означает, что большинство операций, которые Вы видите в приложении, включая перемещение, вращение и масштабирование представления/уровня, не требует перерисовки. Лучший путь к анимации (перемещение, вращение или масштабирование) изображения состоит в том, чтобы поэтому создать представления или уровни для изображений и затем использовать Базовую Анимацию, чтобы сделать любую анимацию. Таким образом, можно избежать полностью вызовов к -drawRect: и таким образом вызовы к CGContextDrawImage или UIImage/-drawInRect:.
Для иллюстрирования его с простым примером скажем, Вы хотите нарисовать спрайт, вращающийся о z перпендикуляр оси на экран. Один способ сделать это применялся бы, вращение преобразовывают к Текущей Матрице Преобразования (CGContextRotateCTM) и перерисовка изображения (CGContextDrawImage) в UIView -drawRect: метод на каждом шаге анимации. Однако намного более эффективный путь состоит в том, чтобы установить изображение как contents свойство поддержки CALayer, и затем анимируйте уровень transform свойство для достижения вращающейся анимации. В следующем Перечисление 1 демонстрирует, как установить a UIImage как содержание уровня в a UIImageView, и Перечисление 2 демонстрирует, что пример анимации представления/уровня преобразовывает. Для получения дополнительной информации о программировании с Базовой Анимацией см. Базовое Руководство по программированию Анимации.
Если у Вас есть отдельные движущиеся компоненты в изображении, то необходимо разбить его, чтобы разделить представления или уровни и анимировать их индивидуально. Например, при рисовании перемещаемого дескриптора по изображению, вместо того, чтобы лишить законной силы все представление изображения, когда дескриптор перемещается, необходимо поместить его в отдельный слой и переместить тот уровень.
Существуют некоторые варианты использования (не большинство) для который CALayer и Базовый подход Анимации не будет работать. Для тех случаев имейте в виду это CGContextDrawImage и UIImage/-drawInRect: мог провести много времени в распаковке или передискретизации изображений по мере необходимости, потому что изображения не будут кэшироваться в дереве уровня. Если Вы можете, скорректировать Ваше искусство ресурса так, чтобы размер изображения (в пикселях) совпал со своим выведенным на экран размером (в пикселях), означая обеспечение различных наборов изображения для iPhone/iPod touch (image.png), iPhone 4 (image@2x.png), и iPad (image-iPad.png). Далее, Вы могли кэшировать изображения сами путем вовлечения растрового контекста и кэширования изображения, которое Вы создаете из контекста. Перечисление 3 демонстрирует, как создать Ваше собственное UIImage копия с целевой шириной и высотой. Можно тогда кэшировать получающееся изображение в матрице изображений.
Даже если содержание представления или уровня изменяется таким способом, которым Вы не можете устранить -drawRect: полностью, путем деления содержания на отдельные представления или уровни, можно сократить сумму, которую необходимо перерисовать. Когда Ваше представление логически состоит из многократных независимых частей, рекомендуется разломать его на представление, содержащее подпредставления или подуровней с содержанием в них. Это позволит Вам работать с ними более естественным способом и изолировать свои обновления получения для каждого подраздела представления вместо того, чтобы иметь необходимость пробить пенальти обновления всего представления.
Перечисление 1 , Устанавливающее UIImage как содержание уровня в UIImageView
// This also sets the view's contentScaleFactor to the image's scale factor imageView.image = image; |
Перечисление 2 , Анимирующее z вращение представления
- (void)rotateView:(UIView *)view toAngle:(float)angle { [UIView beginAnimations:nil context:nil]; [view setTransform:CGAffineTransformMakeRotation(angle)]; [UIView commitAnimations]; } |
Перечисление 3 , Изменяющее размеры UIImage. Результат может кэшироваться в матрице изображений.
- (UIImage*)resizeImage:(UIImage*)image toWidth:(NSInteger)width height:(NSInteger)height
{
// Create a graphics context with the target size
// On iOS 4 and later, use UIGraphicsBeginImageContextWithOptions to take the scale into consideration
// On iOS prior to 4, fall back to use UIGraphicsBeginImageContext
CGSize size = CGSizeMake(width, height);
if (NULL != UIGraphicsBeginImageContextWithOptions)
UIGraphicsBeginImageContextWithOptions(size, NO, 0);
else
UIGraphicsBeginImageContext(size);
CGContextRef context = UIGraphicsGetCurrentContext();
// Flip the context because UIKit coordinate system is upside down to Quartz coordinate system
CGContextTranslateCTM(context, 0.0, height);
CGContextScaleCTM(context, 1.0, -1.0);
// Draw the original image to the context
CGContextSetBlendMode(context, kCGBlendModeCopy);
CGContextDrawImage(context, CGRectMake(0.0, 0.0, width, height), image.CGImage);
// Retrieve the UIImage from the current context
UIImage *imageOut = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return imageOut;
} |
История версии документа
| Дата | Примечания |
|---|---|
| 18.08.2010 | Новый документ, обсуждающий, как улучшить CGContextDrawImage и UIImage/drawInRect: производительность на iOS. |