2009-12-14 29 views
49

mam wsparcie 10.4+ przez wybranie najbardziej aktualny API przy starcie:Pomijanie „«...»jest przestarzała” podczas korzystania respondsToSelector

if ([fileManager respondsToSelector:@selector(removeItemAtPath:error:)]) 
    [fileManager removeItemAtPath:downloadDir error:NULL]; 
else 
    [fileManager removeFileAtPath:downloadDir handler:nil]; 

W tym przypadku, 10,5 i aż użyje removeItemAtPath:error: i 10.4 będzie użyj removeFileAtPath:handler:. Świetnie, ale wciąż otrzymuję ostrzeżenia kompilatora dla starych metod:

warning: 'removeFileAtPath:handler:' is deprecated [-Wdeprecated-declarations] 

istnieje składnia if([… respondsToSelector:@selector(…)]){ … } else { … } że podpowiedzi kompilator (Clang) nie ostrzegać na tej linii?

Jeśli nie, czy istnieje sposób, aby oznaczyć tę linię jako ignorowaną dla -Wdeprecated-declarations?


Po obejrzeniu niektóre odpowiedzi, pozwól mi wyjaśnić, że mylące kompilator do nie wiedząc, co robię, nie jest prawidłowym rozwiązaniem.

Odpowiedz

104

znalazłem an example w Instrukcji Clang kompilator użytkownika, który pozwala mi zignorować ostrzeżenie:

if ([fileManager respondsToSelector:@selector(removeItemAtPath:error:)]) { 
    [fileManager removeItemAtPath:downloadDir error:NULL]; 
} else { 
#pragma clang diagnostic push 
#pragma clang diagnostic ignored "-Wdeprecated-declarations" 
    [fileManager removeFileAtPath:downloadDir handler:nil]; 
#pragma clang diagnostic pop 
} 
+0

Czy możesz po prostu owijać wywołanie w '#pragma clang diagnostic ignored" -Wdeprecated-declaration "', a następnie '#pragma clang warning warning" -Wdeprecated-declaration "' if Clang na OS X nie obsługuje 'push' ? – Wevah

+0

+1 To najlepsze rozwiązanie! – trojanfoe

+0

@ Dziadek czy możesz mi powiedzieć, jak poznać konkretną nazwę ostrzeżenia. To znaczy, pokazuje ostrzeżenie " jest zdeprawowane", ale używamy "-Wdeprecated-deklaracje". Jak znaleźć nazwę atualną, którą musimy użyć w diagnostyce klangów – Johnykutty

8

Można zadeklarować oddzielny plik, który jest przeznaczony do wywoływania przestarzałe metody i ustawić flagi kompilatora per-file w Xcode zignorować -Wdeprecated-declarations. Następnie możesz zdefiniować funkcję fikcyjną w tym pliku, aby wywołać nieaktualne metody, a tym samym uniknąć ostrzeżeń w swoich prawdziwych plikach źródłowych.

+1

Dobry pomysł, zwłaszcza, że ​​dostaje wszystkie nieaktualne wywołania API w jednym miejscu. Przeniosłem kod zgodności do osobnego pliku, dodając metody '-compatibility *' do kategorii w klasach (np. '- [NSFileManager compatibleRemoveItemAtPath:]'). – s4y

6

Nie jestem pewien, czy klang jest na tyle sprytny, aby go złapać, ale jeśli nie, możesz spróbować użyć funkcji performSelector:withObject:withObject: lub zbudować i wywołać obiekt NSInvocation.

+2

performSelector: and kin to poprawne rozwiązanie do wywoływania metod Objective-C w czasie wykonywania, gdy nie masz pewności, czy istnieją. – cdespinosa

5

Można po prostu rzucić fileManager do id - ids są w stanie odnieść się do dowolnego obiektu Objective-C, więc kompilator nie ma sprawdzić metody, które nazywane są na jednym:

[(id)fileManager removeItemAtPath:downloadDir error:NULL]; 

shouldn 't podnieś wszelkie ostrzeżenia lub błędy.

To oczywiście powoduje inne problemy - a mianowicie, tracisz wszystkie sprawdzanie kompilacji pod kątem metod wywoływanych na id. Jeśli więc źle wypiszesz nazwę metody, itd., Nie zostanie ona przechwycona, dopóki ta linia kodu nie zostanie wykonana.

+1

To samo rozwiązanie, ale trochę mniej liberalne można znaleźć tutaj: http://vgable.com/blog/2009/06/15/ignoring-just-one-deprecated-warning/ – MonsieurDart

3

Jeśli uznasz jakąkolwiek formę "zagmatwania" kompilatora za nieprawidłowe rozwiązanie, prawdopodobnie będziesz musiał żyć z ostrzeżeniem. (W mojej książce, jeśli pytasz o to, jak pozbyć się ostrzeżenia, nierozsądnie jest szukać konia z prezentem w ustach i powiedzieć, że coś jest nieważne tylko dlatego, że nie wygląda tak, jak można by się tego spodziewać.)

The odpowiedzi, które działają w środowisku wykonawczym, obejmują maskowanie operacji, która ma miejsce w przypadku dynamicznej wysyłki, aby kompilator nie skarżył się na wycofane połączenie. Jeśli nie podoba ci się to podejście, możesz wyłączyć opcję "Ostrzegaj o przestarzałych funkcjach" w projekcie Xcode lub ustawieniach docelowych, ale generalnie jest to zły pomysł. Chcesz wiedzieć o przestarzałych interfejsach API, ale w tym przypadku chcesz go używać bez ostrzeżenia. Istnieją proste i trudne sposoby na to, a szanse są dla wszystkich "nieprawidłowe" w jakiejś formie, ale to nie przeszkadza im być skuteczne, nawet poprawne.;-)

Jednym z możliwych sposobów, aby uniknąć ostrzeżenia jeszcze wciąż wybierać przy starcie jest użycie objc_msgSend() bezpośrednio:

objc_msgSend(fileManager, @selector(removeFileAtPath:error:), downloadDir, nil]; 

This is what the Objective-C runtime does under the covers anyway i powinna osiągnąć wynik chcesz z minimum zamieszania. Możesz nawet zostawić pierwotną linię skomentowaną powyżej dla jasności. Wiem, że dokumentacja mówi: "Kompilator generuje wywołania funkcji wiadomości, nigdy nie powinieneś wywoływać go bezpośrednio w kodzie, który piszesz." Sam musisz zdecydować, kiedy można zgiąć zasady.

+2

Kod powinien powiedzieć, co to znaczy. Jeśli nie, to interfejs API, język lub programista jest uszkodzony. Jeśli kompilator ostrzega, gdy programista jest przekonany, że jego kod jest poprawny, wówczas kompilator musi dowiedzieć się o tej sytuacji i zignorować go automatycznie lub musi obsługiwać składnię, która pozwala mu zignorować to ostrzeżenie na tej linii (podobnie jak napisana przeze mnie składnia, która nie działa w Clangu dostarczanym z Xcode). Coś jeszcze to hack. – s4y

+2

Pochwalam twój idealizm, ale czasami musisz iść na kompromis. Kod, który napisałem, i że inni też mają, * nie * mówią, co to znaczy. Wierzę, że masz na myśli, że kompilator powinien być w stanie odgadnąć twoje intencje wyłącznie na podstawie kodu, bez przeskakiwania przez obręcze. To miło i wszystko, ale jak zaproponować kompilator powinien wiedzieć, że wywołasz daną metodę tylko w środowisku wykonawczym, gdzie nie jest przestarzała? Bez dodatkowych informacji semantycznych, tak naprawdę nie może. Składnia, która może komunikować takie znaczenie, byłaby fantastyczna, ale dopóki nie istnieje, wywołanie wszystkiego, co jest hakerem, jest bezproduktywne. –

+1

Czasami pisanie kodu, który nie jest wyraźny dla zwykłego obserwatora, jest nieuniknione. To idealny czas na dodanie komentarza wyjaśniającego, jeśli to konieczne. Używanie 'performSelector: withObject: withObject:' lub 'objc_msgSend()' jest minimalnie uciążliwym podejściem, które nadal komunikuje twoje znaczenie i unika ostrzeżenia. Java ma adnotacje, aby tłumić ostrzeżenia, ale C nie. Bummer, ale życie toczy się dalej. Nie bronię obecnego stanu rzeczy tak, jak powinienem, sugerując tylko, że jeśli zamierzasz używać tego języka, bardziej efektywnie jest przyjmować jego dziwactwa niż być elitarnymi. –

Powiązane problemy