簡體   English   中英

將私有的Objective-C方法或屬性公開給子類

[英]Expose a private Objective-C method or property to subclasses

根據一些官方演講,Objective-C中的類僅應在其標頭中公開公共方法和屬性:

@interface MyClass : NSObject

@property (nonatomic, strong) MyPublicObject *publicObject;

- (void)publicMethod;

@end

和私有方法/屬性應保留在.m文件的類擴展名中:

@interface MyClass()

@property (nonatomic, strong) MyPrivateObject *privateObject;

- (void) privateMethod;

@end

我不認為私有的但可以從子類訪問的事物沒有protected類型。 我想知道,除了公開宣布私有財產/方法之外,還有什么方法可以實現?

解決此問題的一種方法是在子類的類擴展中重新聲明該屬性,然后添加@dynamic語句,以使編譯器不會創建該屬性的重寫實現。 所以像這樣:

@interface SuperClass ()

@property (nonatomic, strong) id someProperty;

@end

....


@interface SubClass ()

@property (nonatomic, strong) id someProperty;

@end

@implementation SubClass

@dynamic someProperty;

@end

這顯然不是理想的,因為它復制了一個私有可見的聲明。 但這在某些情況下非常方便且有幫助,因此我要逐案評估與在公共界面中公開該屬性相比,該復制所涉及的危險。

Apple在UIGestureRecognizer中使用的一種替代方法是在單獨的類別頭文件中聲明該屬性,該頭文件顯式命名為“ private”或“ protected”,例如“ SomeClass + Protected.h”。 這樣,其他程序員將知道他們不應該導入文件。 但是,如果您不控制要從中繼承的代碼,那不是一個選擇。

這可以通過使用包含在基類和子類的實現文件中的類擴展名(而不是類別)來實現。

類擴展的定義類似於類別,但沒有類別名稱:

@interface MyClass ()

在類擴展中,您可以聲明屬性,這些屬性將能夠合成支持的ivars(XCode> 4.4的ivars的自動合成也可以在此處使用)。

在擴展類中,您可以覆蓋/優化屬性(將只讀更改為讀寫等),並添加對實現文件“可見”的屬性和方法(但請注意,這些屬性和方法並非真正私有,可以仍由選擇器調用)。

其他人建議為此使用單獨的頭文件MyClass_protected.h,但是也可以使用#ifdef在主頭文件中完成此操作,如下所示:

例:

BaseClass.h

@interface BaseClass : NSObject

// foo is readonly for consumers of the class
@property (nonatomic, readonly) NSString *foo;

@end


#ifdef BaseClass_protected

// this is the class extension, where you define 
// the "protected" properties and methods of the class

@interface BaseClass ()

// foo is now readwrite
@property (nonatomic, readwrite) NSString *foo;

// bar is visible to implementation of subclasses
@property (nonatomic, readwrite) int bar;

-(void)baz;

@end

#endif

BaseClass.m

// this will import BaseClass.h
// with BaseClass_protected defined,
// so it will also get the protected class extension

#define BaseClass_protected
#import "BaseClass.h"

@implementation BaseClass

-(void)baz {
    self.foo = @"test";
    self.bar = 123;
}

@end

ChildClass.h

// this will import BaseClass.h without the class extension

#import "BaseClass.h"

@interface ChildClass : BaseClass

-(void)test;

@end

ChildClass.m

// this will implicitly import BaseClass.h from ChildClass.h,
// with BaseClass_protected defined,
// so it will also get the protected class extension

#define BaseClass_protected 
#import "ChildClass.h"

@implementation ChildClass

-(void)test {
    self.foo = @"test";
    self.bar = 123;

    [self baz];
}

@end

當您調用#import ,它基本上將.h文件復制粘貼到您要導入的位置。 如果您具有#ifdef ,則僅在設置了具有該名稱的#define ,它才會在其中包含代碼。

在您的.h文件中,您沒有設置定義,因此任何導入此.h的類都不會看到受保護的類擴展。 在基類和子類.m文件中,在使用#import之前先使用#define ,以便編譯器將包括受保護的類擴展名。

雖然其他答案正確,但我想補充一下...

私有,保護和公共可供實例變量這樣:

@interface MyClass : NSObject {
@private
  int varA;

@protected
  int varB;

@public
  int varC;
}

@end

您唯一的選擇是在頭文件中將其聲明為public。 如果至少要保持某種方法的分離,則可以創建一個類別,並在其中保留所有受保護的方法和屬性,但是最后,所有內容仍將是公共的。

#import "MyClass.h"

@interface MyClass (Protected)

- (void) protectedMethods;

@end

只需使用您的類擴展名創建.h文件。 將其導入到您的.m文件中。 順便說一句,這是測試私有成員而不破壞封裝的好方法(我並不是說您應該測試私有方法:))。

// MyClassProtectedMembers.h
@interface MyClass()

@property (nonatomic, strong) MyPrivateObject *privateObject;
- (void) privateMethod;
@end

/////////////////

#import "MyClassProtectedMembers.h"

@implementation MyClass
// implement privateMethod here and any setters or getters with computed values
@end

這是這個主旨: https : //gist.github.com/philosopherdog/6461536b99ef73a5c32a

我看到了使屬性可見的好答案,但是我看不到在任何這些答案中都非常清楚地公開解決的方法。 這是我使用類別成功將私有方法公開給子類的方法:

SomeSuperClass.m:

@implementation SomeSuperClass

-(void)somePrivateMethod:(NSString*)someArgument {
    ...
}

SomeChildClass.h

@interface SomeChildClass : SomeSuperClass

SomeChildClass.m

@interface SomeSuperClass (exposePrivateMethod)
-(void)somePrivateMethod:(NSString*)someArgument;
@end

@implementation SomeChildClass

-(void)doSomething {
    [super somePrivateMethod:@"argument"];
}

@end

那是因為私人與公共之間甚至沒有真正的區別。 盡管編譯器可能會警告您某個接口缺少某些方法或實例變量,但您的程序仍然可以運行。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM