2011-12-05 10 views
12

Potrzebuję pomocy w debugowaniu mojej klasy. Dostaję błąd tak dziwaczny, że nie mogłem znaleźć czegoś podobnego, więc zamierzam odłożyć większość mojego kodu.Błąd Xcode: Brak znanej metody wprowadzania dla selektora

//Tab.h 
#import <UIKit/UIKit.h> 
@class Tab; 
@protocol TabDelegateDataSource <NSObject> 
@required 
-(void)removeTab:(Tab *)tab; 
@end 

@interface Tab : UIView 
{ 
    id <TabDelegateDataSource> __strong _delegate; 
} 

@property(strong) id <TabDelegateDataSource> delegate; 

-(void)removeTab; 

@end 

// Tab.m 
#import "Tab.h" 
@implementation Tab 
@synthesize delegate = _delegate; 
-(void)removeTab 
{ 
    [self.delegate removeTab:self];//Error here saying: No known instance method for selector 'removeTab:' 
} 

@end 
+1

Z ciekawości, co stałoby się, gdyby zastąpić 'self.delegate' przez' _delegate' na linii naruszającej prawa? – dasblinkenlight

+0

Czy Twój delegat rzeczywiście ma metodę "removeTab"? Ten komunikat o błędzie sugeruje, że tak nie jest. Spróbuj debugowania i sprawdzania self.delegate i upewnij się, że jest to, czego oczekujesz, i że ma metodę 'removeTab'. – WilHall

+1

problem nie występuje w kodzie, który napisałeś. Skopiowałem go do nowego projektu i kompiluje bez błędów i ostrzeżeń. –

Odpowiedz

5

Myślę, że to był głupi problem z Xcode I ponownie uruchomiłem aplikację kilka razy i skończyło się na pracy.

+0

Nie mogę uwierzyć, że ta odpowiedź działa, ale ponownie uruchom Xcode rozwiązał mój problem. Dzięki stary. – PhatHV

4

Należy zawsze sprawdzić delegata w ten sposób, przed wywołaniem metody, nawet z wymaganymi metodami Protokół:

if(self.delegate != nil && [ self.delegate respondsToSelector: @selector(removeTab:) ] 
{ 
    /* Call delegate method... */ 
} 

Robi tak nawet dla wymaganych metod dodaje dodatkowy-bezpieczeństwo, ponieważ kontrola jest wykonane w czasie wykonywania.
Ktoś może zignorować lub wyłączyć ostrzeżenia kompilatora lub oszukać kompilator za pomocą rzutowania typu.

Na przykład:

UILabel * label  = [ [ UILabel alloc ] initWithFrame: CGRectZero ]; 
someTableView.delegate = (id <UITableViewDelegate>)label; 

Ponadto, można użyć performSelector dla rzeczywistej wywołania metody:

[ self.delegate performSelector: @selector(removeTab:) withObject: self ]; 
+6

Nie widzę powodu, dla którego powinno to być konieczne dla metod zdefiniowanych jako wymagane w protokole. Kompilator wyświetli ostrzeżenie, jeśli wymagana metoda nie zostanie zaimplementowana. –

+1

@Macmade Jakie jest uzasadnienie preferowania 'performSelector' nad wywołaniem metody? – zaph

+0

@fluchtpunkt Jest to dodatkowe bezpieczeństwo, więc nie polegasz na ustawieniach kompilatora. Zobacz moją edycję, która wyjaśnia powód sprawdzania w czasie wykonywania. – Macmade

1

Spróbuj zmienić nazwę delegate innym jak delegateForTab.

Twoja klasa Tab jest instacji UIView, więc self.delegate „s self klasa jest podklasą UIView. UIView może mieć własnego pełnomocnika (dziedziczy po UIResponder i głęboko od NSObject) i nie ma metody -(void)removeTab. Tylko moje osobiste przypuszczenie.
Moje rozwiązanie polega na tym, że zmień nazwę na (nie można znaleźć odpowiedzi na pytanie, czy może być jeszcze podklasowana).

Propozycja użyciu delegata: Należy wdrożyć i użyć delegate w innych kontrolerów widoku, w tej samej klasie, które deklarują go nie. :)

+0

Dobra praktyka, ale UIView nie ma delegata. To niestety nie pomoże ...:) – Macmade

+0

@Macmade, dziękuję za radę!Spotkałem się z tym problemem wcześniej: Stworzyłem klasę dziedziczącą z UINavigationController, która spowodowała ten sam błąd i rozwiązałem ją, zmieniając nazwę na 'delegate'. Właśnie teraz odnoszę się do SDK, UIView nie ma swojego delegata, to prawda. :) Jednak dziedziczy po 'UIResponder' i głęboko od' NSObject'. 'NSObject' ma swój protokół i delegata. Myślę więc, że '[self.delegate removeTab: self];' 'self' to po prostu NSObject. Nie jestem pewien, czy to jest prawdziwy powód. Tylko moje osobiste przypuszczenie. : p – Kjuly

0

Ten błąd nie jest błędem kompilatora, prawda? Ponieważ nie mam tutaj błędów kompilatora z twoim kodem.

Więc jeśli to jest błąd wykonania, masz zadeklarowane <TabDelegateDataSource> w swoich klasach delegata takiego:

@interface SomeClass : UIView <TabDelegateDataSource>

Jeśli tak zrobił, kompilator powinien być ostrzeżeniem, jeśli metoda instancji nie może być znalezionym.

A może powinieneś również opublikować kod swojej klasy delegatów, aby uzyskać więcej informacji.

P.S. Delegat nie powinien być __strong. Zamiast tego lepiej użyć numeru __unsafe_unretained.

14

Mogę teraz odtworzyć i naprawić ten błąd do woli.

Upewnij się, że .h nagłówek gdzie to jest zdefiniowane ...

@protocol TabDelegateDataSource <NSObject> 
-(void)removeTab:(Tab *)tab; 
@end 

...jest dołączony do wszędzie tam, gdzie zamierzasz korzystać z delegata, np. gdzieś na górze źródła .m, który zawiera tak:

[self.delegate removeTab:self] 

Jeśli kompilator widział tylko naprzód definicję z TabDelegateDataSource tak:

@protocol TabDelegateDataSource; 

Dostaniesz błąd:

error: no known instance method for selector 'removeTab:' 

a nie bardziej spodziewane definicja naprzód związane błąd

+1

To był mój problem. Nie importowałem nagłówka dla mojego protokołu w tym pliku .h. Dziękuję Panu ! –

0

Importuję plik appdelegate.h i usunięto błąd ...

2

Upewnij się, że nie zgłoszono nieprawidłowo właściwości delegata w interfejsie (prawdopodobnie przez skopiowanie i wklejenie z innego pliku). Na przykład:

@protocol SomeDelegate 

... 

@end 

@interface SomeClass 

... 

@property (nonatomic, retain) id<DifferentDelegate>delegate; 


@end 

Powyższa linia spowoduje „żadna ze znanych metod instancji dla selektora ...” z powodu niezgodności z indtended protokołu, prawdopodobnie błąd skopiować i wkleić. Co więcej, najprawdopodobniej nadpisuje poprawne odniesienie do INNEJ klasy, w której faktycznie należy, z dala od tej linii kodu, co utrudnia dostrzeżenie.

Popraw powyższe deklarując swoją nieruchomość z przeznaczeniem protokołu: Być może potrzebny

@property (nonatomic, retain) id<SomeDelegate>delegate; 
+0

delegaci zawsze powinni być słabi (nigdy nie zatrzymywać/silni) – SamB

0

Ktoś

SEL selector = NSSelectorFromString(@"removeTab"); 

if([self.delegate respondsToSelector:selector]) { 
    objc_msgSend(self.delegate, selector); 
} 

Uwaga: Nie wolno zapomnieć o tym, #import <objc/message.h>

Powiązane problemy