Определение свойства в расширении класса iOS
Я хотел бы добавить свойство в UITableView в расширение класса:
@interface UITableViewController ()
@property NSString *entityString;
@end
Затем я импортирую расширение, а затем я использую свойство entityString в подклассе UITableViewController:
@implementation CustomerTableViewController
- (void)viewDidLoad {
self.entityString = @"Customer";
...
[super viewDidLoad];
}
...
Документация Apple говорит:
компилятор автоматически синтезирует соответствующий элемент доступа методы (...) внутри основного класса реализация.
Но когда я пытаюсь выполнить его, я получаю эту ошибку:
- [CustomerTableViewController setEntityString:]: непризнанный селектор, отправленный экземпляру 0x737b670
Что я делаю неправильно? возможно, к объекту недоступны подклассы?
Ответы
Ответ 1
Расширение класса используется для объявления дополнительного интерфейса - методов и свойств, чей контракт на реализацию будет выполняться внутри класса primary @implementaiton
.
Именно поэтому вы не можете добавить хранилище - добавить ivars - через расширение класса. Расширение класса - это интерфейс, не более, не меньше. @synthesize
- это то, что создает хранилище для объявлений @property
, но @synthesize
для @property
может отображаться только в @implementation
класса (явно или по умолчанию для компилятора).
Поскольку вы не можете перекомпилировать класс framework, вы не можете добавить туда ivars.
@prashat ответ - один из способов добавить хранилище в существующий класс. Однако этот маршрут обычно нежелателен; зависание состояния каркасных классов волей-неволей является признаком плохого дизайна и сделает ваше приложение значительно сложнее поддерживать с течением времени.
Намного лучше пересмотреть дизайн, понять, почему в настоящее время требуется привязать состояние к объекту, который не может содержать его напрямую, и рефакторинг этого требования.
Ответ 2
Попробуйте использовать категорию с Ассоциативными ссылками. Он намного чище и будет работать во всех экземплярах UIButton.
UIButton+Property.h
#import <Foundation/Foundation.h>
@interface UIButton(Property)
@property (nonatomic, retain) NSObject *property;
@end
UIButton+Property.m
#import "UIButton+Property.h"
#import <objc/runtime.h>
@implementation UIButton(Property)
static char UIB_PROPERTY_KEY;
@dynamic property;
-(void)setProperty:(NSObject *)property
{
objc_setAssociatedObject(self, &UIB_PROPERTY_KEY, property, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
-(NSObject*)property
{
return (NSObject*)objc_getAssociatedObject(self, &UIB_PROPERTY_KEY);
}
@end
//Пример использования
#import "UIButton+Property.h"
UIButton *button1 = [UIButton buttonWithType:UIButtonTypeRoundedRect];
button1.property = @"HELLO";
NSLog(@"Property %@", button1.property);
button1.property = nil;
NSLog(@"Property %@", button1.property);
Ответ 3
Состояние документов:
Расширения классов похожи на анонимные категории, за исключением того, что методы, которые они объявляют, должны быть реализованы в основном блоке @implementation для соответствующего класса.
Когда вы используете @property
, это примерно эквивалентно объявлению методов доступа. Таким образом, это означает, что вы можете делать это только в том случае, если вы также являетесь автором блока "main" @implementation
класса, который с UITableViewController вы не являетесь.
Ваш единственный вариант здесь - это категории, которые не могут добавлять переменные экземпляра.
Ссылка docs, и обратите внимание на самую последнюю строку этой страницы:
Реализация метода setValue: должна отображаться в основном блоке @implementation для класса (вы не можете реализовать его в категории). Если это не так, компилятор выдает предупреждение о том, что он не может найти определение метода для setValue:.