İPhone'da Objective-C ile yöntem adını yazın


153

Şu anda kendimize, günlüğün sınıf adını ve kaynak satır numarasını yazdırmak için genişletilmiş bir günlük mekanizması tanımlamaktayız.

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

Örneğin, NCLog (@ "Merhaba dünya") dediğimde; Çıktı şöyle olacaktır:

<ApplicationDelegate:10>Hello world

Şimdi de yöntem adı gibi oturumu kapatmak istiyorum:

<ApplicationDelegate:applicationDidFinishLaunching:10>Hello world

Bu nedenle, hangi yöntemin çağrıldığını bildiğimizde hata ayıklamamızı kolaylaştırır. Ben de Xcode hata ayıklayıcı var biliyorum ama bazen de çıkış yaparak hata ayıklama yapmak istiyorum.


Son iPhoneprojemde bunu gerçekten elle yaptım. Bunun cevabını görmek isterdim.
Jacob Relkin

Yanıtlar:


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

Swift 3 ve üstü

print(#function)

120
Kullanacaksanız gerçekten NSLog(@"%@", NSStringFromSelector(_cmd))kullanmalısınız _cmd, çünkü AFAIK Apple bir C-string değil _cmd, tip olarak bildirir SEL. Bir C-string (Mac OS X ve iPhone OS'nin mevcut sürümlerinden itibaren) olarak uygulanması, Apple'ın bir OS güncellemesinde değiştirebileceği için onu bu şekilde kullanmanız gerektiği anlamına gelmez.
Nick Forge

5
Evet, NSStringFromSelector daha doğru cevaptır. Ben asla hata ayıklama kodu dışında bir şey için c dize olarak _cmd kullanın.
drawnonward

Vay, derleyici işaretçi uyumsuzluğu hakkında şikayet, ama işe yarıyor ... Yani _cmd (tip: SEL) gerçekten bir char * !?
Nicolas Miari

3
[self doSomething:arg1 somethingElse:arg2]C işlev çağrısına dönüştürülmek gibi yöntem çağrıları objc_msgSend(self, "doSomething:somethingElse:, arg1, arg2);. İkinci parametre objc_msgSend()a'yı alır char*. Objective-C çalışma zamanı dinamik olduğu için, aslında hangi sınıfta hangi char üzerinde çağrılacağına ilişkin yöntemi bulmak için bir arama tablosu kullandığını, bu nedenle yöntemler arama tablosunda dize olarak temsil edildiğinden, bir char * 'ın uygun olduğunu unutmayın.
Jack Lawrence

1
Swift 2.2 için kullanmalıprint("\(#function)")
Jake Lin

161

Sorunuzu teknik olarak cevaplamak için:

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

Veya şunları da yapabilirsiniz:

NSLog(@"%s", __PRETTY_FUNCTION__);

2
İle __FUNCTION__ve oldukça eşdeğer C fonksiyonlarında da mevcut.
Georg Fritzsche

NB __FUNCTION__ayrıca sınıf adını içerir
OrangeDog

1
NSLog kullanıldığında herhangi bir fark var mı (@ "% s", _func_ ); VEYA NSLog (@ "% s", _PRETTY_FUNCTION_ ) ???
Ravi

83

tl; Dr.

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

ayrıntılar

Apple'ın bir Teknik Soru ve Cevap sayfası var: QA1669 - Günlük ifadelerime geçerli yöntem veya satır numarası gibi bağlam bilgilerini nasıl ekleyebilirim?

Günlük tutmaya yardımcı olmak için:

  • C ön işlemcisi birkaç makro sağlar .
  • Objective-C ifadeler (yöntemler) sağlar.
    • Geç örtük argüman geçerli yöntemin seçici için:_cmd

Diğer yanıtların belirttiği gibi, yalnızca geçerli yöntemin adını almak için şunu arayın:

NSStringFromSelector(_cmd)

Geçerli yöntem adını almak ve geçerli satır numarasını almak için şu iki makroyu kullanın __func__ve __LINE__burada görüldüğü gibi:

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

Başka bir örnek… Xcode'un Kod Parçacığı Kütüphanesinde sakladığım kod parçacıkları:

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

… Ve HATA yerine TRACE…

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

… Ve daha uzun bir değer geçen yumuşak kodlu bir açıklama kullanarak ([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__ );

Günlük kaydı için önişlemci makroları

Bir çift ​​alt çizginin kullanımına dikkat edinMakronun her iki yanında karakteri kullandığına dikkat edin.

| Makro | Biçim | Açıklama
  __func__% s Geçerli işlev imzası
  __LINE__% d Geçerli satır numarası
  __FILE__% s Kaynak dosyanın tam yolu
  __PRETTY_FUNCTION__% s __func__ gibi, ancak ayrıntılı
                                    bilgileri C ++ koduna yazın. 

Günlük ifadeleri

| Anlatım | Biçim | Açıklama
  NSStringFromSelector (_cmd)% @ Geçerli seçicinin adı
  NSStringFromClass ([self class])% @ Geçerli nesnenin sınıf adı
  [[NSString% @ Kaynak kodu dosya adı
    stringWithUTF8String: __ FILE__]   
    lastPathComponent] 
  [NSThread callStackSymbols]% @ NS Yığın izinin dizisi

Günlük Çerçeveleri

Bazı günlük çerçeveleri mevcut yöntemi veya satır numarasını almanıza da yardımcı olabilir. Java'da ( SLF4J + LogBack ) büyük bir günlük kaydı çerçevesi kullandığımdan emin değilim ama kakao değil.

Çeşitli Kakao kayıt çerçevelerine bağlantılar için bu soruya bakın .

Seçicinin Adı

Bir Seçici değişkeniniz (bir SEL ) varsa, yöntem adını ("ileti") bu Codec blog gönderisinde açıklandığı gibi iki yoldan biriyle yazdırabilirsiniz :

  • NSStringFromSelector öğesine Objective-C çağrısı kullanma :
    NSLog(@"%@", NSStringFromSelector(selector) );
  • Düz C kullanma:
    NSLog(@"%s", selector );

Bu bilgiler 2013-07-19 itibariyle bağlantılı Apple dokümanı sayfasından alınmıştır. Bu sayfa en son 2011-10-04 tarihinde güncellenmiştir.


1
C için sel_getName(SEL)SEL opak bir tip olduğundan ve her zaman olmayabilirchar *
Ethan Reesor

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

4
Gelecekte bu cevapla karşılaşan herkes için: kabul edilen cevaba eşdeğerdir, ancak kabul edilen cevap, bu cevap gönderildiğinde farklıydı (kabul edilen cevap 2014'te düzenlendi). Oy vermek üzereydim, ancak küçük bir soruşturmadan sonra yerine oy verildi :)
FreeNickname

0

Aslında bu kadar basit:

printf(_cmd);

Bazı nedenlerden dolayı iOS _cmd'nin derleme uyarısı bile olmadan gerçek bir karakter olarak geçirilmesine izin verir. Kim bilir


0

Swift 4'te:

func testi () {

print(#function)

}

test () // "test ()" değerini yazdır

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.