2012-01-15 76 views
2

正如標題所描述的,我正在爲每個UIViewController和每個子類(如UITableViewController)添加自定義屬性。我的第一個想法是創建一個類別,但後來我意識到不能在它們中添加ivars,所以我無法綜合這些屬性。如果我簡單地繼承UIViewController並在其中添加東西,它不會影響其他子類。將屬性添加到UIViewController及其所有子類

基本上我的目的是將自定義工具欄添加到我的'UINavigationController'子類(不,由於各種原因我不能使用默認值)。它需要詢問每個viewController是否需要一個工具欄,以及 - 在這種情況下 - 對於一組toolbarItems。這有點像我相信UIToolbar的工作原理。

你會怎麼做?

+1

爲什麼不子類化UIViewController,然後讓所有其他的子類繼承這個新類?你是如何確定ivars對所有'UIViewController'都是通用的? - 可能事實證明他們不是,並且最終使用'UIViewController'作爲存儲桶來無故無視所有包括廚房水槽在內的存儲桶。 – 2012-01-15 14:09:37

+0

因爲我無法更改,例如'UITableViewControler'的超類。儘管我可以將每個Apples自己的UIViewController子類繼承下來,但這並不合適。我會更新我關於共同性的問題。 – 2012-01-15 14:41:27

回答

14

使用Objective-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 dec中聲明laration需要符合您在使用宏時使用的策略(和/或調用底層API,如果您不使用宏),否則您最終會泄漏內存(或崩潰)。

此外,我再說一遍重點。這個技巧不是「免費」的,所以請務必衡量性能,並確保使用此功能獲得的任何好處都是值得的。

編輯:我將回溯一下我關於關聯對象存儲性能處罰的強調和可怕警告。這是一種懲罰,但是一項快速調查告訴我,以這種方式實施的財產並不比它們的合成和ivar支持的等價物差得多。這項測試有點人爲設計,但是擁有10,000,000個對象,每個對象都有5個關聯存儲支持的iVar,我看到性能設置和獲取速度降低了〜30%。這真的不是那麼可怕,恕我直言。我期待更糟。花費在執行與集合操作相關的內存管理(保留,複製)上的時間使聯合查找的開銷變得相當小。

+0

我錯過了什麼,或者是難以閱讀的宏版本? – 2012-02-11 17:19:30

+2

我認爲這是主觀的。當然,如果發現閱讀困難,就不必使用它。 – ipmcc 2012-02-11 17:40:25