2011-07-20 19 views
5

Poniżej znajduje się fragment z realizacji rzutem sterownika:Zrozumienie Objective-C problem zakres

- (void)myOtherAwesomeMethod 
{ 
    [self myAwesomeMethod]; // Compile ERROR here: Receiver type for instance message does not declare a method with selector 
} 

- (void)myAwesomeMethod 
{ 
    NSLog(@"%@", @"Calling my awesome method..."); 
} 

- (void)viewDidLoad 
{ 
    [self myAwesomeMethod]; 

    [self myOtherAwesomeMethod]; 
} 

nie mam myAwesomeMethod metody zadeklarowane w moim pliku nagłówka, ale dlaczego jest tak, że mogę zadzwonić myAwesomeMethod w viewDidLoad, ale nie w myOtherAwesomeMethod?

Wiem, że rozwiązaniem tego błędu jest zadeklarowanie metody w moim pliku nagłówkowym, ale chciałbym zrozumieć, dlaczego tak się dzieje.

+0

gdzie nazywasz '-myOtherAwesomeMethod'? – vikingosegundo

+1

Uważam, że to tylko ostrzeżenie, a nie błąd? – tia

+0

Również możesz po prostu NSLog ciąg, nie ma potrzeby, aby go sformatować. –

Odpowiedz

11

W języku C reguła jest: należy ją zadeklarować przed jej użyciem.

Pliki są kompilowane od góry do dołu. Oto, co dzieje się w twoim kodzie:

  1. Kompilator odczytuje deklarację @interface dla twojej klasy. Ponieważ mówisz, że żadna metoda nie jest zadeklarowana w pliku nagłówkowym, żadne z nich nie znajduje się jeszcze w tabeli symboli.

    Twój stół symbol zawiera: jeszcze

  2. nic Kompilator odczytuje definicję metody dla myAwesomeMethod. Nie zadeklarowałeś go jeszcze, więc zostanie on dodany do tabeli symboli. Treść tej metody zawiera wywołanie NSLog, które zostało zadeklarowane dawno temu w nagłówku dostarczonym przez Apple.

    Twój stół symbol zawiera: myAwesomeMethod

  3. Kompilator brzmi definicja metody viewDidLoad; zostało zadeklarowane w pliku nagłówkowym nadklasy. Treść metody zawiera wywołanie myAwesomeMethod, które zostało znalezione! Zawiera również wywołanie do myOtherAwesomeMethod. Nigdy nie słyszałem o tym!

    To nie jest błąd, ponieważ nadal może wygenerować kod, aby wykonać połączenie. Może wnioskować o typach argumentów według sposobu ich użycia (w tym przypadku bez argumentów). Nie może jednak być pewny, jaki jest typ zwracany (tylko dlatego, że nie używasz wartości zwracanej, nie oznacza to, że jej nie ma). Tak więc wychodzi z założenia, że ​​wywołanie zwraca id i generuje ostrzeżenie.

    Twój stół symbol zawiera: myAwesomeMethod

  4. Wreszcie, kompilator odczytuje definicję metody dla myOtherAwesomeMethod. Zostaje dodany do tabeli symboli. Kompiluje ciało, które zawiera wywołanie myAwesomeMethod, które znajduje się w tabeli. Wszystko dobre, co się dobrze kończy.

    Na końcu pliku, tabela symbol zawiera: myAwesomeMethod, myOtherAwesomeMethod

Jeśli idziesz z języka takich jak Java, może to wydawać się głupie, ale to dlatego, że Java działa inaczej niż C W języku Java kod źródłowy jest kompilowany i łączony w jednym kroku; nie można skompilować klasy odwołującej się do innej klasy bez posiadania dostępnego kodu źródłowego lub plików klas. To może być uciążliwe, ale z drugiej strony nie potrzebujesz już deklaracji poza definicjami.

W języku C kompilowanie i łączenie są różnymi krokami.Kompilator po prostu generuje kod obiektowy, który odnosi się do symboli, które mogą być zdefiniowane gdzie indziej; używa deklaracji, aby upewnić się, że generuje właściwy kod. Linker jest odpowiedzialny za dopasowanie wszystkich tych symboli do definicji w innych bibliotekach, statycznych lub dynamicznych.

W Objective-C linker nie zna/nie dba o wiadomości Objective-C, ponieważ nie ma sposobu, aby wiedzieć, w czasie kompilacji/łącza, czy obiekt może odpowiedzieć na wiadomość. Tak więc przechodzi on do wersji wykonawczej, która zgłasza wyjątek, jeśli zajdzie tak daleko bez definicji metody.

+0

Dzięki @benzado, dowiedziałem się, że zamówienie jest winowajcą. Nie muszę go nigdzie deklarować, ale definicja metody musi pojawić się zanim zostanie wywołana. W każdym razie akceptuję twoją odpowiedź na niesamowite wyjaśnienie. – pixelfreak

0

Przyznaję, że nie jestem pewien, dlaczego działa w viewDidLoad.

Zauważ, że błąd mówi "nie DECLARE" metody. To wskazówka, że ​​szuka deklaracji (zazwyczaj w nagłówku) .. tj prototyp funkcji.

Jednak nic nie mówi, że deklaracja musi znajdować się w nagłówku. Możesz umieścić go na górze pliku implementacji, jeśli nie chcesz wywoływać tej metody spoza pliku.