2014-11-21 3 views
0

У меня есть вопрос по поводу следующего кода:слоя CALayer не autoreleased

@interface ViewController() 
@property (nonatomic, weak) CALayer *someLayer; 
@end 

@implementation ViewController 

- (void)viewDidLoad { 
    [super viewDidLoad]; 

    self.someLayer = [CALayer layer]; 
    self.someLayer.frame = CGRectMake(10.0, 10.0, 100.0, 100.0); 
    self.someLayer.backgroundColor = [UIColor yellowColor].CGColor; 
    [self.view.layer addSublayer:self.someLayer]; 
} 
@end 

Из моего понимания [CALayer layer] должен возвращать autoreleased значения, которое должно жить так долго, как вызов метода в процессе. Затем он ссылается на слабое свойство someLayer. Поскольку слой позже удерживается на уровне представления, все должно быть хорошо, и слой должен появиться. Что он делает, но только на устройствах < iPhone 5S. По крайней мере, когда я запускаю код в симуляторах.

На новых устройствах слой не будет отображаться. Изменение атрибута свойства для сильной решает проблему, но я хотел бы знать, почему слой сразу освобождается.

Есть ли у вас какие-либо намеки, как я могу отладить это поведение, чтобы увидеть, что изменилось?

Спасибо!

Update:

Использование self.someLayer = [CALayer [alloc]] init] дает соответствующее предупреждение Xcode warning

, который я понимаю, потому что при использовании alloc значение принадлежит абоненту. Так как владелец не сохраняет значение, нет никакой надежной ссылки. Инициализатор удобства, такой как layer, должен автоматически сохранять сохраненное значение, которое должно быть доступно до тех пор, пока пул авторекламы не будет слит. В этом случае также нет предупреждений Xcode.

Update # 2: Он получает более интересным ... я тестировал код на iPhone 6 с прошивкой 8 и на iPhone 4 с прошивкой 6. слой не будет отображаться на ни их ...

НО

если установить точку останова в линии создания и шага над ним слой будет виден на тренажерах < iPhone 5S и на устройствах.

enter image description here

Как я могу проверить, что происходит под капотом?

Update # 3 и еще некоторые объяснения:

Существует большая статья на Большой Nerd Ranch об этом поведении ARC Gotcha - Unexpectedly Short Lifetimes

Взгляд на разборку для кода выше показывает, как ARC вставляет _objc_retainAutoreleasedReturnValue

Из статьи:

вы можете увидеть д'Арк «избежать тыс e autoorelease pool ": если метод возвращает объект с автореализацией, и вызывающему абоненту в противном случае не нужно висеть на нем, ARC может избежать поездки в пул автозапуска.Метод вернет сохраненный объект, и objc_retainAutoreleasedReturnValue избавится от него.

Таким образом, чтобы избежать проблемы, объявите сильное свойство (как я уже упоминал выше) или взглянем на ответ @ graver.

+0

ARC включен? Это странно, возможно, вам нужно отлаживать устройство. Я не доверяю симуляторам. –

+0

Да, ARC включен. – marcusficner

ответ

2

Поскольку ваше свойство someLayer слабое, вам нечего удерживать ссылку на свой слой. Вы должны изменить свой код так:

... 
CALayer *layer = [CALayer layer]; // by default layer this is __strong, so layer holds a strong reference until the end of the scope 
[self.view.layer addSublayer:layer]; // Now self.view.layer retains the layer 
self.somelayer = layer; // weak reference it 

self.someLayer.frame = CGRectMake(10.0, 10.0, 100.0, 100.0); 
self.someLayer.backgroundColor = [UIColor yellowColor].CGColor; 

// In the end of the scope layer would be released, but it's also retained by self.view.layer and weak referenced by self.someLayer 
... 
+0

Почему исходный код работает на устройствах gabbler

+0

Это хороший вопрос. Теоретически это не должно. Вы тестировали устройство или только симулятор? – graver

+0

@graver См. Мое обновление. Я тестировал его на iPhone 6 с тем же результатом, что и на симуляторе, что означает, что этот слой не виден. – marcusficner

1

код @graver «s работает для меня на реальном iPhone 6 устройств, что означает слой показал, что вы всегда должны полагаться на реальных устройствах вместо тренажеров. Вы можете обратиться к this question и xcode debugger hide issue with weak proper, кажется, что отладчик будет иметь сильное подтверждение для объекта автообновления, поэтому он сохраняется и отображается.

Вы всегда можете проверить self.somelayer, внеся его в систему.

self.someLayer = [CALayer layer]; 
NSLog(@"someLayer is %@",_someLayer); 

Он должен войти в Null, но на некоторых тренажерах было бы имеет значение, которое не должно произойти.

+0

Спасибо за ваш вклад! Я уточнил свой вопрос с некоторыми дальнейшими выводами. – marcusficner

+0

Вы протестировали его, где добавить '[uicolor self]'? – gabbler

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