web-dev-qa-db-ja.com

Objective-Cでクラスのプライベートメソッドを定義するための最良の方法

私はObjective-Cのプログラミングを始めたばかりで、Javaの経験があるので、Objective-Cプログラムを書いている人がプライベートメソッドをどのように扱うのか疑問に思います。

私はいくつかの慣習や習慣があるかもしれないと理解していて、人々がObjective-Cのプライベートメソッドを扱うのに使う最も良いテクニックのアグリゲータとしてこの質問について考えます。

それを投稿するときあなたのアプローチのための議論を含めてください。どうしていいの?どのような欠点があるのか​​(あなたが知っていること)、そしてどのようにそれらに対処しますか?


私の調査結果はこれまでのところ。

カテゴリ [を使用することは可能です。 MyClass.mファイルでプライベートメソッドをグループ化するために定義されたMyClass(Private)]。

このアプローチには2つの問題があります。

  1. Xcode(およびコンパイラ?)は、対応する@implementationブロック内のプライベートカテゴリ内のすべてのメソッドを定義したかどうかを確認しません。
  2. プライベートカテゴリを宣言している@interfaceをMyClass.mファイルの先頭に配置する必要があります。

最初の問題は 空のカテゴリ [で回避することができます。私のクラス ()]。
2番目のものは私をとても悩ませます。ファイルの終わり近くでプライベートメソッドを実装(および定義)してもらいたいのですが。それが可能かどうかはわかりません。

350
Yurii Soldak

他の人がすでに言ったように、Objective-Cのプライベートメソッドのようなものはありません。ただし、Objective-C 2.0(Mac OS X Leopard、iPhone OS 2.0以降を意味)以降では、Class Extensionという名前の空の名前(つまり@interface MyClass ())でカテゴリを作成できます。クラス拡張のユニークな点は、メソッドの実装はパブリックメソッドと同じ@implementation MyClassで行わなければならないということです。だから私はこのように私のクラスを構成します。

.hファイルでは、

@interface MyClass {
    // My Instance Variables
}

- (void)myPublicMethod;

@end

そして.mファイルで:

@interface MyClass()

- (void)myPrivateMethod;

@end

@implementation MyClass

- (void)myPublicMethod {
    // Implementation goes here
}

- (void)myPrivateMethod {
    // Implementation goes here
}

@end

このアプローチの最大の利点は、メソッド実装を機能ごとにグループ化できることです。パブリック/プライベートの区別ではない場合があります。

433
Alex

私はObjective-Cの専門家ではありませんが、自分のクラスの実装でメソッドを定義するだけです。確かに、それはそれを呼び出すメソッドの前に(上で)定義されていなければなりませんが、それは間違いなく行うべき仕事の最小量を取ります。

37
Andy

プライベートメソッドを@implementationブロックで定義することは、ほとんどの目的に理想的です。 Clangは宣言順に関係なく、これらを@implementation内に表示します。それらをクラス継続(別名クラス拡張)または名前付きカテゴリで宣言する必要はありません。

場合によっては、クラス継続でメソッドを宣言する必要があります(たとえば、クラス継続と@implementationの間のセレクタを使用する場合)。

static関数は、特に機密性が高い、またはスピードが重要なプライベートメソッドに非常に適しています。

接頭辞の命名規則は、プライベートメソッドを誤ってオーバーライドしないようにするのに役立ちます(クラス名は接頭辞として安全です)。

名前付きカテゴリ(例:@interface MONObject (PrivateStuff))は、ロード時に名前が衝突する可能性があるため、特にお勧めできません。それらは、本当に友人や保護されたメソッドにしか役に立ちません(これはめったに良い選択ではありません)。カテゴリの実装が不完全であることを警告するために、実際に実装する必要があります。

@implementation MONObject (PrivateStuff)
...HERE...
@end

これはちょっと注釈付きのチートシートです:

MONObject.h

@interface MONObject : NSObject

// public declaration required for clients' visibility/use.
@property (nonatomic, assign, readwrite) bool publicBool;

// public declaration required for clients' visibility/use.
- (void)publicMethod;

@end

MONObject.m

@interface MONObject ()
@property (nonatomic, assign, readwrite) bool privateBool;

// you can use a convention where the class name prefix is reserved
// for private methods this can reduce accidental overriding:
- (void)MONObject_privateMethod;

@end

// The potentially good thing about functions is that they are truly
// inaccessible; They may not be overridden, accidentally used,
// looked up via the objc runtime, and will often be eliminated from
// backtraces. Unlike methods, they can also be inlined. If unused
// (e.g. diagnostic omitted in release) or every use is inlined,
// they may be removed from the binary:
static void PrivateMethod(MONObject * pObject) {
    pObject.privateBool = true;
}

@implementation MONObject
{
    bool anIvar;
}

static void AnotherPrivateMethod(MONObject * pObject) {
    if (0 == pObject) {
        assert(0 && "invalid parameter");
        return;
    }

    // if declared in the @implementation scope, you *could* access the
    // private ivars directly (although you should rarely do this):
    pObject->anIvar = true;
}

- (void)publicMethod
{
    // declared below -- but clang can see its declaration in this
    // translation:
    [self privateMethod];
}

// no declaration required.
- (void)privateMethod
{
}

- (void)MONObject_privateMethod
{
}

@end

明白ではないかもしれないもう一つのアプローチ:C++型は非常に高速であり、エクスポートされロードされたobjcメソッドの数を最小にしながらはるかに高度な制御を提供することができます。

19
justin

あなたはあなたのインスタンスへのポインタを取るあなたの実装の上下に静的関数を定義することを試みることができます。インスタンス変数にアクセスできます。

//.h file
@interface MyClass : Object
{
    int test;
}
- (void) someMethod: anArg;

@end


//.m file    
@implementation MyClass

static void somePrivateMethod (MyClass *myClass, id anArg)
{
    fprintf (stderr, "MyClass (%d) was passed %p", myClass->test, anArg);
}


- (void) someMethod: (id) anArg
{
    somePrivateMethod (self, anArg);
}

@end
14
dreamlax

あなたはブロックを使うことができますか?

@implementation MyClass

id (^createTheObject)() = ^(){ return [[NSObject alloc] init];};

NSInteger (^addEm)(NSInteger, NSInteger) =
^(NSInteger a, NSInteger b)
{
    return a + b;
};

//public methods, etc.

- (NSObject) thePublicOne
{
    return createTheObject();
}

@end

これは古い質問ですが、この質問に対する答えを探していたときに最初に見つけた質問の1つです。私はこの解決策が他で議論されるのを見たことがないので、これをすることについて何かばかなことがあるかどうか私に知らせてください。

3
FellowMD

objective Cのすべてのオブジェクトは、performSelector:メソッドを保持するNSObjectプロトコルに準拠しています。私は以前、パブリックレベルで公開する必要のない「ヘルパーまたはプライベート」メソッドを作成する方法も探していました。あなたがオーバーヘッドなしであなたのヘッダファイルでそれを定義する必要がないプライベートメソッドを作成したいなら、これに打撃を与える...

下記のコードのようなシグネチャであなたのメソッドを定義してください...

-(void)myHelperMethod: (id) sender{
     // code here...
}

その後、メソッドを参照する必要があるときは、単にセレクタとしてそれを呼び出すだけです。

[self performSelector:@selector(myHelperMethod:)];

このコード行は、作成したメソッドを呼び出しますが、ヘッダーファイルで定義されていないことについての煩わしい警告はありません。

3
Zack Sheppard

先頭の@interfaceブロックを避けたい場合は、プライベート宣言を常に別のファイルに入れることができます。MyClassPrivate.hは理想的ではありませんが、実装が散らかっていません。

MyClass.h

interface MyClass : NSObject {
 @private
  BOOL publicIvar_;
  BOOL privateIvar_;
}

@property (nonatomic, assign) BOOL publicIvar;
//any other public methods. etc
@end

MyClassPrivate.h

@interface MyClass ()

@property (nonatomic, assign) BOOL privateIvar;
//any other private methods etc.
@end

MyClass.m

#import "MyClass.h"
#import "MyClassPrivate.h"
@implementation MyClass

@synthesize privateIvar = privateIvar_;
@synthesize publicIvar = publicIvar_;

@end
2
rebelzach

私がここで言及していないもう一つのこと - Xcodeは名前に "_private"を持つ.hファイルをサポートします。 MyClassというクラスがあるとしましょう - MyClass.mとMyClass.hがあり、そして今度はMyClass_private.hも持つことができます。 Xcodeはこれを認識し、アシスタントエディタの「カウンターパート」のリストに含めます。

//MyClass.m
#import "MyClass.h"
#import "MyClass_private.h"
2
Rich Schonthal

問題#2を回避する方法はありません。それがまさにCコンパイラ(そしてそれゆえObjective-Cコンパイラ)が働く方法です。 XCodeエディタを使用する場合は、関数popupを使用すると、ファイル内の@interfaceブロックと@implementationブロックを簡単にナビゲートできるはずです。

1
Barry Wark

プライベートメソッドがないことの利点があります。隠したいロジックを別のクラスに移動してデリゲートとして使用することができます。この場合、あなたはデリゲートオブジェクトをプライベートとしてマークすることができ、それは外部から見えなくなります。ロジックを別のクラス(おそらく複数)に移動すると、プロジェクトの設計が改善されます。クラスが単純になり、メソッドが適切な名前のクラスにまとめられるようにします。

1
Sneg

他の人々が@implementationブロックでプライベートメソッドを定義することはほとんどの目的のためにOKであると言ったように。

code organization - の話題で、私はXcodeでのナビゲーションを容易にするためにそれらをpragma mark privateの下にまとめておくのが好きです

@implementation MyClass 
// .. public methods

# pragma mark private 
// ...

@end
0
Milan