2009-08-14 37 views
34

Tôi có một đối tượng Obj-C với một loạt các phương thức bên trong nó. Đôi khi một phương thức cần gọi một phương thức khác bên trong cùng một đối tượng. Tôi dường như không thể tìm ra cách để có được một phương pháp C để gọi một phương thức obj-C ...Làm thế nào để gọi một Phương pháp Mục tiêu-C từ Phương pháp C?

CÔNG TRÌNH: obj-C phương pháp gọi một phương thức obj-C:

[self objCMethod]; 

CÔNG TRÌNH: obj-C phương pháp gọi một phương pháp C:

cMethod(); 

KHÔNG LÀM VIỆC: C phương pháp gọi một phương thức obj-C:

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

Ví dụ cuối cùng gây ra trình biên dịch spits ra lỗi này:

lỗi: 'tự' không khai báo (lần đầu tiên sử dụng chức năng này)

Hai câu hỏi. Tại sao chức năng C không thể nhìn thấy biến "tự" ngay cả khi nó nằm trong đối tượng "tự", và làm cách nào để gọi nó mà không gây ra lỗi? Cảm ơn rất nhiều vì đã giúp đỡ! :)

Trả lời

47

Để cho rằng để làm việc, bạn cần xác định phương pháp C như thế này:

void cMethod(id param); 

và khi bạn gọi nó, gọi nó là như thế này:

cMethod(self); 

sau đó, bạn sẽ được có thể viết:

[param objcMethod]; 

Trong cMethod.

Điều này là do biến số self là một tham số đặc biệt được truyền tự động cho các phương pháp Objective-C. Vì phương thức C không được hưởng đặc quyền này, nếu bạn muốn sử dụng self, bạn phải tự mình gửi.

Xem thêm trong số Method Implementation section of the programming guide.

+0

Hoàn hảo, cảm ơn bạn !!! –

+0

Không nên "[tự objcMethod];" là "[param objcMethod];" –

+0

@Peter: Tất nhiên! Đã sửa! :) –

10

Chức năng C không phải là "bên trong đối tượng self". Trong thực tế, không có gì.

Phương pháp mục tiêu-C có hiệu quả nhận được self làm đối số ẩn, với phép thuật được thực hiện dưới mui xe. Đối với các hàm C thuần túy, chúng không được liên kết với bất kỳ lớp hoặc đối tượng nào và không có phép gọi, vì vậy không có self. Nếu bạn cần nó, bạn cần truyền nó cho hàm C của bạn một cách rõ ràng như một đối số.

+0

Cảm ơn bạn đã giải thích. Rõ ràng hơn nhiều. :) –

4

Hoàn toàn trung thực, không có phương thức nào như phương pháp C. C có chức năng.Để minh họa sự khác biệt, nhìn vào các ví dụ sau:

Đây là một chương trình làm việc C định nghĩa một kiểu và hai chức năng mà đi cùng với nó:

#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; 
} 

Đây là một thực hiện Objective-C đó chương trình:

#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; 
} 

Đầu ra của chương trình C tinh khiết là:

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

Đầu ra của chương trình Objective-C là:

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 

Sự khác biệt duy nhất là tất cả các rác mà NSLog đặt trước văn bản. Các chức năng là chính xác như nhau. Vì vậy, trong C, bạn có thể sử dụng một cái gì đó loại giống như phương pháp, nhưng họ thực sự chỉ là chức năng bao gồm một con trỏ đến một cấu trúc.

Tôi không nghĩ rằng điều này đã trả lời câu hỏi ban đầu của bạn, nhưng nó đã làm sáng tỏ một số vấn đề về thuật ngữ mà bạn dường như đang gặp phải.

+1

Tôi đánh giá cao nhận xét. Rất hữu ích. Cảm ơn! :) –

+0

Không sao cả! Vui mừng được giúp đỡ ... –

+0

Điều này không trả lời được câu hỏi gốc ... –

24

Tôi biết câu hỏi của bạn đã được trả lời bằng cách Aviad nhưng chỉ để thêm vào các thông tin vì đây không phải là không liên quan:

Trong trường hợp của tôi, tôi cần thiết để gọi một phương pháp Objective-C từ một hàm C mà tôi đã không gọi bản thân mình (một chức năng Carbon Event được kích hoạt bằng cách đăng ký một sự kiện hotkey toàn cầu) để tự chuyển mình như một tham số là không thể. Trong trường hợp này bạn có thể làm điều này:

Định nghĩa một biến lớp học trong việc thực hiện của bạn:

id thisClass; 

Sau đó, trong phương pháp init của bạn, thiết lập nó để tự:

thisClass = self; 

Sau đó bạn có thể gọi Các phương thức C mục tiêu từ bất kỳ hàm C nào trong lớp mà không cần phải chuyển self làm tham số cho hàm:

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

Cảm ơn! :) Tôi thực sự chạy vào tình huống tương tự và đã làm điều đó. Trong tệp @interface, tôi đặt "id aSelf;" trước @interface, và sau đó đặt "aSelf = self;" trong init (hoặc awakeFromNib) cho @implementation. –

+1

Làm thế nào để bạn thậm chí xác định id từ một hàm C, vì nó chỉ có quyền truy cập vào lib chuẩn? Tôi có thể nhập bất kỳ thư viện Apple cụ thể nào cho phép tôi sử dụng 'id' trong tệp C của mình không? – Micrified

+0

Điều này không hoạt động; nó trả về lỗi 'biểu tượng trùng lặp' khi chạy. –

2

Một tùy chọn khác cho các câu trả lời được đưa ra cho đến nay là sử dụng hàm objc_msgSend() do thời gian chạy Objective-C cung cấp.

+0

Nói chung không phải là một ý tưởng tuyệt vời. Các quy ước gọi là một chút phức tạp. Trong thời gian chạy của Apple, có các phiên bản khác nhau của objc_msgGửi cho các kiểu trả về khác nhau, ví dụ. An toàn hơn để cho trình biên dịch tìm ra điều này. –

+3

Bạn có thể cung cấp một ví dụ, ưu điểm hay nhược điểm không? Vì đó là bạn, Dave, tôi sẽ giả định đây là một trong những cách tốt hơn để đi ... –

Các vấn đề liên quan