Làm thế nào để xây dựng một NSArray (hoặc NSMutableArray) của các phương thức lớp trong Objective-C?


14

Tôi đang cố gắng xây dựng một NSArray của các phương thức trong Objective-C.

tôi phải cổng này để Objective-C và tôi không biết làm thế nào để xây dựng một loạt các (giống như sau trong C Những gì tôi đang cố gắng để hoàn thành ở đây là) các con trỏ hàm (trong thế giới Objective-c, lớp) tại thời gian biên dịch.

Trong mục tiêu-C Tôi có những điều sau đây.

- (void)handleCommandA { ... } 
- (void)handleCommandB { ... } 

/* Now how to add above 2 functions into NSArray? */ 
NSArray *handler_table = [NSArray arrayWithObjects:... ]; /* This doesn't seem to work. */ 
5

Sử dụng NSValue.

Ví dụ:

NSArray* handlers = [NSArray arrayWithObjects:[NSValue valueWithPointer:handleA] ... ]; 

sau đó truy cập:

handleptr* handle = (handlerptr*)[[handlers objectAtIndex:0] pointerValue]; 
handle(foo_bar); 

28

Vấn đề ở đây là để ràng buộc các chức năng đó, bạn phải sử dụng từ khóa chọn trả về loại SEL. Đây là kiểu con trỏ trong khi NSArray lưu trữ các đối tượng.

Bạn có ba tùy chọn;

  1. Sử dụng C-type mảng thường xuyên
  2. Gấp các chức năng vào một lớp học có nguồn gốc NSObject rằng sẽ gọi cho họ.
  3. Sử dụng giao thức.

Cách thứ hai có thể đẹp hơn và bạn có thể sử dụng lớp NSValue để giữ kết quả chọn. Ví dụ;

NSValue* selCommandA = [NSValue valueWithPointer:@selector(handleCommandA:)]; 
NSValue* selCommandB = [NSValue valueWithPointer:@selector(handleCommandB:)]; 

NSArray *handler_table = [NSArray arrayWithObjects:selCommandA, selCommandB, nil ]; 

Khi bạn đã truy xuất đúng mục nhập từ mảng, để chuyển đổi lại bạn sẽ làm;

SEL mySelector = [selCommand pointerValue]; 
[someObject performSelector:mySelector]; 

(Lưu ý Tôi giả định rằng từ cú pháp Objective-C của bạn rằng đây là dự định được sử dụng như phương pháp trên một đối tượng và không chức năng toàn cầu. Nếu bạn muốn sử dụng chúng trên toàn cầu thì bạn nên viết chúng như bạn sẽ đồng bằng C.)

Một tùy chọn khác là chính thức hóa các phương thức lệnh thành giao thức. Điều này cho phép bạn viết chức năng sẽ hoạt động trên bất kỳ đối tượng nào thực hiện giao thức đó và trình biên dịch sẽ cung cấp kiểm tra nhiều hơn nếu bạn chỉ gọi các bộ chọn.

Ví dụ:

// some header 
@protocol CommandHandler 
@required 
-(void) handleCommandA; 
-(void) handleCommandB; 
@end 

// some other header 
@interface someClass : NSObject<CommandHandler> 
{ 
// you will receive compiler warnings if you do not implement the protocol functions 
} 

Mã xử lý và công văn của bạn sau đó được viết để làm việc với các đối tượng thuộc loại "CommandHandler". Ví dụ:

-(void) registerForCommands:(CommandHandler*)handler 
  0

Tôi muốn sử dụng chuỗi thay vì con trỏ, vì nó sẽ làm cho gỡ lỗi dễ dàng hơn nhiều. Nhìn vào NSStringFromSelector() và NSSelectorFromString(). 17 may. 092009-05-17 09:10:39

+1

Chỉnh sửa nhỏ, bằng cách sử dụng bộ chọn thực sự trông giống như: [someObject performSelector: mySelector]; 19 jan. 112011-01-19 03:30:33


4

Trong mục tiêu-C, bạn không truyền xung quanh phương pháp; bạn vượt qua các bộ chọn , về cơ bản là các tên phương thức chuẩn. Sau đó, để làm cho một đối tượng phản hồi với một thông báo chọn, bạn gửi nó performSelector:. Ví dụ:

NSString *exampleString = [NSString stringWithString:@"Hello"]; 
SEL methodName = @selector(stringByAppendingString:); 
    // ^This is the selector. Note that it just represents the name of a 
    // message, and doesn't specify any class or implementation 
NSString *combinedString = [exampleString performSelector:methodName withObject:@" world!"]; 

Những gì bạn sẽ muốn là làm cho một mảng của NSStrings chứa tên của các selectors bạn quan tâm Bạn có thể sử dụng chức năng NSStringFromSelector() để làm điều này.. Sau đó, khi bạn muốn sử dụng chúng, hãy gọi NSSelectorFromString() trên các dây để lấy lại bộ chọn gốc và chuyển nó đến đối tượng thích hợp performSelector:.(Như được trình bày trong ví dụ trên, người nhận không được mã hóa trong bộ chọn - chỉ là tên phương thức - vì vậy bạn có thể cần lưu trữ người nhận.)