Как правильно переопределить установщик свойств? - PullRequest
6 голосов
/ 21 марта 2011

Если я хочу определить пользовательский подкласс UIView, который делает что-то, когда его границы установлены, как я могу переопределить сеттер?Переопределение setBounds кажется опасным, поскольку, если я правильно понимаю, имена получателей и сеттеров не являются частью открытого интерфейса и могут измениться в любое время.

Конечно, я использую class_copyPropertyList, чтобы запросить во время выполнения список свойств, определенныхв классе, затем запросите его для имени установщика и, наконец, используйте class_addMethod для добавления метода, предварительно получив ссылку на более ранний метод для вызова исходной версии.

Все это кажется хакерским.Есть ли чистый способ сделать то, что я хочу, который гарантированно не сломается в будущих версиях ОС?Спасибо.

Ответы [ 3 ]

19 голосов
/ 21 марта 2011

Вы можете переопределить метод установки / получения без необходимости изучать внутреннее состояние класса (т.е. ivars) - просто вызовите методы super в ваших переопределениях:

- (Thing *)thing {
    // do your extra stuff here
    //  ...

    return [super thing];
}

- (void)setThing:(Thing *)thing {
    // do your extra stuff here
    //  ...

    [super setThing:thing];
}

Альтернативой, которая может удовлетворить вашу проблему, является использование KVO .

Обновление

Конечно, переопределение setBounds может не потребоваться. См. этот вопрос - layoutSubviews вызывается при изменении кадра, а изменение границ приводит к тому, что размер кадра также обновляется. Так что подумайте над тем, чтобы поместить свой код в layoutSubviews.

Окончательное обновление

Хорошо, вот почему Apple никогда не собирается внезапно объявить некоторые @property элементы как имена нестандартных методов (как вы боитесь):

Это сломало бы все в магазине приложений.

Подумайте об этом так: во время компиляции любой код, который обращается к свойству с помощью точечной нотации, например синтаксический сахар obj.x преобразуется в сообщение вида [obj x]. Аналогично для свойств - они преобразуются во время компиляции в обычные методы. Итак, скомпилированные двоичные файлы ничего не знают о точечной нотации и свойствах - они просто вызывают обычные селекторы. Так что, если Apple выпустит обновление для iOS, которое объявит некоторые открытые свойства как нестандартные методы реализации, все в приложении Магазин может сломаться. Все. В этом сценарии нет ошибки от вашего имени, если ваше приложение сломалось, как и все остальное, - это вина Apple, а не ваша.

2 голосов
/ 21 марта 2011
@property(nonatomic) CGRect bounds; 

- сокращение для

-(CGRect)bounds; 
-(void)setBounds:(CGRect)bounds; 

,

view.bounds = rect; 

- сокращение для

[view setBounds:rect];

,

CGRect rect = view.bounds;

является сокращением для

CGRect rect = [view bounds];

Обозначения точек и объявления @property являются SYNTACTIC SUGAR.Они для сокращения кода и удобства.Сообщения и селекторы всегда находятся под ними, и на них всегда можно полагать, что они являются стабильной, если не самой стабильной частью интерфейса.

Переопределение setBounds: это безопасный способ сделать это."setBounds:" явно не указан в общедоступном интерфейсе, поскольку он объявлен как @property.Однако стандартом является то, что метод set с именем set -capitalized всегда создается (если только он не доступен для чтения).

0 голосов
/ 22 июля 2013

В OSX есть уведомление NSViewBoundsDidChange.Похоже, что это лучшее решение, хотя опасения переопределения методов @property кажутся необоснованными.Я попал в этот пост с тем же вопросом о переопределении методов доступа, и вы убедили меня предпочесть уведомления.

...