Mục tiêu-C: Gọi bộ chọn với nhiều đối số


142

Trong MyClass.m, tôi đã xác định

- (void) myTest: (NSString *) withAString{
    NSLog(@"hi, %@", withAString);
}

và khai báo thích hợp trong MyClass.h. Sau này tôi muốn gọi

[self performSelector:@selector(mytest:withAString:) withObject: mystring];

trong MyClass.m nhưng tôi nhận được một lỗi tương tự như ứng dụng * Ngừng do ngoại lệ còn tự do 'NSInvalidArgumentException', lý do: '* - [MyClass MyTest: withAtring:]: chọn không được công nhận gửi đến dụ 0xe421f0'

Tôi đã thử một trường hợp đơn giản hơn với một bộ chọn mà không có đối số nào in một chuỗi lên bàn điều khiển và nó hoạt động tốt. Có gì sai với mã và làm thế nào tôi có thể sửa nó? Cảm ơn.


4
Bài đăng của bạn đang hỏi về 'nhiều đối số', nhưng bạn chỉ sử dụng một. Bây giờ tôi tò mò về cách ai đó sẽ làm điều đó với nhiều đối số, ngoài việc gói chúng trong một mảng / dict / bất cứ điều gì.
RonLugge

Câu trả lời:


137

Chữ ký phương thức của bạn là:

- (void) myTest:(NSString *)

withAString xảy ra là tham số (tên bị sai lệch, có vẻ như đó là một phần của chữ ký của bộ chọn).

Nếu bạn gọi hàm theo cách này:

[self performSelector:@selector(myTest:) withObject:myString];

Nó sẽ làm việc.

Nhưng, như các áp phích khác đã đề xuất, bạn có thể muốn đổi tên phương thức:

- (void)myTestWithAString:(NSString*)aString;

Và gọi:

[self performSelector:@selector(myTestWithAString:) withObject:myString];

2
Bây giờ tôi thấy mọi người đã được hưởng lợi từ câu trả lời này, tôi đã xem lại phản hồi của mình; Tôi muốn đề xuất rằng cuộc gọi chỉ đơn giản là: - (void) testWithString: (NSString *) aString;
Lyndsey Ferguson

313

Trong Objective-C, chữ ký của bộ chọn bao gồm:

  1. Tên của phương thức (trong trường hợp này là 'myTest') (bắt buộc)
  2. A ':' (dấu hai chấm) theo tên phương thức nếu phương thức có đầu vào.
  3. Tên và ':' cho mỗi đầu vào bổ sung.

Người chọn không có kiến ​​thức về:

  1. Các loại đầu vào
  2. Kiểu trả về của phương thức.

Đây là một triển khai lớp trong đó phương thức PerformanceMethodsViaSelector thực hiện các phương thức lớp khác bằng cách chọn:

@implementation ClassForSelectors
- (void) fooNoInputs {
    NSLog(@"Does nothing");
}
- (void) fooOneIput:(NSString*) first {
    NSLog(@"Logs %@", first);
}
- (void) fooFirstInput:(NSString*) first secondInput:(NSString*) second {
    NSLog(@"Logs %@ then %@", first, second);
}
- (void) performMethodsViaSelectors {
    [self performSelector:@selector(fooNoInputs)];
    [self performSelector:@selector(fooOneInput:) withObject:@"first"];
    [self performSelector:@selector(fooFirstInput:secondInput:) withObject:@"first" withObject:@"second"];
}
@end

Phương thức bạn muốn tạo một bộ chọn cho có một đầu vào duy nhất, vì vậy bạn sẽ tạo một bộ chọn cho nó như sau:

SEL myTestSelector = @selector(myTest:);

3
Câu trả lời tốt. Để làm rõ một chút, tên bộ chọn của bạn PHẢI có ít nhất một phần, có thể có hoặc không có tham số - nếu có, nó phải có dấu hai chấm. Tên bộ chọn có hai hoặc nhiều phần PHẢI có dấu hai chấm sau M EI phần - không hợp pháp khi có bộ chọn có dạng "-useFoo: andBar: toDoSthing".
Quinn Taylor

cảm ơn vì điều đó. Tôi đã vật lộn với điều này trong một thời gian, vui mừng vì sự giúp đỡ!
Hội trường James

Làm thế nào về các tham số đầu vào là số nguyên? Làm gì trong trường hợp này?
Hoàng Phạm

1
Bạn sẽ cần phải bọc số nguyên trong một đối tượng NSNumber (xem developer.apple.com/l Library / ios / # document / Cocoa / Reference / / ) và lấy giá trị số nguyên trong phần thân của phương thức được gọi. Nó có thể là một chút dài dòng (và tôi đã không tìm thấy một cách tốt hơn xung quanh nó) nhưng nó hoạt động tốt.
Shane Arney

30
+100: Điều này thật tuyệt vời! Tôi không biết về việc có thể sử dụng nhiều tham số "withObject:". Tôi sẽ nâng cấp điều này hàng trăm lần nếu tôi có thể ...
FreeAsInBeer

13

@Shane Arney

performSelector:withObject:withObject:

Bạn cũng có thể muốn đề cập rằng phương pháp này chỉ để truyền tối đa 2 đối số và không thể trì hoãn. (chẳng hạn như performSelector:withObject:afterDelay:).

Thật kỳ lạ khi apple chỉ hỗ trợ 2 đối tượng được gửi và không làm cho nó chung chung hơn.


2
Cảm ơn bạn về thông tin. Tôi không thể trì hoãn công việc và bây giờ tôi biết tại sao. FYI, để vượt qua giới hạn của hai đối tượng, tôi đã truyền một mảng và sau đó sử dụng nó trong phương thức.
JScarry

7

Mã của bạn có hai vấn đề. Một người được xác định và trả lời, nhưng người kia thì không. Đầu tiên là bộ chọn của bạn bị thiếu tên của tham số. Tuy nhiên, ngay cả khi bạn sửa lỗi đó, dòng vẫn sẽ đưa ra một ngoại lệ, giả sử chữ ký phương thức sửa đổi của bạn vẫn bao gồm nhiều hơn một đối số. Giả sử phương pháp sửa đổi của bạn được khai báo là:

-(void)myTestWithString:(NSString *)sourceString comparedTo:(NSString *)testString ;

Tạo các bộ chọn cho các phương thức có nhiều đối số là hoàn toàn hợp lệ (ví dụ: @selector (myTestWithString: soTo :)). Tuy nhiên, phương thức PerformanceSelector chỉ cho phép bạn truyền một giá trị cho myTest, không may có nhiều hơn một tham số. Nó sẽ báo lỗi và cho bạn biết rằng bạn đã không cung cấp đủ giá trị.

Bạn luôn có thể xác định lại phương thức của mình để lấy một bộ sưu tập dưới dạng tham số duy nhất:

-(void)myTestWithObjects:(NSDictionary *)testObjects ;

Tuy nhiên, có một giải pháp thanh lịch hơn (không yêu cầu tái cấu trúc). Câu trả lời là sử dụng NSInvocation, cùng với các phương thức setArgument:atIndex:invokephương thức của nó .

Tôi đã viết một bài báo, bao gồm một ví dụ mã , nếu bạn muốn biết thêm chi tiết. Trọng tâm là về luồng, nhưng những điều cơ bản vẫn được áp dụng.

Chúc may mắn!


3

Chữ ký phương thức của bạn không có ý nghĩa, bạn có chắc chắn đó không phải là một lỗi đánh máy? Tôi không rõ làm thế nào nó thậm chí biên dịch, mặc dù có lẽ bạn đang nhận được cảnh báo rằng bạn đang bỏ qua?

Có bao nhiêu tham số bạn mong đợi phương pháp này sẽ mất?


Xin lỗi bạn đang viết. Tôi đã gõ nó ra và cố gắng làm cho nó đơn giản hơn thay vì sao chép và dán mã của tôi nhưng tôi đã mắc lỗi trong quá trình này. Tôi hy vọng phương pháp này sẽ lấy một tham số; chuỗi tôi muốn in.
Stu

2

Hãy nghĩ rằng lớp nên được định nghĩa là:

- (void) myTestWithSomeString:(NSString *) astring{
    NSLog(@"hi, %s", astring);
}

Bạn chỉ có một tham số duy nhất vì vậy bạn chỉ nên có một tham số duy nhất:

Bạn cũng có thể muốn xem xét sử dụng% @ trong NSLog của mình - đó chỉ là một thói quen tốt - sau đó sẽ viết ra bất kỳ đối tượng nào - không chỉ các chuỗi.


-1

Người dùng iOS cũng mong muốn tự động hóa: Trong trường văn bản tiêu chuẩn, chữ cái đầu tiên của câu trong ngôn ngữ phân biệt chữ hoa chữ thường được tự động viết hoa.

Bạn có thể quyết định có thực hiện các tính năng đó hay không; không có API chuyên dụng cho bất kỳ tính năng nào được liệt kê, vì vậy cung cấp chúng là một lợi thế cạnh tranh.

Tài liệu của Apple cho biết không có API khả dụng cho tính năng này và một số tính năng được mong đợi khác trong bảng tùy chỉnh. Vì vậy, bạn cần phải tìm ra logic của riêng bạn để thực hiện điều này.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.