2009-08-28 20 views
35

Có cách nào để tôi có thể chuyển đối số trong bộ chọn không?Các đối số trong @selector

dụ: tôi có phương pháp này

- (void)myMethod:(NSString*)value1 setValue2:(NSString*)value2{ 

} 

và tôi cần phải gọi chức năng này thông qua một selector đi qua hai đối số.

[NSTimer scheduledTimerWithTimeInterval:0.1 target:self selector:@selector(/*my method*/) userInfo:nil repeats:YES]; 

Tôi làm cách nào để thực hiện việc này?

Trả lời

56

Bạn có thể sử dụng phương pháp NSTimer:

+ (NSTimer *)scheduledTimerWithTimeInterval:(NSTimeInterval)seconds 
           invocation:(NSInvocation *)invocation 
            repeats:(BOOL)repeats; 

Thay vào đó, kể từ khi một đối tượng NSInvocation sẽ cho phép bạn để vượt qua đối số; một đối tượng NSInvocation là, như các docs định nghĩa nó:

một Objective-C nhắn render tĩnh, có nghĩa là, nó là một hành động biến thành một đối tượng.

Trong khi tạo một đối tượng NSTimer sử dụng một selector đòi hỏi định dạng của các phương pháp phúc:

- (void)timerFireMethod:(NSTimer*)theTimer 

Một NSInvocation cho phép bạn thiết lập các mục tiêu, chọn, và các đối số mà bạn vượt qua trong:

SEL selector = @selector(myMethod:setValue2:); 

NSMethodSignature *signature = [MyObject instanceMethodSignatureForSelector:selector]; 
NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature]; 
[invocation setSelector:selector]; 

NSString *str1 = @"someString"; 
NSString *str2 = @"someOtherString"; 

//The invocation object must retain its arguments 
[str1 retain]; 
[str2 retain]; 

//Set the arguments 
[invocation setTarget:targetInstance]; 
[invocation setArgument:&str1 atIndex:2]; 
[invocation setArgument:&str2 atIndex:3]; 

[NSTimer scheduledTimerWithTimeInterval:0.1 invocation:invocation repeats:YES]; 

đâu MyObject là lớp học mà myMethod:setValue2: được khai báo và thực hiện trên - instanceMethodSignatureForSelector: là một functi tiện trên tuyên bố trên NSObject trả về một đối tượng NSMethodSignature cho bạn, được chuyển đến NSInvocation.

Ngoài ra, cần lưu ý, với setArgument:atIndex:, các chỉ số cho các đối số được truyền cho phương thức thiết lập như khi bắt đầu công cụ chọn ở chỉ số 2. Từ các tài liệu:

Chỉ số 0 và 1 cho thấy các đối số ẩn tự và _cmd, tương ứng; bạn nên thiết lập các giá trị này trực tiếp với các phương thức setTarget: và setSelector:.Sử dụng các chỉ số 2 và lớn hơn cho các đối số thường được truyền trong một tin nhắn.

+1

Đây là câu trả lời hay hơn tôi. Bạn nên làm điều này để tránh gây ô nhiễm cho việc triển khai của bạn bằng các phương thức không cần thiết. –

+3

Lưu ý rằng, là 'str1' và' str2' không được phân bổ tĩnh, bạn sẽ bị rò rỉ chúng. 'NSTimer' được ghi lại là gửi' -retainArguments' đến đối tượng invocation của nó, nhưng nó sẽ không làm tổn thương cho bạn để gửi '-retainArguments' đến đối tượng invocation. Vấn đề là tự giữ lại các đối số, sau đó nói với lời kêu gọi giữ lại chúng. Không giữ lại đối số lời gọi! Để lời gọi xử lý nó - và, ở đây, để bộ hẹn giờ tự xử lý nó. –

+3

Không mã hóa lớp 'targetInstance', như đã được thực hiện trong việc truy xuất chữ ký phương thức. Nếu bạn thực sự muốn sử dụng '+ instanceMethodSignatureForSelector:', bạn có thể sử dụng '[[targetInstance class] instanceMethodSignatureForSelector: selector]', nhưng điều đó không cần thiết phức tạp - chỉ cần hỏi chính đối tượng đó cho chữ ký phương thức bằng cách sử dụng '[targetInstance methodSignatureForSelector: selector]' . –

-2
@selector(myMethod:setValue2:) 

Kể từ khi cho phương pháp của bạn không chỉ được gọi là myMethod nhưng thay vì myMethod:setValue2:.

Ngoài ra (và tôi có thể tắt cơ sở ở đây), tôi tin rằng về mặt kỹ thuật bạn có thể thả các từ giữa dấu hai chấm và do đó cũng sử dụng @selector(myMethod::) nhưng không báo cho tôi về điều này trừ khi người khác có thể xác nhận.

+2

Điều đó không đúng. Bộ chọn là toàn bộ tên của phương thức, bao gồm tất cả mọi thứ giữa các dấu hai chấm. 'myMethod ::' và 'myMethod: setValue2:' là các bộ chọn riêng biệt, sẽ được liên kết với các triển khai riêng biệt trừ khi bạn đã làm việc một số phép thuật thời gian chạy. –

+0

OK. Tôi đã rời khỏi căn cứ. – jbrennan

27

Đối với scheduledTimerWithTimeInterval:, bộ chọn bạn vượt qua chỉ có thể có một đối số. Hơn nữa, đối số của nó phải là đối tượng NSTimer *. Nói cách khác, bộ chọn phải mang hình thức sau:

- (void)timerFireMethod:(NSTimer*)theTimer 

gì bạn có thể làm là lưu trữ các đối số trong từ điển userInfo và gọi chọn bạn muốn từ giờ gọi lại:

- (void)startMyTimer { 
    /* ... Some stuff ... */ 
    [NSTimer scheduledTimerWithTimeInterval:0.1 
            target:self 
            selector:@selector(callMyMethod:) 
            userInfo:[NSDictionary dictionaryWithObjectsAndKeys:someValue, 
         @"value1", someOtherValue, @"value2", nil] 
            repeats:YES]; 
} 

- (void)callMyMethod:(NSTimer *)theTimer { 
    NSString *value1 = [[theTimer userInfo] objectForKey:@"value1"]; 
    NSString *value2 = [[theTimer userInfo] objectForKey:@"value2"]; 
    [self myMethod:value1 setValue2:value2]; 
} 
+2

Điều này đúng cho phương pháp cụ thể mà bạn đã đăng ở trên isiaatz. Nếu đó chỉ là một ví dụ và bạn muốn biết nói chung làm thế nào để gửi nhiều đối số cho một bộ chọn xin vui lòng sửa đổi câu hỏi của bạn – h4xxr

+0

Tôi thích điều này tốt hơn so với câu trả lời được chấp nhận vì nó ngắn gọn hơn. –

+1

Tôi thích điều này cũng tốt hơn –

2

Trông giống như một công việc cho các khối (giả định này được nhắm mục tiêu cho Snow Leopard.)

-jcr

0

khối có vẻ như một câu trả lời rõ ràng bây giờ ... nhưng có một thành ngữ đó là rất phổ biến trong thời gian chạy cổ điển, dưa luận của bạn trong một đối tượng duy nhất:

- (void)doMyMethod:(NSDictionary *)userInfo 
{ 
    [self myMethod: [userInfo objectForKey:@"value1"] setValue2: [userInfo objectForKey:@"value2"]]; 
} 
- (void)myMethod:(NSString*)value1 setValue2:(NSString*)value2{ 

} 

bây giờ bạn có thể gửi đến

[self performSelector:@selector(doMyMethod:) withObject:@{@"value1":@"value1",@"value2":@"value2"}]; 
Các vấn đề liên quan