NSLoguj nazwę metody za pomocą Objective-C w telefonie iPhone


153

Obecnie sami definiujemy rozszerzony mechanizm dziennika, aby wydrukować nazwę klasy i numer linii źródłowej dziennika.

#define NCLog(s, ...) NSLog(@"<%@:%d> %@", [[NSString stringWithUTF8String:__FILE__] lastPathComponent], \
    __LINE__, [NSString stringWithFormat:(s), ##__VA_ARGS__])

Na przykład, kiedy dzwonię do NCLog (@ "Hello world"); Wynik będzie:

<ApplicationDelegate:10>Hello world

Teraz chcę również wylogować się z nazwy metody, takiej jak:

<ApplicationDelegate:applicationDidFinishLaunching:10>Hello world

Dzięki temu nasze debugowanie stanie się łatwiejsze, gdy będziemy wiedzieć, która metoda jest wywoływana. Wiem, że mamy również debugger Xcode, ale czasami chcę również debugować, wylogowując się.


W moim ostatnim iPhoneprojekcie zrobiłem to ręcznie. Chciałbym zobaczyć odpowiedź na to pytanie.
Jacob Relkin

Odpowiedzi:


261
print(__FUNCTION__) // Swift
NSLog(@"%@", NSStringFromSelector(_cmd)); // Objective-C

Swift 3 i nowsze

print(#function)

120
Naprawdę powinieneś użyć NSLog(@"%@", NSStringFromSelector(_cmd)), jeśli zamierzasz używać _cmd, ponieważ AFAIK Apple deklaruje _cmdjako typ SEL, a nie ciąg znaków C. To, że zdarzyło się, że jest zaimplementowany jako ciąg C (w obecnych wersjach Mac OS X i iPhone OS), nie oznacza, że ​​powinieneś go używać w ten sposób, ponieważ Apple może to zmienić w aktualizacji systemu operacyjnego.
Nick Forge

5
Tak, NSStringFromSelector jest bardziej poprawną odpowiedzią. Nigdy nie używam _cmd jako ciągu c do niczego poza kodem debugowania.
wyciągnięty

Wow, kompilator skarży się na niekompatybilność wskaźnika, ale działa ... Więc _cmd (typ: SEL) naprawdę jest char *!?
Nicolas Miari

3
Metoda nazywa się jak [self doSomething:arg1 somethingElse:arg2]get konwertowane do wywołania funkcji C objc_msgSend(self, "doSomething:somethingElse:, arg1, arg2);. Drugi parametr objc_msgSend()zajmuje a char*. Pamiętaj, że ponieważ środowisko wykonawcze Objective-C jest dynamiczne, w rzeczywistości używa tabeli odnośników, aby dowiedzieć się, którą metodę wywołać, dlatego znak * jest wygodny, ponieważ metody są reprezentowane jako łańcuchy w tabeli odnośników.
Jack Lawrence,

1
Dla Swift 2.2 należy użyćprint("\(#function)")
Jake Lin

161

Aby technicznie odpowiedzieć na swoje pytanie, chcesz:

NSLog(@"<%@:%@:%d>", NSStringFromClass([self class]), NSStringFromSelector(_cmd), __LINE__);

Możesz też zrobić:

NSLog(@"%s", __PRETTY_FUNCTION__);

2
With __FUNCTION__i jego całkiem odpowiednik są również dostępne w funkcjach C.
Georg Fritzsche

Uwaga: __FUNCTION__zawiera również nazwę klasy
OrangeDog

1
czy jest jakaś różnica w używaniu NSLog (@ "% s", _func_ ); OR NSLog (@ "% s", _PRETTY_FUNCTION_ ) ???
Ravi,

83

tl; dr

NSLog( @"ERROR %@ METHOD %s:%d ", @"DescriptionGoesHere", __func__, __LINE__ );

Detale

Firma Apple ma stronę z technicznymi pytaniami i odpowiedziami: QA1669 - Jak mogę dodać informacje kontekstowe - takie jak bieżąca metoda lub numer wiersza - do moich wyciągów logowania?

Aby pomóc w logowaniu:

  • Preprocesor C udostępnia kilka makr .
  • Objective-C zapewnia wyrażenia (metody).
    • Przekaż niejawny argument dla selektora bieżącej metody:_cmd

Jak wskazały inne odpowiedzi, aby uzyskać tylko nazwę bieżącej metody, zadzwoń:

NSStringFromSelector(_cmd)

Aby uzyskać aktualną nazwę metody i numer bieżącego wiersza, użyj tych dwóch makr __func__i __LINE__jak widać tutaj:

NSLog(@"%s:%d someObject=%@", __func__, __LINE__, someObject);

Kolejny przykład… Fragmenty kodu, które trzymam w bibliotece fragmentów kodu Xcode:

NSLog( @"ERROR %@ METHOD %s:%d ", @"DescriptionGoesHere", __func__, __LINE__ );

… I TRACE zamiast ERROR…

NSLog( @"TRACE %@ METHOD %s:%d ", @"DescriptionGoesHere", __func__, __LINE__ );

… I dłuższy, wykorzystujący miękki opis z przekazaniem wartości ( [rows count])…

NSLog( @"TRACE %@ METHOD %s:%d.", [NSString stringWithFormat:@"'Table of Contents.txt' file's count of Linefeed-delimited rows: %u.", [rows count]] , __func__, __LINE__ );

Makra preprocesora do rejestrowania

Zwróć uwagę na użycie pary znaków podkreślenia po obu stronach makra.

| Makro | Format | Opis
  __func__% s Aktualna sygnatura funkcji
  __LINE__% d Aktualny numer linii
  __FILE__% s Pełna ścieżka do pliku źródłowego
  __PRETTY_FUNCTION__% s Podobnie jak __func__, ale zawiera szczegółowe informacje
                                    wpisz informacje w kodzie C ++. 

Wyrażenia do logowania

| Wyrażenie | Format | Opis
  NSStringFromSelector (_cmd)% @ Nazwa bieżącego selektora
  NSStringFromClass ([klasa własna])% @ Nazwa klasy bieżącego obiektu
  [[NSString% @ Nazwa pliku kodu źródłowego
    stringWithUTF8String: __ FILE__]   
    lastPathComponent] 
  [NSThread callStackSymbols]% @ NSArray śledzenia stosu

Struktury rejestrowania

Niektóre struktury rejestrowania mogą również pomóc w uzyskaniu aktualnej metody lub numeru linii. Nie jestem pewien, ponieważ korzystałem ze świetnego mechanizmu rejestrowania w Javie ( SLF4J + LogBack ), ale nie w Cocoa.

Zobacz to pytanie, aby uzyskać linki do różnych struktur rejestrowania Cocoa.

Nazwa selektora

Jeśli masz zmienną selektora ( SEL ), możesz wydrukować nazwę jej metody („komunikat”) na dwa sposoby, jak opisano w tym poście na blogu Codec :

  • Używanie wywołania Objective-C do NSStringFromSelector :
    NSLog(@"%@", NSStringFromSelector(selector) );
  • Używając prostego C:
    NSLog(@"%s", selector );

Te informacje pochodzą z połączonej strony dokumentów Apple z dnia 19.07.2013 r. Ta strona była ostatnio aktualizowana 2011-10-04.


1
W przypadku C użyj, sel_getName(SEL)ponieważ SEL jest typem nieprzezroczystym i nie zawsze może byćchar *
Ethan Reesor

8
NSLog(@"%@", NSStringFromSelector(_cmd)); // Objective-C
print(__FUNCTION__) // Swift

4
Dla każdego, kto spotka się z tą odpowiedzią w przyszłości: jest ona równoważna z zaakceptowaną odpowiedzią, ale zaakceptowana odpowiedź była inna, gdy ta została opublikowana (zaakceptowana odpowiedź została zredagowana w 2014 roku). Miałem zamiar oddać głos, ale zamiast tego po małym dochodzeniu głosowałem
pozytywnie

0

W rzeczywistości jest to tak proste, jak:

printf(_cmd);

Z jakiegoś powodu iOS pozwala na przekazywanie _cmd jako dosłownego znaku bez nawet ostrzeżenia o kompilacji. Kto wie


0

W Swift 4:

func test () {

print(#function)

}

test () // wydrukuj wartość "test ()"

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.