web-dev-qa-db-ja.com

CメソッドからObjective-Cメソッドを呼び出す方法は?

たくさんのメソッドを含むObj-Cオブジェクトがあります。メソッドが同じオブジェクト内の別のメソッドを呼び出す必要がある場合があります。 CメソッドでObj-Cメソッドを呼び出す方法がわからないようです...

WORKS: Obj-Cメソッドを呼び出すObj-Cメソッド:

[self objCMethod];

WORKS: Cメソッドを呼び出すObj-Cメソッド:

cMethod();

動作しません: Obj-Cメソッドを呼び出すCメソッド:

[self objCMethod];     // <--- this does not work

最後の例では、コンパイラがこのエラーを吐き出します。

エラー: 'self'が宣言されていません(この関数での最初の使用)

2つの質問。 C関数が「self」オブジェクト内にあるのに「self」変数を認識できないのはなぜですか。エラーを発生させずに呼び出すにはどうすればよいですか。助けてくれてありがとう! :)

39
Dave Gallagher

これを機能させるには、次のようにCメソッドを定義する必要があります。

void cMethod(id param);

あなたがそれを呼ぶとき、それをこのように呼んでください:

cMethod(self);

次に、次のように書くことができます。

[param objcMethod];

cMethodで。

これは、self変数がObjective-Cメソッドに自動的に渡される特別なパラメーターであるためです。 Cメソッドはこの特権を享受しないため、selfを使用する場合は、自分で送信する必要があります。

詳細については、 プログラミングガイドのメソッド実装セクション を参照してください。

50
Aviad Ben Dov

私はあなたの質問がすでにAviadによって答えられていることを知っていますが、これは無関係ではないので情報に追加するだけです:

私の場合、自分で呼び出さなかったC関数(グローバルホットキーイベントの登録によってトリガーされるCarbon Event関数)からObjective-Cメソッドを呼び出す必要があったため、パラメーターとしてselfを渡すことはできませんでした。この特定のケースでは、これを行うことができます:

実装でクラス変数を定義します。

id thisClass;

次に、initメソッドで、selfに設定します。

thisClass = self;

次に、selfをパラメーターとして関数に渡す必要なしに、クラス内の任意のC関数からObjective-Cメソッドを呼び出すことができます。

void cMethod([some parameters]) {
    [thisClass thisIsAnObjCMethod];
}
26
Form

C関数は「selfオブジェクトの内部」ではありません。実際、何もありません。

Objective-Cメソッドは、内部で魔法を使って、暗黙の引数としてselfを効果的に取得します。プレーンC関数の場合、それらはクラスやオブジェクトに関連付けられておらず、呼び出しマジックもないため、selfはありません。必要な場合は、引数として明示的にC関数に渡す必要があります。

10
Pavel Minaev

正直なところ、C法のようなものはありません。 Cには機能があります。違いを説明するために、次の例を見てください。

これは、型とそれに付随する2つの関数を定義する実用的なCプログラムです。

#include <stdio.h>

typedef struct foo_t {
    int age;
    char *name;
} Foo;

void multiply_age_by_factor(int factor, Foo *f) {
    f->age = f->age * factor;
}

void print_foo_description(Foo f) {
    printf("age: %i, name: %s\n", f.age, f.name);
}

int main() {
    Foo jon;
    jon.age = 17;
    jon.name = "Jon Sterling";

    print_foo_description(jon);
    multiply_age_by_factor(2, &jon);
    print_foo_description(jon);

    return 0;
}

そのプログラムのObjective-C実装は次のとおりです。

#import <Foundation/Foundation.h>

@interface Foo : NSObject {
    NSUInteger age;
    NSString *name;
}

@property (nonatomic, readwrite) NSUInteger age;
@property (nonatomic, copy) NSString *name;

- (void)multiplyAgeByFactor:(NSUInteger)factor;
- (NSString *)description;
- (void)logDescription;

@end


@implementation Foo 
@synthesize age;
@synthesize name;

- (void)multiplyAgeByFactor:(NSUInteger)factor {
    [self setAge:([self age] * factor)];
}

- (NSString *)description {
    return [NSString stringWithFormat:@"age: %i, name: %@\n", [self age], [self name]];
}

- (void)logDescription {
    NSLog(@"%@",[self description]);
}

@end


int main (int argc, const char * argv[]) {
    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];

    Foo *jon = [[[Foo alloc] init] autorelease];
    [jon setAge:17];
    [jon setName:@"Jon Sterling"];

    [jon logDescription];
    [jon multiplyAgeByFactor:2];
    [jon logDescription];

    [pool drain];

    return 0;
}

純粋なCプログラムの出力は次のとおりです。

age: 17, name: Jon Sterling
age: 34, name: Jon Sterling

Objective-Cプログラムの出力は次のとおりです。

2009-08-25 17:40:52.818 test[8963:613] age: 17, name: Jon Sterling
2009-08-25 17:40:52.828 test[8963:613] age: 34, name: Jon Sterling

唯一の違いは、NSLogがテキストの前に置くすべてのがらくたです。機能はまったく同じです。したがって、Cでは、メソッドのようなものを使用できますが、実際には、それらは構造体へのポインターを含む単なる関数です。

これがあなたの最初の質問に答えたとは思いませんが、あなたが抱えていたと思われるいくつかの用語の問題を明らかにしました。

5

これまでに与えられた答えに対する別のオプションは、Objective-Cランタイムによって提供される objc_msgSend() 関数を使用することです。

2
Dave DeLong