NSLog nama metode dengan Objective-C di iPhone

153

Saat ini, kami mendefinisikan diri kami mekanisme log yang diperluas untuk mencetak nama kelas dan nomor baris sumber log.

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

Misalnya, ketika saya memanggil NCLog (@ "Hello world"); Outputnya adalah:

<ApplicationDelegate:10>Hello world

Sekarang saya juga ingin keluar nama metode seperti:

<ApplicationDelegate:applicationDidFinishLaunching:10>Hello world

Jadi, ini akan membuat proses debug kita menjadi lebih mudah ketika kita dapat mengetahui metode mana yang dipanggil. Saya tahu bahwa kami juga memiliki debugger Xcode tetapi terkadang, saya juga ingin melakukan debugging dengan logout.

vodkhang
sumber
Dalam iPhoneproyek terakhir saya , saya benar-benar melakukan ini secara manual. Senang melihat jawaban untuk ini.
Jacob Relkin
Kemungkinan rangkap: stackoverflow.com/questions/969130/…
erkanyildiz

Jawaban:

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

Cepat 3 dan lebih tinggi

print(#function)
ditarik ke depan
sumber
120
Anda benar-benar harus menggunakan NSLog(@"%@", NSStringFromSelector(_cmd)), jika Anda akan menggunakan _cmd, karena AFAIK Apple mendeklarasikan _cmdsebagai tipe SEL, bukan C-string. Hanya karena kebetulan diterapkan sebagai string-C (pada versi Mac OS X dan iPhone OS saat ini) tidak berarti Anda harus menggunakannya dengan cara itu, karena Apple dapat mengubahnya dalam pembaruan OS.
Nick Forge
5
Ya, NSStringFromSelector adalah jawaban yang lebih benar. Saya tidak pernah menggunakan _cmd sebagai c string untuk apa pun kecuali kode debug.
ditarik
Wow, kompiler mengeluh tentang ketidakcocokan pointer, tetapi berfungsi ... Jadi _cmd (ketik: SEL) benar-benar adalah char *!?
Nicolas Miari
3
Metode panggilan seperti [self doSomething:arg1 somethingElse:arg2]get diubah menjadi panggilan fungsi C objc_msgSend(self, "doSomething:somethingElse:, arg1, arg2);. Parameter kedua dari objc_msgSend()a char*. Ingatlah bahwa karena runtime Objective-C adalah dinamis, itu sebenarnya menggunakan tabel pencarian untuk mengetahui metode yang memanggil kelas sehingga char * nyaman karena metode direpresentasikan sebagai string dalam tabel pencarian.
Jack Lawrence
1
Untuk Swift 2.2 harus menggunakanprint("\(#function)")
Jake Lin
161

Untuk secara teknis menjawab pertanyaan Anda, Anda ingin:

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

Atau Anda juga bisa:

NSLog(@"%s", __PRETTY_FUNCTION__);
Dave DeLong
sumber
2
Dengan __FUNCTION__dan itu cukup setara juga tersedia di C-fungsi.
Georg Fritzsche
NB __FUNCTION__juga menyertakan nama kelas
OrangeDog
1
apakah ada perbedaan menggunakan NSLog (@ "% s", _func_ ); ATAU NSLog (@ "% s", _PRETTY_FUNCTION_ ) ???
Ravi
83

tl; dr

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

Detail

Apple memiliki halaman Tanya Jawab Teknis: QA1669 - Bagaimana saya bisa menambahkan informasi konteks - seperti metode atau nomor baris saat ini - ke pernyataan logging saya?

Untuk membantu pencatatan:

  • Preprocessor C menyediakan beberapa makro .
  • Objective-C memberikan ekspresi (metode).
    • Lewati argumen implisit untuk pemilih metode saat ini:_cmd

Seperti jawaban lain yang ditunjukkan, untuk sekadar mendapatkan nama metode saat ini, hubungi:

NSStringFromSelector(_cmd)

Untuk mendapatkan nama metode saat ini dan nomor baris saat ini, gunakan dua makro ini __func__dan __LINE__seperti yang terlihat di sini:

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

Contoh lain ... Cuplikan kode yang saya simpan di Perpustakaan Cuplikan Kode Xcode:

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

... dan TRACE bukannya ERROR ...

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

... dan yang lebih panjang menggunakan deskripsi kode lunak yang meneruskan nilai ( [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__ );

Makro preprosesor untuk logging

Perhatikan penggunaan sepasang karakter garis bawah di sekitar kedua sisi makro.

| Makro | Format | Deskripsi
  __func__% s Tanda tangan fungsi saat ini
  __LINE__% d Nomor baris saat ini
  __FILE__% s Path lengkap ke file sumber
  __PRETTY_FUNCTION__% s Suka __func__, tetapi termasuk verbose
                                    ketik informasi dalam kode C ++. 

Ekspresi untuk logging

| Ekspresi | Format | Deskripsi
  NSStringFromSelector (_cmd)% @ Nama pemilih saat ini
  NSStringFromClass ([kelas mandiri])% @ Nama kelas objek saat ini
  [[NSString% @ Nama file kode sumber
    stringWithUTF8String: __ FILE__]   
    lastPathComponent] 
  [NSThread callStackSymbols]% @ NSArray jejak tumpukan

Kerangka Penebangan

Beberapa kerangka kerja logging dapat membantu mendapatkan metode atau nomor baris saat ini juga. Saya tidak yakin, karena saya telah menggunakan kerangka kerja logging yang bagus di Jawa ( SLF4J + LogBack ) tetapi tidak untuk Cocoa.

Lihat pertanyaan ini untuk tautan ke berbagai kerangka kerja penebangan Kakao.

Nama Pemilih

Jika Anda memiliki variabel Pemilih ( SEL ), Anda dapat mencetak nama metode ("message") dengan salah satu dari dua cara seperti yang dijelaskan oleh posting blog Codec ini :

  • Menggunakan panggilan Objective-C ke NSStringFromSelector :
    NSLog(@"%@", NSStringFromSelector(selector) );
  • Menggunakan C lurus:
    NSLog(@"%s", selector );

Informasi ini diambil dari halaman Apple doc tertaut pada 2013-07-19. Halaman itu terakhir diperbarui 2011-10-04.

Basil Bourque
sumber
1
Untuk C, gunakan sel_getName(SEL)karena SEL adalah tipe buram dan mungkin tidak selalu menjadichar *
Ethan Reesor
8
NSLog(@"%@", NSStringFromSelector(_cmd)); // Objective-C
print(__FUNCTION__) // Swift
Huynh Inc
sumber
4
Untuk siapa pun yang menemukan jawaban ini di masa mendatang: itu setara dengan jawaban yang diterima, tetapi jawaban yang diterima berbeda, ketika jawaban ini diposting (jawaban yang diterima diedit pada 2014). Saya baru saja akan memilih, tetapi setelah penyelidikan kecil, memilih sebagai gantinya :)
FreeNickname
0

Ini sebenarnya sesederhana:

printf(_cmd);

Untuk beberapa alasan, iOS mengizinkan _cmd untuk diteruskan sebagai karakter literal tanpa peringatan kompilasi. Siapa tahu

Albert Renshaw
sumber
0

Dalam Swift 4:

tes func () {

print(#function)

}

test () // cetak nilai "test ()"

Ankit garg
sumber