2010-11-10 175 views
30

我有一種情況,似乎需要將實例變量添加到類別中,但是我從Apple的文檔中知道我無法做到這一點。所以我想知道最好的選擇或解決方法是什麼。目標C類別的實例變量

我想要做的是添加一個類添加到UIViewControllers的功能。我會發現它適用於我所有不同的UIViewControllers,無論它們擴展了哪些特定的UIViewController子類,所以我認爲類是最好的解決方案。爲了實現這個功能,我需要幾種不同的方法,我需要跟蹤它們之間的數據,所以這就是我想要創建實例方法的原因。

如果有幫助,這是我特別想要做的。我想更容易地跟蹤軟件鍵盤隱藏和顯示的時間,以便我可以調整視圖中的內容大小。我發現唯一可行的方法是將代碼放在四個不同的UIViewController方法中,並跟蹤實例變量中的額外數據。因此,這些方法和實例變量是我想要放到一個類別中的,所以我不必在每次需要處理軟件鍵盤時都複製粘貼它們。 (如果對於這個確切的問題有一個更簡單的解決方案,那也沒關係 - 但我仍然想知道類別實例變量的答案以備將來參考!)

+5

你可以創建一個子類嗎? – kennytm 2010-11-10 15:46:14

回答

0

爲什麼不簡單地創建UIViewController的子類,爲此,然後使用該類(或其子類)來代替?

+6

'UITableViewController'是'UIViewController'的子類。一個類將爲兩者添加功能,而一個子類則不會。 – 2010-11-10 15:50:33

+1

我懷疑OP遇到了他們無法控制的'UIViewController'子類。 – Justin 2010-11-10 15:51:56

+0

我明白你的觀點。有些措辭讓我覺得這些純粹是OP自己的直接UIViewController子類。我懷疑KennyTM(根據他的評論)以同樣的方式閱讀。 :-) – 2010-11-10 16:01:58

0

根據你在做什麼,你可能想要使用靜態類別方法。

所以,我認爲你有這樣的問題:

滾動型有一對夫婦在他們textedits的。用戶鍵入文本編輯時,您需要滾動滾動視圖,以便在鍵盤上方顯示文本編輯。

+ (void) staticScrollView: (ScrollView*)sv scrollsTo:(id)someView 
{ 
    // scroll view to someviews's position or some such. 
} 

從這返回並不一定需要視圖移回,因此它不需要存儲任何東西。

但這就是我能想到沒有代碼示例,對不起。

0

我相信可以使用Obj-C運行時將變量添加到類中。
我發現this discussion也。

+0

這是否使它成爲iOS?我沒有跟上這個新功能(它對我來說似乎太髒了:-))。 – 2010-11-10 16:05:30

7

我相信現在可以將合成屬性添加到類別中,並且實例變量是自動創建的,但是我從來沒有嘗試過,所以我不確定它是否可行。

更哈克的解決方案:

創建一個單獨的NSDictionary這將有作爲的UIViewController鑰匙(或者更確切地說,它的地址包裹作爲NSValue)和你的財產作爲其價值的價值。

爲屬性創建getter和setter,以便實際訪問字典以獲取/設置屬性。

@interface UIViewController(MyProperty) 

@property (nonatomic, retain) id myProperty; 
@property (nonatomic, readonly, retain) NSMutableDcitionary* propertyDictionary; 

@end 

@implementation UIViewController(MyProperty) 

-(NSMutableDictionary*) propertyDictionary 
{ 
    static NSMutableDictionary* theDictionary = nil; 
    if (theDictionary == nil) 
    { 
     theDictioanry = [[NSMutableDictionary alloc] init]; 
    } 
    return theDictionary; 
} 


-(id) myProperty 
{ 
    NSValue* key = [NSValue valueWithPointer: self]; 
    return [[self propertyDictionary] objectForKey: key]; 
} 

-(void) setMyProperty: (id) newValue 
{ 
    NSValue* key = [NSValue valueWithPointer: self]; 
    [[self propertyDictionary] setObject: newValue forKey: key];  
} 

@end 

兩個潛在的問題與上面的方法:

  • 沒有辦法刪除已釋放視圖控制器的按鍵。只要你只追蹤一小撮,那應該不成問題。或者您可以添加一種方法,在知道完成後從字典中刪除密鑰。
  • 我不是100%確定NSValue的isEqual:方法比較內容(即包裝的指針)以確定是否相等,或者它是否比較self以查看比較對象是否完全相同的NSValue。如果是後者,則必須使用NSNumber而不是NSValue作爲密鑰(在32位和64位平臺上,NSNumber numberWithUnsignedLong:都會起作用)。
+4

....或者你可以使用相關的參考文獻 – 2010-11-10 17:28:09

26

是的,你可以做到這一點,但既然你問了,我必須問:你是否確定你需要? (如果你說「是」,然後回去,找出你想做什麼,看看是否有不同的方式來做到這一點)

但是,如果你真的想注入存儲到一個類, t控制,請使用associative reference

+0

我不知道關聯參考,好的提示! – 2011-06-21 18:56:07

+4

新的關聯參考鏈接:http://developer.apple.com/library/ios/#documentation/Cocoa/Conceptual/ObjectiveC/Chapters/ocAssociativeReferences.html – lilbyrdie 2011-06-24 17:55:30

+0

@lilbyrdie謝謝我修復了鏈接:) – 2011-06-24 18:00:01

14

最近,我需要這樣做(將狀態添加到類別)。 @Dave DeLong對此有正確的看法。在研究最佳方法時,我發現Tom Harrington的一個很棒的blog post。我喜歡@ JeremyP關於在類別中使用@property聲明的想法,但不是他的特定實現(不是全局單例的粉絲或持有全局引用)。聯想參考是要走的路。

這是代碼添加(看起來像)的ivars到您的類別。我詳細地對此進行了博客here的博客。

在File.h,來電者只看到乾淨的,高層次的抽象:

@interface UIViewController (MyCategory) 
@property (retain,nonatomic) NSUInteger someObject; 
@end 

在File.m,我們可以實現@property(注意:這些不能@ synthesize'd) :

@implementation UIViewController (MyCategory) 

- (NSUInteger)someObject 
{ 
    return [MyCategoryIVars fetch:self].someObject; 
} 

- (void)setSomeObject:(NSUInteger)obj 
{ 
    [MyCategoryIVars fetch:self].someObject = obj; 
} 

我們還需要聲明和定義類MyCategoryIVars。爲了便於理解,我已經從正確的編譯順序中解釋了這一點。 @接口需要放在Category @實現之前。

@interface MyCategoryIVars : NSObject 
@property (retain,nonatomic) NSUInteger someObject; 
+ (MyCategoryIVars*)fetch:(id)targetInstance; 
@end 

@implementation MyCategoryIVars 

@synthesize someObject; 

+ (MyCategoryIVars*)fetch:(id)targetInstance 
{ 
    static void *compactFetchIVarKey = &compactFetchIVarKey; 
    MyCategoryIVars *ivars = objc_getAssociatedObject(targetInstance, &compactFetchIVarKey); 
    if (ivars == nil) { 
    ivars = [[MyCategoryIVars alloc] init]; 
    objc_setAssociatedObject(targetInstance, &compactFetchIVarKey, ivars, OBJC_ASSOCIATION_RETAIN_NONATOMIC); 
    [ivars release]; 
    } 
    return ivars; 
} 

- (id)init 
{ 
    self = [super init]; 
    return self; 
} 

- (void)dealloc 
{ 
    self.someObject = nil; 
    [super dealloc]; 
} 

@end 

上面的代碼聲明並實現了持有我們的ivars(someObject)的類。由於我們無法真正擴展UIViewController,這將不得不做。

+1

在您的示例中實現,'-init'覆蓋服務的目的是什麼?這似乎是一個沒有操作。謝謝! – Olie 2014-07-22 18:16:41

+1

@Olie,你是對的,這是不需要的。我傾向於用我的編碼來強調一點OCD。由於有一個dealloc,我喜歡提供一個匹配的init來提醒自己在添加資源到對象時觸及兩者。你可以安全地消除它。 – 2014-07-23 19:17:50

+0

沒問題。由於我剛接觸'objc_setAssociatedObject()',我不確定是否存在某種奇怪的,令人滿意的副作用。謝謝! – Olie 2014-07-23 22:44:55

5

使用內置的ObjC功能關聯對象(又名關聯引用)最好實現,在下面的示例中,只需更改爲您的類別並用您的變量名替換associatedObject。

NSObject的+ AssociatedObject.h

@interface NSObject (AssociatedObject) 
@property (nonatomic, strong) id associatedObject; 
@end 

NSObject的+ AssociatedObject.m

#import <objc/runtime.h> 

@implementation NSObject (AssociatedObject) 
@dynamic associatedObject; 

- (void)setAssociatedObject:(id)object { 
    objc_setAssociatedObject(self, @selector(associatedObject), object, OBJC_ASSOCIATION_RETAIN_NONATOMIC); 
} 

- (id)associatedObject { 
    return objc_getAssociatedObject(self, @selector(associatedObject)); 
} 

在這裏看到完整的教程:

http://nshipster.com/associated-objects/

3

它在許多文檔的在線中都提到,您無法在類別中創建新的變量,但我發現了一種實現該功能的非常簡單的方法。這是讓類聲明新變量的方法。

在你的。.h文件

@interface UIButton (Default) 

    @property(nonatomic) UIColor *borderColor; 

@end 

在您.m文件

#import <objc/runtime.h> 
static char borderColorKey; 

@implementation UIButton (Default) 

- (UIColor *)borderColor 
{ 
    return objc_getAssociatedObject(self, &borderColorKey); 
} 

- (void)setBorderColor:(UIColor *)borderColor 
{ 
    objc_setAssociatedObject(self, &borderColorKey, 
          borderColor, OBJC_ASSOCIATION_RETAIN_NONATOMIC); 
    self.layer.borderColor=borderColor.CGColor; 
} 

@end 

這就是現在你有新的變量。