2009-08-14 107 views
34

我有一個Obj-C對象,裏面有一堆方法。有時候一個方法需要調用同一個對象內的另一個方法。我似乎無法弄清楚如何讓一個C方法調用對象 - 法...如何從C方法調用Objective-C方法?

WORKS:對象 - 方法調用的對象 - 方法:

[self objCMethod]; 

WORKS:的OBJ-C方法調用C方法:

cMethod(); 

不起作用: C法調用一個OBJ-C方法:

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

最後一個例子使編譯器吐出了這個錯誤:

錯誤:未申報的 '自我'(在一次使用此功能)

兩個問題。爲什麼C函數不能看到「self」變量,即使它在「self」對象內部,我如何在不引起錯誤的情況下調用它?非常感謝您的幫助! :)

回答

47

爲了這一目標的工作,你應該定義的C法是這樣的:

void cMethod(id param); 

,當你調用它,這樣稱呼它:

cMethod(self); 

那麼,你會能寫:

[param objcMethod]; 

在您的cMethod

這是因爲self變量是一個自動傳遞給Objective-C方法的特殊參數。由於C方法不享受這個特權,如果你想使用self,你必須自己發送它。

詳見Method Implementation section of the programming guide

+0

完美,謝謝! – 2009-08-14 21:26:36

+0

不應該「[self objcMethod];」是「[param objcMethod];」 – 2009-08-15 06:02:38

+0

@彼得:當然!固定! :) – 2009-08-15 12:08:20

10

C函數不是「self對象的內部」。事實上,沒有什麼。

Objective-C方法有效地將self作爲一個隱含的參數,在引擎蓋下完成了魔法。對於普通的C函數,它們不與任何類或對象關聯,並且沒有調用魔法,所以沒有self。如果你需要它,你需要將它明確地作爲參數傳遞給你的C函數。

+0

感謝您的解釋。現在更清楚了。 :) – 2009-08-14 21:25:59

4

爲了完全真實,沒有C方法這樣的事情。 C有功能。爲了說明差異,看看下面的例子:

這是一個工作的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中,可以使用類似於方法的東西,但它們實際上只是包含指向結構體的指針的函數。

我不認爲這回答了您的原始問題,但它確實清除了您似乎遇到的一些術語問題。

+1

我很欣賞評論。很有幫助。謝謝! :) – 2009-09-08 14:34:57

+0

沒問題!很高興有幫助... – 2009-09-08 23:07:41

+0

這不回答原來的問題... – 2016-07-28 22:47:40

24

我知道你的問題已經被阿維亞德回答,但只是添加到信息,因爲這是不無關係:

在我來說,我需要調用從我沒有C函數Objective-C的方法調用我自己(通過註冊全局熱鍵事件觸發的碳事件功能),因此將自我作爲參數傳遞是不可能的。在這種特殊情況下,你可以這樣做:

在您的實現定義一個類變量:

id thisClass; 

然後在你的init方法,將其設置爲自:

thisClass = self; 

然後,您可以撥打Objective-C方法來自任何C類函數,無需通過self作爲函數的參數:

void cMethod([some parameters]) { 
    [thisClass thisIsAnObjCMethod]; 
} 
+1

謝謝! :)我實際上遇到了同樣的情況,並做到了這一點。在@interface文件中,我將「id aSelf;」在@interface之前,然後設置「aSelf = self;」在init(或awakeFromNib)中執行@implementation。 – 2009-10-06 19:39:41

+1

你甚至可以從C函數中定義id,因爲它只能訪問標準庫?我可以導入任何特定的Apple庫,允許我在我的C文件中使用'id'嗎? – Micrified 2016-01-28 20:19:30

+0

這不起作用;它會在運行時返回'重複符號'錯誤。 – 2016-07-28 22:43:59

2

到目前爲止給出的答案的另一種選擇是使用Objective-C運行時提供的objc_msgSend()函數。

+0

一般不是一個好主意。調用約定有點神祕。例如,在Apple的運行時,針對不同的返回類型有不同版本的objc_msgSend。更安全的讓編譯器解決這個問題。 – 2009-10-06 20:12:18

+3

您能否提供一個示例,優點或缺點?既然是你,戴夫,我會認爲這是更好的方法之一... – 2015-01-05 13:47:42