NSLog имя метода с Objective-C в iPhone


153

В настоящее время мы сами определяем расширенный механизм журнала, чтобы распечатать имя класса и номер строки исходного кода журнала.

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

Например, когда я звоню NCLog (@ "Hello world"); Выход будет:

<ApplicationDelegate:10>Hello world

Теперь я также хочу выйти из имени метода, как:

<ApplicationDelegate:applicationDidFinishLaunching:10>Hello world

Таким образом, это сделает нашу отладку проще, когда мы сможем узнать, какой метод вызывается. Я знаю, что у нас также есть отладчик Xcode, но иногда я также хочу выполнить отладку, выйдя из системы.


В моем последнем iPhoneпроекте я фактически делал это вручную. Хотелось бы увидеть ответ на это.
Джейкоб Релкин

Возможный дубликат: stackoverflow.com/questions/969130/…
erkanyildiz

Ответы:


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

Свифт 3 и выше

print(#function)

120
Вы действительно должны использовать NSLog(@"%@", NSStringFromSelector(_cmd)), если вы собираетесь использовать _cmd, так как AFAIK Apple объявляет _cmdкак тип SEL, а не C-строку. Тот факт, что он реализован в виде C-строки (в текущих версиях Mac OS X и iPhone OS), не означает, что вы должны использовать его таким образом, поскольку Apple может изменить его в обновлении ОС.
Ник Фордж

5
Да, NSStringFromSelector - более правильный ответ. Я никогда не использую _cmd как строку c для чего-либо, кроме кода отладки.
обращается

Вау, компилятор жалуется на несовместимость указателей, но это работает ... Так что _cmd (type: SEL) действительно является char *!?
Николас Миари

3
Метод требует , как [self doSomething:arg1 somethingElse:arg2]преобразуется в вызов функции C objc_msgSend(self, "doSomething:somethingElse:, arg1, arg2);. Второй параметр objc_msgSend()принимает char*. Помните, что поскольку среда выполнения Objective C является динамической, она фактически использует таблицу поиска, чтобы выяснить, какой метод для какого класса вызывать, так что char * удобен, поскольку методы представлены в виде строки в таблице поиска.
Джек Лоуренс

1
Для Swift 2.2 следует использоватьprint("\(#function)")
Джейк Лин

161

Чтобы технически ответить на ваш вопрос, вы хотите:

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

Или вы также можете сделать:

NSLog(@"%s", __PRETTY_FUNCTION__);

2
С __FUNCTION__и его довольно эквивалентно также доступны в C-функциях.
Георг Фрицше

NB __FUNCTION__также включает в себя название класса
OrangeDog

1
есть ли разница с помощью NSLog (@ "% s", _func_ ); ИЛИ NSLog (@ "% s", _PRETTY_FUNCTION_ ) ???
Рави

83

ТЛ; др

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

подробности

У Apple есть техническая страница вопросов и ответов : QA1669 - Как я могу добавить контекстную информацию - такую ​​как текущий метод или номер строки - в свои операторы регистрации?

Чтобы помочь с регистрацией:

  • Препроцессор C предоставляет несколько макросов .
  • Objective-C предоставляет выражения (методы).
    • Передайте неявный аргумент для селектора текущего метода:_cmd

Как указано в других ответах, чтобы просто получить имя текущего метода, вызовите:

NSStringFromSelector(_cmd)

Чтобы получить текущее имя методы и номер текущей строки, используйте эти два макрос __func__и , __LINE__как показано здесь:

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

Другой пример ... Фрагменты кода, которые я храню в библиотеке фрагментов кода Xcode:

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

... и TRACE вместо ERROR ...

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

… И более длинный, использующий мягкое описание, передающее значение ( [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__ );

Макросы препроцессора для регистрации

Обратите внимание на использование пары символов подчеркивания по обе стороны макроса.

| Макро | Формат | Описание
  __func__% s Текущая подпись функции
  __LINE__% d Текущий номер строки
  __FILE__% s Полный путь к исходному файлу
  __PRETTY_FUNCTION__% s Как и __func__, но содержит подробный
                                    введите информацию в коде C ++. 

Выражения для регистрации

| Выражение | Формат | Описание
  NSStringFromSelector (_cmd)% @ Имя текущего селектора
  NSStringFromClass ([self class])% @ Имя класса текущего объекта
  [[NSString% @ Имя файла исходного кода
    stringWithUTF8String: __ FILE__]   
    lastPathComponent] 
  [NSThread callStackSymbols]% @ NSArray трассировки стека

Фреймворки

Некоторые каркасы журналирования также могут помочь в получении текущего метода или номера строки. Я не уверен, так как я использовал отличный каркас для ведения журналов в Java ( SLF4J + LogBack ), но не в Какао.

Смотрите этот вопрос для ссылок на различные каркасы ведения журнала Какао.

Имя селектора

Если у вас есть переменная Selector (а SEL ), вы можете распечатать его имя метода ( «сообщение») в одном из двух способов, описанных этим Codec блоге :

  • Используя Objective-C вызов NSStringFromSelector :
    NSLog(@"%@", NSStringFromSelector(selector) );
  • Используя прямой C:
    NSLog(@"%s", selector );

Эта информация взята со ссылочной страницы Apple Doc по состоянию на 2013-07-19. Эта страница была в последний раз обновлена ​​2011-10-04.


1
Для C используйте, sel_getName(SEL)поскольку SEL является непрозрачным типом и не всегда может бытьchar *
Ethan Reesor

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

4
Для любого, кто сталкивается с этим ответом в будущем: он эквивалентен принятому ответу, но принятый ответ был другим, когда этот был опубликован (принятый ответ был отредактирован в 2014 году). Я собирался проголосовать вниз, но после небольшого расследования проголосовал вместо этого :)
FreeNickname

0

На самом деле это так же просто, как:

printf(_cmd);

По какой-то причине iOS позволяет передавать _cmd как буквенный символ даже без предупреждения компиляции. Кто знает


Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.