Objective-C: Birden çok argümana sahip çağrı seçiciler


142

MyClass.m'de,

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

ve MyClass.h dosyasındaki uygun bildirimi. Daha sonra aramak istiyorum

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

Ancak benzer bir hata alıyorum * NSInvalidArgumentException 'yakalanmamış istisna nedeniyle uygulamayı sonlandırma, nedeni:' * - [Sınıfım myTest: withAtring:]: tanınmayan seçici 0xe421f0 örneğine gönderildi '

Konsola bir dize yazdırdı ve sadece iyi çalıştı hiçbir argüman aldı bir seçici ile daha basit bir dava denedim. Koddaki sorun nedir ve nasıl düzeltebilirim? Teşekkürler.


4
Gönderiniz 'birden fazla argüman' soruyor, ancak yalnızca bir tane kullanıyorsunuz. Şimdi birisinin bunu bir dizi / dict / neyse içine almak dışında, birden fazla argümanla nasıl yapabileceğini merak ediyorum.
RonLugge

Yanıtlar:


137

Yöntem imzanız:

- (void) myTest:(NSString *)

withAString parametre olur (ad yanıltıcıdır, seçicinin imzasının bir parçası gibi görünüyor).

İşlevi bu şekilde çağırırsanız:

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

Çalışacak.

Ancak, diğer posterlerin önerdiği gibi, yöntemi yeniden adlandırmak isteyebilirsiniz:

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

Ve Çağrı yap:

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

2
Artık insanların bu cevaptan yararlandığını gördüğüme göre, yanıtımı inceledim; Çağrı basitçe öneririm: - (void) testWithString: (NSString *) aString;
Lyndsey Ferguson

313

Objective-C'de bir seçicinin imzası aşağıdakilerden oluşur:

  1. Yöntemin adı (bu durumda 'myTest' olur) (gerekli)
  2. Yöntemin bir girdisi varsa yöntem adını izleyen bir ':' (iki nokta üst üste).
  3. Her ek giriş için bir ad ve ':'.

Seçicilerin bilgisi yoktur:

  1. Giriş türleri
  2. Yöntemin dönüş türü.

PerformMethodsViaSelectors yönteminin seçiciler yoluyla diğer sınıf yöntemlerini gerçekleştirdiği bir sınıf uygulaması:

@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

Bir seçici oluşturmak istediğiniz yöntemin tek bir girişi vardır, bu nedenle bunun için bir seçici oluşturacaksınız:

SEL myTestSelector = @selector(myTest:);

3
İyi cevap. Biraz açıklığa kavuşturmak için, seçici adınızın en az bir parçası olması gerekir; bu parametre alabilir veya almayabilir - eğer varsa, iki nokta üst üste olması gerekir. İki veya daha fazla parçalı seçici adlarının HER bölümden sonra iki nokta üst üste OLMALIDIR - "-useFoo: andBar: toDoSomething" biçiminde bir seçici olması yasal değildir.
Quinn Taylor

Bunun için teşekkürler. ive bir süredir bunun için mücadele ediyorum, yardım için sevindim!
James Hall

giriş parametreleri tamsayı sayılarından ne haber? bu durumda ne yapmalı?
Hoang Pham

1
Tamsayıyı bir NSNumber nesnesine sarmanız gerekir (bkz. Developer.apple.com/library/ios/#documentation/Cocoa/Reference/… ) ve çağrılan yöntemin gövdesindeki tam sayı değerini almanız gerekir . Biraz ayrıntılı olabilir (ve çevresinde daha iyi bir yol bulamadım) ama iyi çalışıyor.
Shane Arney

30
+100: Harika! Birden çok "withObject:" parametresi kullanabilmek hakkında bilmiyordum. Eđer yapabilseydim bunu yüz kere
vurabilirdim

13

@Shane Arney

performSelector:withObject:withObject:

Ayrıca, bu yöntemin yalnızca en fazla 2 argüman iletmek olduğunu ve geciktirilemeyeceğini belirtmek isteyebilirsiniz. (gibi performSelector:withObject:afterDelay:).

Apple sadece gönderilecek 2 nesneyi destekliyor ve daha genel hale getirmiyor.


2
Bilgi için teşekkürler. Çalışmayı geciktiremedim ve şimdi nedenini biliyorum. FYI, iki nesnenin sınırını aşmak için bir dizi geçtim ve yöntemde kullandım.
JScarry

7

Kodunuzun iki sorunu vardır. Biri tanımlandı ve cevaplandı, ama diğeri olmadı. Birincisi, seçicinizde parametresinin adı eksikti. Bununla birlikte, bunu düzelttiğinizde bile, revize edilmiş yöntem imzanızın hala birden fazla argüman içerdiği varsayılarak, satır yine de bir istisna oluşturacaktır. Gözden geçirilmiş yönteminizin şu şekilde beyan edildiğini varsayalım:

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

Birden çok argüman alan yöntemler için seçiciler oluşturmak tamamen geçerlidir (örn. @Selector (myTestWithString: comparTo :)). Ancak performSelector yöntemi, maalesef birden fazla parametreye sahip olan myTest'e yalnızca bir değer iletmenize izin verir. Hata verecek ve size yeterli değer sağlamadığınızı söyleyecektir.

Bir koleksiyonu almak için yönteminizi her zaman parametresi olarak yeniden tanımlayabilirsiniz:

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

Bununla birlikte, daha zarif bir çözüm var (bu yeniden düzenleme gerektirmiyor). Cevap NSInvocation'ı setArgument:atIndex:ve invokeyöntemleriyle birlikte kullanmaktır .

Daha fazla ayrıntı istiyorsanız, bir kod örneği de dahil olmak üzere bir makale yazdım . Odak diş çekme üzerinedir, ancak temeller hala geçerlidir.

İyi şanslar!


3

Yöntem imzanızın bir anlamı yok, bunun bir yazım hatası olmadığından emin misiniz? Nasıl derlendiğini net değilim, ama belki de görmezden geldiğine dair uyarılar alıyorsun?

Bu yöntemin kaç parametre almasını bekliyorsunuz?


Üzgünüm yazıyorsunuz. Bunu yazdım ve kodumu kopyalayıp yapıştırmak yerine basitleştirmeye çalıştım ama süreçte bir hata yaptım. Bir parametre almak için bu yöntemi bekliyorum; yazdırmak istediğim dize.
Stu

2

Sınıfın şu şekilde tanımlanması gerektiğini düşünün:

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

Yalnızca tek bir parametreniz olduğundan tek bir parametreniz olmalıdır:

NSLog'unuzda% @ kullanmayı da düşünebilirsiniz - bu sadece içine girmek için iyi bir alışkanlıktır - daha sonra herhangi bir nesneyi yazacaktır - sadece dizeleri değil.


-1

iOS kullanıcıları ayrıca otomatik büyük harf kullanımı bekler: Standart bir metin alanında, büyük / küçük harfe duyarlı bir dildeki bir cümlenin ilk harfi otomatik olarak büyük harfle yazılır.

Bu tür özelliklerin uygulanıp uygulanmayacağına karar verebilirsiniz; listelenen özelliklerin hiçbiri için özel bir API yoktur, bu nedenle bunları sağlamak rekabetçi bir avantajdır.

Apple dokümanı, bu özellik ve özel klavyede beklenen diğer bazı özellikler için kullanılabilir API olmadığını söylüyor. bu yüzden bunu uygulamak için kendi mantığınızı bulmanız gerekir.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.