2011-10-27 24 views
5

Tôi muốn thiết lập một cái gì đó như thế này trong môi trường của tôi.Làm thế nào để trampoline từ một thông báo Cocoa để gọi con trỏ chức năng c?

[[NSUserDefaultsController sharedUserDefaultsController] addObserver:self 
    forKeyPath:[@"values." stringByAppendingString: @"MyPreference"] 
    options:NSKeyValueObservingOptionNew 
    context:NULL]; 

Tôi đang làm điều này từ môi trường Smalltalk. Các Smalltalk cụ thể thực sự có thể lái xe ở trên thông qua các tính năng thời gian chạy mục tiêu-c. Vấn đề là "tự" ở đó là đối số addObserver:. Từ Smalltalk, tôi có thể tạo một con trỏ hàm C sẽ hoạt động như một cuộc gọi lại trong Smalltalk. Nhưng nó không thể đưa ra khái niệm về Object là gì đối với môi trường ObjectiveC.

Vì vậy, tôi đang cố gắng tìm hiểu làm thế nào để trampoline từ một số loại đối tượng với API thích hợp gây ra con trỏ hàm tôi tạo ra được thực hiện. Tôi đã xem NSInvokation và bạn bè, nhưng không ai trong số đó được sử dụng để quấn quanh một con trỏ hàm C. Và tôi không chắc chắn họ sẽ dịch các addObserver:forKeyPath:options:context: để làm điều đúng.

Đun sôi câu hỏi là, làm cách nào bạn sử dụng các đối tượng Cocoa hiện có để đăng ký phản hồi cho Thông báo là thực thi con trỏ hàm C mà không biên dịch bất kỳ mã objc mới nào.

Trả lời

2

Bạn sẽ cần phải tạo lớp keo trong Mục tiêu-C. Bạn có thể làm điều này:

typedef void TravisGriggsCallback(); 

@interface TravisGriggsGlue { 
    TravisGriggsCallback *_callback; 
} 
- (id)initWithCallback:(TravisGriggsCallback *)callback; 
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object 
    change:(NSDictionary *)change context:(void *)context 
@end 

@implementation TravisGriggsGlue 

- (id)initWithCallback:(TravisGriggsCallback *)callback 
{ 
    if (!(self = [super init])) 
     return nil; 
    _callback = callback; 
    return self; 
} 

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object 
    change:(NSDictionary *)change context:(void *)context 
{ 
    _callback(); 
} 

@end 

Nếu bạn cần chuyển đối số cho hàm gọi lại, bạn cần phải thêm biến mẫu để giữ đối số và chuyển chúng vào phương thức init.

Sau đó, bạn sử dụng nó như thế này:

TravisGriggsGlue *glue = [[TravisGriggsGlue alloc] 
    initWithCallback:&someCallbackFunction]; 
[[NSUserDefaultsController sharedUserDefaultsController] 
    addObserver:self 
    forKeyPath:[@"values." stringByAppendingString: @"MyPreference"] 
    options:NSKeyValueObservingOptionNew 
    context:NULL]; 
[glue release]; // only needed if not using ARC 
0

sử dụng một đối tượng chức năng đơn giản:

@interface MONFunctor : NSObject 
- (void)performFunction; 
@end 

Sau đó chỉ cần chuyên khi cần thiết:

@interface MONFunctorSpecialization : NSObject 
{ 
@private 
// data, state, arguments for function, function pointer... 
} 
- (void)performFunction; 
@end 

Bạn có thể sử dụng các functor như một người biết lắng nghe, nhưng tôi phác thảo này ra như thể người nghe của bạn sẽ chỉ nói [functor performFunction]; trong gọi lại.

Nhìn lại, không cần MONFunctor làm lớp học; một giao thức sẽ đủ.

+0

Thật không may điều đó không giúp tôi được Justin. Tôi không thể tạo các lớp ObjC mới. Chỉ cần sử dụng những cái hiện có mà thời gian chạy objc sẽ hiển thị. –

+0

@Travis ah! tôi đã không nhận ra đó cũng là hạn chế. – justin

1

Tôi không biết loại Smalltalk bạn đang sử dụng, nhưng trong Pharo/squeak bạn có lẽ sử dụng plugin ObjectiveCBridge. Nếu đúng như vậy, bạn có thể mở rộng một ObjectiveCSqueakProxy và sử dụng nó như một đối tượng được giao từ ca cao cho ứng dụng của bạn.

hy vọng điều này phù hợp với bạn :)

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