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ę.

vodkhang
źródło
W moim ostatnim iPhoneprojekcie zrobiłem to ręcznie. Chciałbym zobaczyć odpowiedź na to pytanie.
Jacob Relkin
Możliwy duplikat: stackoverflow.com/questions/969130/…
erkanyildiz

Odpowiedzi:

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

Swift 3 i nowsze

print(#function)
ciągnięty do przodu
źródło
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__);
Dave DeLong
źródło
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.

Basil Bourque
źródło
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
Huynh Inc
źródło
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

Albert Renshaw
źródło
0

W Swift 4:

func test () {

print(#function)

}

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

Ankit garg
źródło