2008-11-25 40 views
5

Tôi có một phương thức trong lớp mục tiêu-C. Nó có 2 hàm gọi lại được viết bằng C. Con trỏ lớp tức là self được chuyển đến các hàm này là void *. Trong các hàm C, tôi tạo một con trỏ của lớp kiểu và gán tham số void *. Hàm gọi lại đầu tiên thực thi thành công. Nhưng con trỏ void * trở thành nil trong hàm gọi lại thứ 2. Lưu ý rằng tôi đã không tinh chỉnh con trỏ trong lần gọi lại đầu tiên nhưng tôi vẫn nhận được nil trong lần gọi lại thứ hai.Xử lý cuộc gọi lại

Bất kỳ ý tưởng nào có thể xảy ra sai?

Ví dụ:

kr = IOServiceAddMatchingNotification(gNotifyPort, kIOFirstMatchNotification, 
             matchingDict, RawDeviceAdded, NULL, 
             &gRawAddedIter); 

RawDeviceAdded(NULL, gRawAddedIter, self); 

này hoạt động tốt. Nhưng chức năng bên dưới nhận được selfnil.

kr = IOServiceAddMatchingNotification(gNotifyPort, kIOFirstMatchNotification, 
             matchingDict, BulkTestDeviceAdded, NULL, 
             &gBulkTestAddedIter); 

BulkTestDeviceAdded(NULL, gBulkTestAddedIter, self); 
+0

Sẽ dễ dàng hơn nếu bạn có thể chỉnh sửa để thêm mã hiển thị những gì bạn đang cố gắng làm. –

Trả lời

0

Đây là những gì selector Objective-C là cho: http://developer.apple.com/iphone/library/documentation/Cocoa/Reference/NSInvocationOperation_Class

API không phải là rất trực quan, nhưng tốt của nó một khi bạn hiểu nó

Bạn có thể cần phải làm một số refactoring là tốt, bây giờ có thể có một cách tốt hơn, nhưng khi tôi có vấn đề này giải pháp của tôi là refactor và sử dụng InvoationOperation.

1

Thông thường, các cuộc gọi lại trong Mục tiêu-C được xử lý bằng cách truyền đối tượng ủy nhiệm và bộ chọn để thực hiện trên đại biểu đó. Ví dụ, phương thức này sẽ gọi một phương thức trên đại biểu của nó sau khi đăng nhập một tin nhắn, truyền cả bản thân và thông điệp đã được ghi lại.

- (void)logMessage:(NSString *)message 
      delegate:(id)delegate 
    didLogSelector:(SEL)didLogSelector 
{ 
    NSLog(@"%@", message); 

    if (delegate && didLogSelector && [delegate respondsToSelector:didLogSelector]) { 
     (void) [delegate performSelector:didLogSelector 
           withObject:self 
           withObject:message]; 
    } 
} 

Bạn có thể gọi nó là trong mã như thế này:

- (void)sayHello 
{ 
    [logger logMessage:@"Hello, world" 
       delegate:self 
     didLogSelector:@selector(messageLogger:didLogMessage:)]; 
} 

- (void)messageLogger:(id)logger 
     didLogMessage:(NSString *)message 
{ 
    NSLog(@"Message logger %@ logged message '%@'", logger, message); 
} 

Bạn cũng có thể sử dụng objc_msgSend() trực tiếp thay vào đó, mặc dù bạn cần phải hiểu thời gian chạy Objective-C đủ để chọn biến thể sử dụng và làm thế nào để xây dựng nguyên mẫu và con trỏ hàm để gọi nó. (Đó là cơ chế mà thông điệp gửi được thực sự được thực hiện trong Objective-C - trình biên dịch thường tạo ra các cuộc gọi để biểu diễn các biểu thức [].)

+0

Xin lỗi - trước khi mã được đăng, tôi nghĩ rằng câu hỏi là về cách viết mã thực hiện một hệ thống gọi lại trong Mục tiêu-C, không phải về việc sử dụng các cuộc gọi lại C. –

10

Các vấn đề của bạn có đặc biệt với các thói quen gọi lại IOKit không? Vấn đề với ví dụ cụ thể mà bạn đưa ra là IOServiceMatchingCallback chỉ lấy 2 tham số, không phải 3. Bạn cần hàm gọi lại RawDeviceAdded() và BulkTestDeviceAdded() của bạn để khớp với nguyên mẫu IOServiceMatchingCallback và chấp nhận tự làm tham số đầu tiên (refCon), không thứ 3. Ngoài ra, bạn cần phải tự chuyển sang tham số thứ hai-to-cuối của IOServiceAddMatchingNotification() để chuyển nó trở lại cho bạn bằng cách gọi lại.

Phương pháp phổ biến để xử lý cuộc gọi lại C trong mã Mục tiêu-C là chỉ có một hàm tĩnh chuyển tiếp cuộc gọi lại đến cá thể của bạn. Vì vậy, mã gọi lại mẫu của bạn sẽ trông giống như sau:

static RawDeviceAdded(void* refcon, io_iterator_t iterator) 
{ 
    [(MyClass*)refcon rawDeviceAdded:iterator]; 
} 

@implementation MyClass 
- (void)setupCallbacks 
{ 
    // ... all preceding setup snipped 
    kr = IOServiceAddMatchingNotification(gNotifyPort,kIOFirstMatchNotification, matchingDict,RawDeviceAdded,(void*)self,&gRawAddedIter); 
    // call the callback method once to 'arm' the iterator 
    [self rawDeviceAdded:gRawAddedIterator]; 
} 
- (void)rawDeviceAdded:(io_iterator_t)iterator 
{ 
    // take care of the iterator here, making sure to complete iteration to re-arm it 
} 
@end 
Các vấn đề liên quan