1

我試圖將實例變量和屬性添加到現有類。我想要這樣做來擴展開源庫的基類,而不修改源代碼(爲了更容易的代碼管理)。使用類擴展將ivar和屬性添加到類

documentation

不同於常規類,一類擴展可以添加自己的 屬性和實例變量的類。如果您在類擴展中聲明 屬性,編譯器將自動合成 合成主類實現內的相關訪問器方法以及實例 變量。

我試圖在測試應用程序中做到這一點。我有一個空類ClassA

ClassA.h

#import <Foundation/Foundation.h> 
@interface ClassA : NSObject 
@end 

ClassA.m

#import "ClassA.h"  
@implementation ClassA 
@end 


然後,我添加的擴展:

ClassA的+ Ext.h

#import "ClassA.h" 
@interface ClassA() 

@property (nonatomic) NSString *name;  // <-- this is my new property 

@end 


最後,在我的AppDelegate我只是一個初始化和ClassA嘗試設置,然後再登錄該name

#import "AppDelegate.h" 
#import "ClassA.h" 
#import "ClassA+Ext.h" 

@implementation AppDelegate 

- (void)applicationDidFinishLaunching:(NSNotification *)aNotification 
{ 
    ClassA *a = [[ClassA alloc] init]; 
    a.name = @"test"; 
    NSLog(@"Name: %@", a.name); 
} 

@end 

這編譯和運行,但我得到了控制檯上的錯誤:

2013-05-10 00:58:08.598 Test[53161:303] -[ClassA setName:]: unrecognized selector 
sent to instance 0x108a1a630 
2013-05-10 00:58:08.600 Test[53161:303] -[ClassA setName:]: unrecognized selector 
sent to instance 0x108a1a630 

名稱沒有登錄。如果我設置了一個斷點並檢查ClassA實例,它沒有name伊娃。我究竟做錯了什麼?這實際上不可能做到嗎?

+0

這個錯誤與一個ivar在那裏或沒有沒有關係。問題在於該屬性的setter方法無法識別。註釋掉'a.name = ...'這一行並查看在日誌語句中是否存在與「getter」有關的問題。 – rmaddy 2013-05-09 23:04:35

+0

如果我這樣做,我得到的錯誤爲getter [[ClassA name]] – DrummerB 2013-05-09 23:07:44

+1

正如刪除的答案所述,添加到類擴展中的屬性對於類是私有的。這就是爲什麼另一個類無法看到private屬性'name'的setter或getter。 – rmaddy 2013-05-09 23:11:12

回答

3

你的理解是不正確的。您通過類​​擴展添加了一個屬性。這個屬性應該只能在你的類中使用。它不應該被用作你的類的一個真正的「屬性」,你可以通過外部實例化來改變它。把它看作一個僞私有實例變量。

我相信你想要做的就是簡單地繼承你的A類什麼

提出的另一種可行的解決方案是:

「你可以寫一個類別,它包裝成 - [setAssociatedObject:forKey:]」當使用objc_setAssociatedObject - > by @Artur

+0

我不能繼承子類,因爲這是庫中的基類和庫中的其他類的子類。我必須改變很多才能在層次結構中插入額外的類,這使得代碼非常繁瑣。 – DrummerB 2013-05-09 23:15:06

+0

然後對需要變量的類進行子類化,不必在根目錄下執行它。 – 2013-05-09 23:16:23

+0

不幸的是他們都需要它。這就像圖書館的創建者忘了將通常的'userData'或'userInfo' ivar添加到API中。 – DrummerB 2013-05-09 23:18:47

0

我認爲類擴展應該放在class.m文件中,通常放在類的@implementation之上。