2012-01-15 3 views
2

Как описано в заголовке, я хочу добавить пользовательские свойства для каждого UIViewController и каждого подкласса (например, UITableViewController). Моя первая мысль заключалась в том, чтобы создать категорию, но потом я понял, что в них нельзя добавить иваров, поэтому я не могу синтезировать свойства. Если я просто подклассифицирую UIViewController и добавляю туда вещи, это не повлияет на другие подклассы.Добавление свойств в UIViewController и все его подклассы

В принципе, моя цель - добавить пользовательскую панель инструментов в мой подкласс «UINavigationController» (Нет, я не могу использовать значение по умолчанию по разным причинам). Он должен спросить каждого viewController, хочет ли он панель инструментов, и - в этом случае - для массива элементов toolbarItems. Мне нравится, как работает UIToolbar?

Как вы это сделаете?

+1

Почему не подкласс 'UIViewController', а затем сделать все ваши другие подклассы наследуемыми от этого нового класса? Насколько вы уверены, что ивары являются общими для всех 'UIViewController'? - вполне возможно, что это не так, и вы в конечном итоге используете 'UIViewController' в качестве ведра для хранения всего, включая кухонную раковину, без причины. –

+0

Потому что я не могу изменить, например, суперкласс «UITableViewControler». Однако я мог подклассифицировать каждый из подклассов UIViewController, но это не кажется правильным.Я уточню свой вопрос о распространенности. –

ответ

14

Добавление свойств (с резервным хранилищем) возможно с использованием ObjectO-C ассоциированного объекта API. У меня даже есть небольшой макрос, который я написал для этой цели. Но до макро, вот что это будет выглядеть как «развернутый»:

#import <objc/runtime.h> 

@interface UIViewController (SOAdditions) 
@property (atomic, readwrite, copy) NSString* myProperty; 
@end 

static void * const kMyPropertyAssociatedStorageKey = (void*)&kMyPropertyAssociatedStorageKey; 

@implementation UIViewController (SOAdditions) 

- (void)setMyProperty:(NSString *)myProperty 
{ 
    objc_setAssociatedObject(self, kMyPropertyAssociatedStorageKey, myProperty, OBJC_ASSOCIATION_COPY); 
} 

- (NSString*)myProperty 
{ 
    return objc_getAssociatedObject(self, kMyPropertyAssociatedStorageKey); 
} 

@end 

Вы можете найти documentation for associated storage here. Вы должны знать, что для использования связанных объектов существует ограничение производительности (скорость и память). Они - аккуратный трюк, но вы можете спросить себя, есть ли лучший способ сделать то, что вы пытаетесь сделать. (Опрятная часть трюка, если вы спросите меня, что среда выполнение будет обрабатывать -releases на -dealloc для Вас, в соответствии с политикой вы укажете, смотрите документацию для получения дополнительной информации.)

Теперь вот макрос:

#ifndef ASSOCIATED_STORAGE_PROPERTY_IMP 
#define THREE_WAY_PASTER_INNER(a, b, c) a ## b ## c 
#define THREE_WAY_PASTER(x,y,z) THREE_WAY_PASTER_INNER(x,y,z) 

#define ASSOCIATED_STORAGE_PROPERTY_IMP(type, setter, getter, policy) \ 
static void * const THREE_WAY_PASTER(__ASSOCIATED_STORAGE_KEY_, getter, __LINE__) = (void*)&THREE_WAY_PASTER(__ASSOCIATED_STORAGE_KEY_, getter,__LINE__); \ 
\ 
- (type)getter { return objc_getAssociatedObject(self, THREE_WAY_PASTER(__ASSOCIATED_STORAGE_KEY_, getter,__LINE__)); } \ 
\ 
- (void)setter: (type)value { objc_setAssociatedObject(self, THREE_WAY_PASTER(__ASSOCIATED_STORAGE_KEY_, getter,__LINE__) , value, policy); } \ 

#endif 

Если вы поп, что в файле заголовка, то в приведенном выше примере можно свести к следующим образом:

#import <objc/runtime.h> 

@interface UIViewController (SOAdditions) 

@property (atomic, readwrite, copy) NSString* myProperty; 

@end 

@implementation UIViewController (SOAdditions) 

ASSOCIATED_STORAGE_PROPERTY_IMP(NSString*, setMyProperty, myProperty, OBJC_ASSOCIATION_COPY) 

@end 

это должно пойти, не говоря о том, что политика (то есть сохраняют/копировать/назначить, атомное/nonatomic) вы объявляете в @property decl арация должна соответствовать политике, которую вы используете при использовании макроса (и/или вызываете базовый API, если вы не используете макрос), в противном случае вы закончите утечку памяти (или сбой).

Также , Я скажу еще раз за акцент. Этот трюк не является «бесплатным», поэтому, пожалуйста, не забудьте измерить производительность и убедитесь, что все выгоды, которые вы получаете, используя это, стоят того.

EDIT: Я собираюсь немного отступить от своих решительных и страшных предупреждений о штрафах за производительность связанного хранилища объектов. Существует штраф, но быстрое расследование говорит мне, что свойства, реализованные таким образом, не намного хуже, чем их @synthesized и эквивалентные ivar-эквиваленты. Тест немного надуман, но с 10 000 000 объектов, каждый из которых имеет 5 iVars с поддержкой ассоциативного хранения, я вижу ~ 30% медленную настройку производительности и получение. Это действительно не все так страшно, ИМХО. Я ожидал гораздо хуже. Время, затрачиваемое на управление памятью (сохраняет, копии), связанную с установленными операциями, затмевает накладные расходы из ассоциативных поисков.

+0

Я что-то упустил или это версия макроса сложнее читать? –

+2

Я бы подумал, что это субъективно. Конечно, если читать труднее, не нужно его использовать. – ipmcc

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

  • Нет связанных вопросов^_^