Есть ли причина, по которой я не могу инициализировать CALayer вне класса UIView? - PullRequest
3 голосов
/ 30 апреля 2009

Я пытался использовать CALayers как «спрайты» в приложении для iPhone, над которым я работаю. Из того, что я читал, кажется, что здесь правильно делать.

Когда я настраиваю слой внутри класса UIView, я могу заставить слой отображаться на экране: NSLog (@ "GameView initWithCoder");

NSString* imagePath = [[NSBundle mainBundle] pathForResource:@"earth" ofType:@"png"];
earthImage = [[UIImage alloc] initWithContentsOfFile:imagePath];

earthLayer = [CALayer layer];
[earthLayer setContents:(id)[earthImage CGImage]];
[earthLayer setBounds:CGRectMake(0, 0, 32, 32)];
[earthLayer setPosition:CGPointMake(50, 50)];
[earthLayer setName:@"earth"];

[[self layer] addSublayer:earthLayer];

Однако, когда я пытаюсь инициализировать CALayer вне UIView, мое приложение вылетает:

- (void)loadImage:(NSString*)fileName
{
  NSLog(@"GamePiece loadImage");
  NSArray* fileNameParts = [fileName componentsSeparatedByString:@"."];
  imageName = [[fileNameParts objectAtIndex:0] retain];
  NSString* ext = [fileNameParts objectAtIndex:1];

  NSString* imagePath = [[NSBundle mainBundle] pathForResource:imageName ofType:ext];
  image = [[UIImage alloc] initWithContentsOfFile:imagePath];

  layer = [CALayer layer];
  [layer setContents:(id)[image CGImage]];

  [layer setBounds:CGRectMake(0.0f, 0.0f, 32.0f, 32.0f)];
  [layer setPosition:CGPointMake(50.0f, 50.0f)];
  [layer setName:imageName];

  [fileNameParts release], fileNameParts = nil;
  [ext release], ext = nil;
}

NSLog(@"GameView initWithCoder");
earth = [[GamePiece alloc] init];
[earth loadImage:@"earth.png"];

[[self layer] addSublayer:[earth layer]];

Очевидно, что я делаю что-то не так, но я просто не знаю, что это будет. Я прочитал Руководство по программированию основной анимации, а также Руководство по программированию приложений для iPhone, но, похоже, они действительно не говорят о том, как инициализировать CALayer, кроме как при передаче.

Мне просто нужно слегка подтолкнуть в правильном направлении. Я получил довольно хорошее понимание всего остального, что я узнал, когда дело доходит до программирования iPhone. У меня просто проблемы с графикой, слоями и анимацией.

Заранее спасибо!

Ответы [ 3 ]

2 голосов
/ 30 апреля 2009

Вы не являетесь владельцем слоя, полученного методом layer, поэтому вы должны стать владельцем. Через некоторое время после того, как ваш метод возвращается, слой освобождается, и это вызывает ваш сбой. Чтобы вылечить это:

layer = [[CALayer layer] retain]; // now we explicitly take ownership of this layer

Кроме того, не забудьте освободить слой, так как он у вас сейчас есть:

// in your dealloc method
[layer release];

Вам следует просмотреть Руководство по программированию управления памятью для какао , чтобы узнать больше о том, когда вы владеете объектами и каковы ваши обязанности в отношении управления памятью.

0 голосов
/ 08 октября 2011

Чтобы сделать то, что вы хотели, вот как вы можете изменить свой код. В loadImage: используйте эту строку, чтобы добавить UIImage, который вы загрузили в слой earth:

self.contents = image.CGImage;

CALayers имеет свойство contents, которое можно установить на CGImage, вместо того, чтобы использовать вызовы Core Graphics для рисования изображения в контексте слоя.

Затем в родительском подклассе UIView вы можете добавить earth к иерархии представления следующим образом:

[self.layer addSublayer: earth];

Обратите внимание, что earth сам по себе CALayer с изображением в качестве его содержимого, поэтому я добавляю его непосредственно в качестве подслоя. Другая вещь, которую я всегда забываю сделать, это установить свойство слоя frame. В противном случае его ширина и высота будут равны нулю и поэтому не будут отображаться.

В своем коде вы создали слой, но никогда не добавляли его в иерархию представлений. Есть дерево if views (класс UIView) и их подпредставления. Корнем дерева является [UIWindow mainwindow] (обратите внимание, что UIWindow является подклассом UIView. Каждый UIView имеет свойство layer типа CALayer, которое фактически содержит видимое содержимое. UIView это просто Оберните вокруг CALayer, чтобы добавить такие вещи, как способность обрабатывать прикосновения.

Важная идея, которую вам здесь не хватает, заключается в том, что для того, чтобы что-либо было видно на экране, оно должно быть частью этого дерева представлений с UIWindow в качестве его корня, и все представления должны быть видимыми (т.е. иметь свои hidden свойство установлено на NO) между окном верхнего уровня и соответствующим слоем. Только тогда слой будет виден на экране. Так что где-то в вашем коде вам нужно добавить свой слой как подслой чего-то уже видимого, вызвав addSublayer:.

В вашем случае я предполагаю, что earth является экземпляром CALayer, и что вы сделали в методе loadImage:, это создали новый CALayer (с вызовом [CALayer layer]) в слой earth, но вы никогда не добавляли этот новый слой ни к чему, чтобы он никогда не становился видимым. Вместо этого вы попытались добавить слой earth, который по-прежнему не имеет содержимого, к тому, что я считаю слоем UIView

[[собственный слой] addSublayer: [слой земли]];

Одна проблема с этой строкой в ​​том, что вы, кажется, думаете, layer является свойством earth. На самом деле layer - это метод класса CALayer, который является фабричным методом для создания новых экземпляров CALayer. Это сбивает с толку, потому что [self layer] фактически обращается к свойству layer экземпляра UIView. (Я предполагаю, что self относится к экземпляру UIView подкласса.)

0 голосов
/ 30 апреля 2009

Джейсон, большое спасибо за ответ! Однако ваш ответ, похоже, не влияет на исход моей проблемы.

На самом деле ответ «это» что-то, связанное с управлением памятью. Не Layer, а имя, которое я получил от NSArray после вызова componentSeparatedByString :. Если я не выпускаю NSArray, код работает нормально. Поэтому мне нужно сделать копию строки NSString внутри массива, а не использовать объект в массиве.

Я должен сказать, что я не читал Руководство по программированию управления памятью для какао, как вы предлагаете. Тем не менее, я прочитал несколько других книг, в которых рассказывалось о стандарте, используемом в Какао для созданных объектов, и об их количестве сохраняемых объектов. У меня хорошее понимание, но, видимо, не так хорошо, как нужно.

У меня действительно было подозрение, что я должен скопировать строку из массива, но когда она работала в UIView, я просто предположил, что это правильно. Проблема была в том, что я не держал его так, как будто я нахожусь внутри объекта GamePiece.

Спасибо, что, по крайней мере, заставили меня смотреть в правильном направлении! Я был действительно в конце концов с этим кодом.

...