Почему addSubview: не сохраняет вид? - PullRequest
7 голосов
/ 17 марта 2012

Я добавляю два подпредставления, которые хранятся в свойствах, в мое представление. При добавлении подпредставлений к моему представлению подпредставления, по-видимому, освобождаются после вызова моего метода setup. Конечный результат - представления никогда не отображаются Теперь, если я изменю свои свойства на strong вместо weak, я сохраню ссылку на виды, и они теперь отображаются на экране. Так что здесь происходит? Почему addSubview: и insertSubview: не сохраняют подпредставления? Смотрите код ниже:

Кстати, я использую iOS5 с ARC (отсюда сильные и слабые стороны)

#import "NoteView.h"
@interface NoteView() <UITextViewDelegate>
@property (weak, nonatomic) HorizontalLineView *horizontalLineView;  // custom subclass of UIView that all it does is draw horizontal lines
@property (weak, nonatomic) UITextView *textView;
@end

@implementation NoteView
@synthesize horizontalLineView = _horizontalLineView;
@synthesize textView = _textView;

#define LEFT_MARGIN 20
- (void)setup
{
    // Create the subviews and set the frames
    self.horizontalLineView = [[HorizontalLineView alloc] initWithFrame:self.frame];
    CGRect textViewFrame = CGRectMake(LEFT_MARGIN, 0, self.frame.size.width, self.frame.size.height);
    self.textView = [[UITextView alloc] initWithFrame:textViewFrame];


    // some addition setup stuff that I didn't include in this question...

    // Finally, add the subviews to the view
    [self addSubview:self.textView];
    [self insertSubview:self.horizontalLineView atIndex:0];
}

- (void)awakeFromNib
{
    [super awakeFromNib];

    [self setup];
}

- (id)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {
        // Initialization code
        [self setup];
    }
    return self;
}

Ответы [ 3 ]

21 голосов
/ 17 марта 2012

Вот строка вашего кода:

self.horizontalLineView = [[HorizontalLineView alloc] initWithFrame:self.frame];

Напомним, что свойство horizontalLineView является слабым. Давайте пройдемся по тому, что действительно происходит в этой строке, с дополнительным кодом, который генерирует ARC. Сначала вы отправляете методы alloc и initWithFrame:, получая надежную ссылку:

id temp = [[HorizontalLineView alloc] initWithFrame:self.frame];

На данный момент объект HorizontalLineView имеет счет сохранения 1. Далее, поскольку вы использовали точечный синтаксис для установки свойства horizontalLineView, компилятор генерирует код для отправки метода setHorizontalLineView: в self , передав temp в качестве параметра. Поскольку свойство HorizontalLineView объявлено weak, метод установки делает это:

objc_storeWeak(&self->_horizontalLineView, temp);

Это устанавливает self->_horizontalLineView равным temp и помещает &self->_horizontalLineView в список слабых ссылок объекта. Но он не увеличивает счетчик сохранения HorizontalLineView объекта.

Наконец, поскольку переменная temp больше не нужна, компилятор генерирует это:

[temp release];

Это уменьшает количество сохраняемых объектов HorizontalLineView до нуля, поэтому освобождает объект. Во время освобождения он просматривает список слабых ссылок и устанавливает для каждой nil. Так что self->_horizontalLineView становится nil.

Способ исправить это - сделать переменную temp явной, чтобы вы могли продлить срок ее службы до тех пор, пока вы не добавите объект HorizontalLineView в его суперпредставление, которое сохраняет его:

HorizontalLineView *hlv = [[HorizontalLineView alloc] initWithFrame:self.frame];
self.horizontalLineView = hlv;
// ...
[self insertSubview:hlv atIndex:0];
3 голосов
/ 17 марта 2012

Слабое не следует использовать, если только в случаях, когда не сформирован цикл сохранения родитель-потомок (родительский элемент сохраняет ссылку на дочерний элемент, дочерний элемент сохраняет ссылку на родительский элемент, поэтому ни один из них не является dealloc'd). Strong является ARC-эквивалентом retain (теперь недопустимым для ARC) и сохраняет хороший стабильный указатель на объект в течение гораздо более длительного периода времени, чем слабая ссылка, поэтому addSubview фактически работает вместо того, чтобы выдавать какую-то ошибку.

Почему addSubview: и insertSubview: не сохраняют подпредставления?

Вы когда-нибудь пытались вызвать retain для нулевого объекта? Да, все еще ноль. Ваша слабая ссылка не удерживает объект UIView достаточно долго, чтобы успешно «вызвать удержание» объекта.

0 голосов
/ 17 марта 2012

Попробуйте использовать это вместо:

    @property (nonatomic, retain)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...