Objective-Cの保護されたメソッド


112

Objective-Cの保護されたメソッドに相当するものは何ですか?派生クラスのみが呼び出し/実装できるメソッドを定義したい。

回答:


47

メソッドを保護またはプライベートとして宣言することはできません。Objective-Cの動的な性質により、メソッドのアクセス制御を実装することは不可能です。(コンパイラーまたはランタイムを大幅に変更することで、速度が大幅に低下する可能性がありますが、明らかな理由により、これは行われません。)

ソースから取得


技術的にはできませんが、プライベート変数をエミュレートできます。
Sharen Eayrs

Lee-@protectedで関数ポインターを宣言し、initメソッドで関数を割り当てると、機能しますか?
bikram990 2014年

156

次のようにして、メソッドへの保護されたアクセスとプライベートアクセスをシミュレートできます。

  • クラス拡張でプライベートメソッドを宣言します(つまり、クラスの.mファイルの先頭近くで宣言されている名前のないカテゴリ)
  • 保護されたメソッドをサブクラスヘッダーで宣言する– Appleは、UIGestureRecognizerに関してこのパターンを使用します(UIGestureRecognizerSubclass.hのドキュメントとリファレンスを参照)

Sachinが述べたように、これらの保護は実行時に適用されません(たとえば、Javaの場合)。


2
UIGestureRecognizerに似たソリューションについて:問題は、一部のコードがサブクラスをインポートする場合、サブクラスヘッダーもインポートするため、「保護された」メソッドにアクセスできることです。それを回避する方法はありますか?
yonix

5
こんにちはyonix、サブクラスヘッダーのインポートは.hファイル内ではなく.mファイル内で行われるため、サブクラスをインポートしてもこれらの保護されたメソッドはインポートされません。
ブライアンウェストファル

クールな提案ブライアン、ありがとう、トン!! 元の投稿者に対して、宣言されたプロパティについては、サブクラスのクラス拡張(名前のないカテゴリ)実装で@dynamicを使用し、実行時に親クラスの実装が使用されるようにしてください
user1046037

1
UIGestureRecognizerSubclass.hを確認するにはどうすればよいですか?
Sharen Eayrs

5
Appleが内部でどのように行っているかについて指摘してくれてありがとう。私はAppleと同じようにものを実装する方法の完全な例投稿しましたUIGestureRecognizerSubclass.h
Dirty Henry

14

メソッド自体を実装することを要求せずに、保護されたメソッドをサブクラスから見えるようにするために私がやったことは次のとおりです。これは、実装が不完全であることについて、サブクラスでコンパイラの警告を受け取らなかったことを意味します。

SuperClassProtectedMethods.h(プロトコルファイル):

@protocol SuperClassProtectedMethods <NSObject>
- (void) protectMethod:(NSObject *)foo;
@end

@interface SuperClass (ProtectedMethods) < SuperClassProtectedMethods >
@end

SuperClass.m:(コンパイラーは保護されたメソッドを追加するように強制します)

#import "SuperClassProtectedMethods.h"
@implementation SuperClass
- (void) protectedMethod:(NSObject *)foo {}
@end

SubClass.m:

#import "SuperClassProtectedMethods.h"
// Subclass can now call the protected methods, but no external classes importing .h files will be able to see the protected methods.

2
意味は保護されたが、あることができない外部と呼ばれていました。外部から見えるかどうかに関係なく、クラスで定義されているメソッドを呼び出すことができます。
eonil '19

はい、わかりました。この方法は、実際のコンパイル済みコードではなく、人間の脳で機能します。しかし、Objective-Cはそれを許可していません(外部から呼び出すことはできません)。あなたはいつでもperformSelectorそれをすることができます。
Michael Kernahan

1
あなたも行うことができます[(id)obj hiddenMethod]。正確に言うと、Objective-Cでは保護されたメソッドはサポートされていません。
eonil '19

これの問題は、いわゆる保護されたクラスがプロパティを広告できないことです。プロパティが必要ない場合は、保護されたカテゴリを簡単に追加できることは誰でも知っています。
Sharen Eayrs

@eonil: "[(id)obj hiddenMethod]も実行できます。" はい、できますが、そのメソッドが含まれているインターフェイスにない場合は、コンパイラから警告が表示されます。
Kaiserludi 2013年

9

Adamの答えを改善するために、スーパークラスで.mファイルに保護されたメソッドの実装を作成しますが、.hファイルでは宣言しないでください。サブクラスで、スーパークラスの保護されたメソッドの宣言を使用して.mファイルに新しいカテゴリを作成します。サブクラスでスーパークラスの保護されたメソッドを使用できます。これは、実行時に強制された場合、最終的に保護されていると思われるメソッドの呼び出し元を妨げません。

/////// SuperClass.h
@interface SuperClass

@end

/////// SuperClass.m
@implementation SuperClass
- (void) protectedMethod
{}
@end

/////// SubClass.h
@interface SubClass : SuperClass
@end

/////// SubClass.m
@interface SubClass (Protected)
- (void) protectedMethod ;
@end

@implementation SubClass
- (void) callerOfProtectedMethod
{
  [self protectedMethod] ; // this will not generate warning
} 
@end

2
この場合、コンパイラはまだ実装されていないメソッドについて警告をスローしますprotectedMethod
skywinder '21

これは適切な回避策ですが、カテゴリ(保護)を作成する代わりに、拡張を作成できます。
Dharmesh Siddhpura

@skywinder以前のバージョンで行われた可能性がありますが、現在のバージョンのXcodeではこのソリューションに問題はありません。
Darren Ehlers、2017年

2

@protected変数を使用する別の方法。

@interface SuperClass:NSObject{
  @protected
    SEL protectedMehodSelector;
}

- (void) hackIt;
@end

@implementation SuperClass

-(id)init{

self = [super init];
if(self) {
 protectedMethodSelector = @selector(baseHandling);
 }

return self;
}

- (void) baseHandling {

  // execute your code here
}

-(void) hackIt {

  [self performSelector: protectedMethodSelector];
}

@end

@interface SubClass:SuperClass
@end

@implementation SubClass

-(id)init{

self = [super init];
if(self) {
 protectedMethodSelector = @selector(customHandling);
 }

return self;
}

- (void) customHandling {

  // execute your custom code here
}

@end

また、保護されたIVarをprotectedという名前のヘッダーファイルのクラス拡張に配置することもできます
malhal

1

メソッドを親クラスのプライベートメソッドとして定義[super performSelector:@selector(privateMethod)];し、子クラスで使用できます。


0

カテゴリを使用してこれを並べ替えることができます。

@interface SomeClass (Protected)
-(void)doMadProtectedThings;
@end

@implementation SomeClass (Protected)

- (void)doMadProtectedThings{
    NSLog(@"As long as the .h isn't imported into a class of completely different family, these methods will never be seen. You have to import this header into the subclasses of the super instance though.");
}

@end

別のクラスにカテゴリをインポートする場合、メソッドは非表示になりませんが、非表示にすることはありません。Objective-Cの動的な性質により、呼び出し元のインスタンスタイプに関係なく、メソッドを完全に非表示にすることは実際には不可能です。

最善の方法は、おそらく@Brian Westphalが回答したクラス継続カテゴリですが、サブクラス化されたインスタンスごとに、このカテゴリのメソッドを再定義する必要があります。


0

1つのオプションは、クラス拡張を使用することですしてメソッドを非表示にすることです。

.h

@interface SomeAppDelegate : UIResponder <UIApplicationDelegate>

@property (strong, nonatomic) UIWindow *window;

@end

.m

@interface SomeAppDelegate()
- (void)localMethod;
@end

@implementation SomeAppDelegate

- (void)localMethod
{
}

@end

@interface.mファイルの宣言も必要ないと思います。関数を宣言して使用すれば、プライベートとして扱われます。
Russ

1
これはObjective Cの最近の更新にのみ当てはまることに注意してください。それ以前は、インターフェイスでメソッドを宣言する必要がありました。宣言しないと、少なくとも警告が表示されます。
ギヨームローラン

0

私は通常、内部プレフィックスで保護されたメソッドに名前を付けます:

-(void) internalMethod;
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.