2009-06-19 37 views
135

在MyClass.m,我定義的Objective-C:選擇調用使用多個參數

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

和MyClass.h相應的聲明。後來我想打電話給

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

在MyClass.m,但我得到類似 *終止應用程序錯誤,由於未捕獲的異常 'NSInvalidArgumentException',原因是:「* - [MyClass的MYTEST:withAtring:]:無法識別的選擇發送到實例0xe421f0'

我試圖更簡單的情況下,選擇器沒有任何參數,打印到控制檯的字符串,並且工作得很好。代碼有什麼問題,我該如何解決它?謝謝。

+4

你的帖子詢問'多個參數',但你只使用一個。現在我很好奇某人會怎樣用多個參數來做這件事,除了把它們封裝在一個數組/字典/任何東西之外。 – RonLugge 2012-03-12 00:24:45

回答

130

你的方法簽名是:

- (void) myTest:(NSString *) 

withAString恰好是參數(名稱是誤導性的,它看起來像它是選擇簽名的一部分)。

如果你調用這樣的功能:

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

它將工作。

但是,正如其他海報建議,您可能要重命名的方法:

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

而且撥打:

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

謝謝! 微調。 「mytest:」中的「t」應該大寫爲「T」。 self performSelector:@selector(mytest :) withObject:myString]; – Stu 2009-06-19 16:38:02

+0

謝謝,更新了我的文章:) – 2009-06-19 16:39:44

+1

現在我看到有人從這個答案中受益,我已經回顧了我的回答;我建議這個調用很簡單: - (void)testWithString:(NSString *)aString; – 2012-03-12 12:46:40

2

想想類應定義爲:

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

你只有一個參數,所以你應該只有一個:

你可能要考慮在你的NSLog還使用%@ - 這只是一個好習慣 - 然後寫出任何對象 - 而不僅僅是字符串。

3

您的方法簽名毫無意義,您確定它不是拼寫錯誤嗎?我不清楚它是如何編譯的,雖然也許你得到了你忽略的警告?

您預計此方法需要多少個參數?

+0

對不起,你正在寫。我輸入它並試圖使它更簡單,而不是複製和粘貼我的代碼,但我在這個過程中犯了一個錯誤。 我期待這種方法採取一個參數;我想打印的字符串。 – Stu 2009-06-19 14:28:53

297

在Objective-C,選擇的簽名包括:

  1. 的方法的名稱(在此情況下,將「MYTEST」)(必需)
  2. 如果方法有輸入,則在方法名稱後面有一個':'(冒號)。
  3. 名稱和':'爲每個額外的輸入。

選擇器沒有的知識:

  1. 輸入類型
  2. 方法的返回類型。

這裏是一個類的實現,其中performMethodsViaSelectors方法,通過選擇的方式執行其他類中的方法:

@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 

你想創建一個選擇器有一個單一的輸入,所以你會創建一個選擇的方法因爲它是這樣的:

SEL myTestSelector = @selector(myTest:); 
7

你的代碼有兩個問題。一個被確認並回答,但另一個不是。首先是你的選擇器缺少參數的名字。然而,即使你修正了這個問題,假設你的修改後的方法簽名仍然包含多個參數,那麼該行仍然會引發異常。比方說,修改後的方法聲明爲:

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

創建多個參數的方法選擇是完全有效的(例如@selector(myTestWithString:comparedTo :))。然而,performSelector方法只允許你傳遞一個值給myTest,不幸的是它有多個參數。它會錯誤地告訴你,你沒有提供足夠的值。

你總是可以重新定義你的方法採取集合,因爲它是唯一的參數:

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

但是,還有一個更優雅的解決方案(不需要重構)。答案是使用NSInvocation以及其setArgument:atIndex:invoke方法。

我寫了an article, including a code example,如果你想了解更多的細節。重點在於線程,但基礎仍然適用。

祝你好運!

13

@Shane Arney

performSelector:withObject:withObject: 

您可能還需要一提的是此方法僅適用於通過最多2個參數,它不能拖延。 (如performSelector:withObject:afterDelay:)

有點奇怪,蘋果只支持2個對象被髮送,並沒有使其更通用

0

iOS用戶也期望autocapitalization:在一個標準的文本字段, 第一字母在區分大小寫的語言的句子是 自動大寫

您可以決定是否要實現這樣的功能;有任何的剛剛上市的功能沒有 專用API,所以爲他們提供 是一種競爭優勢。

Apple文檔說這個功能和自定義鍵盤中沒有其他預期的功能。所以你需要找出你自己的邏輯來實現這一點。