Удалить println() для версии iOS Swift
Я хотел бы глобально игнорировать все println() вызывает мой Swift-код, если я не нахожусь в отладочной сборке. Я не могу найти никаких надежных пошаговых инструкций для этого и был бы признателен за руководство. есть ли способ сделать это глобально, или мне нужно окружить каждый println() с #IF DEBUG/#ENDIF заявления?
14 ответов:
самый простой способ-поставить свою собственную глобальную функцию перед Swift
println:func println(object: Any) { Swift.println(object) }когда пришло время прекратить ведение журнала, просто закомментируйте тело этой функции:
func println(object: Any) { // Swift.println(object) }или вы можете сделать это автоматически при помощи условного:
func println(object: Any) { #if DEBUG Swift.println(object) #endif }EDIT В Swift 2.0
printlnизменено наfunc print(items: Any..., separator: String = " ", terminator: String = "\n") { Swift.print(items[0], separator:separator, terminator: terminator) }в Swift 3 необходимо подавить внешнюю метку первого параметра:
func print(_ items: Any..., separator: String = " ", terminator: String = "\n") { Swift.print(items[0], separator:separator, terminator: terminator) }
обновлено для Swift 4.x:
С Swift 2.0 / 3.0 и Xcode 7/8 теперь из бета-версии, были некоторые изменения в том, как отключить функцию печати в релизе строит.
есть некоторые важные моменты, упомянутые @matt и @Nate Birkholz выше, которые все еще действительны.
The
println()функция была заменена наprint()использовать
#if DEBUGмакрос, то вы должны определить " Swift компилятор - Пользовательские флаги-другие флаги", чтобы содержать значение-D DEBUGЯ бы рекомендовал переопределить
Swift.print()функции в глобальной области видимости, так что вы можете использоватьprint()функция как обычно в вашем коде, но она удалит вывод для не отладочных сборок. Вот сигнатура функции, которую вы можете добавить в глобальную область, чтобы сделать это в Swift 2.0 / 3.0:func print(items: Any..., separator: String = " ", terminator: String = "\n") { #if DEBUG var idx = items.startIndex let endIdx = items.endIndex repeat { Swift.print(items[idx], separator: separator, terminator: idx == (endIdx - 1) ? terminator : separator) idx += 1 } while idx < endIdx #endif }Примечание: мы по умолчанию, чтобы быть здесь, и по умолчанию Терминатор будет новой строкой. Вы можете настроить это по-другому в своем проекте, если хотите.
надеюсь, что это помогает.
обновление:
обычно предпочтительно поместить эту функцию в глобальную область, чтобы она сидела перед Swift
проблема со всеми этими подходами, включая мой, заключается в том, что они не устраняют накладные расходы на оценку
print(myExpensiveFunction())единственное достойное решение-обернуть фактический вызов печати в условную компиляцию (предположим, что
DEBUGопределен только для отладочных сборок):#if DEBUG print(myExpensiveFunction()) #endifэто, и только это, мешает
myExpensiveFunctionот вызова в релизе строить.тем не менее, вы можете отодвинуть оценку на один уровень с помощью autoclosure. Таким образом, вы можете переписать мое решение (это Swift 3) следующим образом:
func print(_ item: @autoclosure () -> Any, separator: String = " ", terminator: String = "\n") { #if DEBUG Swift.print(item(), separator:separator, terminator: terminator) #endif }это решает проблему только в том случае, когда вы печатаете только одну вещь, что обычно верно. Это потому что
item()не вызывается в режиме релиза.print(myExpensiveFunction())таким образом, перестает быть дорогим, потому что вызов завернут в закрытие без оценки, и в режиме выпуска он не будет оценивали вообще.
как уже отмечалось, я студент и мне нужно, чтобы вещи были определены немного более четко, чтобы следовать дальше. После большого количества исследований, последовательность, которую я должен был следовать:
нажмите на имя проекта в верхней части файлового навигатора слева от окна проекта Xcode. Это строка с именем проекта, количеством целевых объектов сборки и версией iOS SDK.
выбрать Параметры Построения вкладка и прокрутите вниз до "Компилятор Swift - Пользовательские Флаги" раздел в нижней части. Щелкните стрелку вниз рядом с Другие Флаги для расширения раздела.
нажмите на кнопку Debug строка для его выбора. Наведите курсор мыши на правую сторону линии и дважды щелкните. Появится представление списка. Нажмите кнопку + в левом нижнем углу списка, чтобы добавить значение. Текстовое поле станет активным.
в текстовом поле Введите текст
-D DEBUGи нажмите возвращение для фиксации линии.добавьте новый файл Swift в свой проект. Вы собираетесь сделать пользовательский класс для файла, поэтому введите текст в следующих строках:
class Log { var intFor : Int init() { intFor = 42 } func DLog(message: String, function: String = __FUNCTION__) { #if DEBUG println("\(function): \(message)") #endif } }у меня были проблемы с тем, чтобы класс был принят Xcode сегодня, поэтому init может быть немного более тяжелым, чем необходимо.
теперь вам нужно будет ссылаться на свой пользовательский класс в любом классе, в котором вы собираетесь использовать новую пользовательскую функцию место
println()добавьте это как свойство в каждом применимом классе:let logFor = Log()теперь вы можете заменить любые случаи
println()СlogFor.DLog(). Выходные данные также включают имя функции, в которой была вызвана строка.обратите внимание, что внутри функций класса я не мог вызвать функцию, если я не сделал копию функции как функции класса в этом классе, и
println()также немного более гибко с вводом, поэтому я не мог использовать это в каждом случае в моем код.
протестировано с Swift 2.1 & Xcode 7.1.1
есть простой способ исключить все операторы печати из версий выпуска, как только вы знаете, что пустые функции удаляются компилятором Swift.
Примечание: В эпоху Objective-C был предварительный парсер, который можно было использовать для удаления операторов NSLog до запуска компилятора, как описано в моем ответе здесь. Но так как Свифта нет больше нет предварительного парсера этот подход больше не действует.
вот что я использую сегодня в качестве расширенной и легко настраиваемой функции журнала, не беспокоясь о ее удалении в сборках релизов. Кроме того, установив различные флаги компилятора, вы можете настроить информацию, которая регистрируется по мере необходимости.
вы можете настроить функцию по мере необходимости, любое предложение по ее улучшению приветствуется!
// Gobal log() function // // note that empty functions are removed by the Swift compiler -> use #if $endif to enclose all the code inside the log() // these log() statements therefore do not need to be removed in the release build ! // // to enable logging // // Project -> Build Settings -> Swift Compiler - Custom flags -> Other Swift flags -> Debug // add one of these 3 possible combinations : // // -D kLOG_ENABLE // -D kLOG_ENABLE -D kLOG_DETAILS // -D kLOG_ENABLE -D kLOG_DETAILS -D kLOG_THREADS // // you can just call log() anywhere in the code, or add a message like log("hello") // func log(message: String = "", filePath: String = #file, line: Int = #line, function: String = #function) { #if kLOG_ENABLE #if kLOG_DETAILS var threadName = "" #if kLOG_THREADS threadName = NSThread.currentThread().isMainThread ? "MAIN THREAD" : (NSThread.currentThread().name ?? "UNKNOWN THREAD") threadName = "[" + threadName + "] " #endif let fileName = NSURL(fileURLWithPath: filePath).URLByDeletingPathExtension?.lastPathComponent ?? "???" var msg = "" if message != "" { msg = " - \(message)" } NSLog("-- " + threadName + fileName + "(\(line))" + " -> " + function + msg) #else NSLog(message) #endif #endif }вот где вы устанавливаете флаги компилятора :
пример вывода со всеми флагами выглядит так:
2016-01-13 23:48:38.026 FoodTracker[48735:4147607] -- [MAIN THREAD] ViewController(19) -> viewDidLoad() - helloкод с log() выглядит так:
override func viewDidLoad() { log("hello") super.viewDidLoad() // Handle the text field's user input through delegate callbacks nameTextField.delegate = self }
вот функция, которую я использую, которая отлично работает в Swift 3:
func gLog<T>( _ object: @autoclosure() -> T, _ file: String = #file, _ function: String = #function, _ line: Int = #line) { #if DEBUG let value = object() let stringRepresentation: String if let value = value as? CustomDebugStringConvertible { stringRepresentation = value.debugDescription } else if let value = value as? CustomStringConvertible { stringRepresentation = value.description } else { fatalError("gLog only works for values that conform to CustomDebugStringConvertible or CustomStringConvertible") } let fileURL = NSURL(string: file)?.lastPathComponent ?? "Unknown file" let queue = Thread.isMainThread ? "UI" : "BG" let gFormatter = DateFormatter() gFormatter.dateFormat = "HH:mm:ss:SSS" let timestamp = gFormatter.string(from: Date()) print(" \(timestamp) {\(queue)} \(fileURL) > \(function)[\(line)]: " + stringRepresentation + "\n") #endif }вот пример вывода, который он генерирует:
объяснение:
зеленая галочка используется для быстрого просмотра ваших печатных (gLog) сообщений в консоли, где они иногда могут потеряться в море других сообщений
время/дата штамп
поток, на котором он запускается -- в моем случае это либо MainThread (который я называю UI), либо не MainThread (который я называю BG, для фонового потока)
имя файла, в котором находится сообщение gLog
функция в файле, в котором находится сообщение gLog
номер строки сообщения gLog
фактический глег сообщение, которое вы хотели бы распечатать
надеюсь, что это полезно кому-то еще!
XCode 8 представил несколько новое строительство.
В частности, один из упомянутыхActive Compilation Conditionsделает подобным образом то, что Другие Флаги настройки сделали."активные условия компиляции" - это новый параметр сборки для передачи флагов условной компиляции компилятору Swift.
согласно XCode 8 (проверено в 8.3.2) вы получите это по умолчанию:
так без любой конфигурации вы можете написать следующее:
#if DEBUG print("⚠️ Something weird happened") #endifя настоятельно рекомендую вам, если вы широко используете этот подход, создать класс / структуру / функцию, которая обертывает эту логику ведения журнала. Вы можете расширить это дальше по дороге.
еще проще, убедившись
-D DEBUGдляOTHER_SWIFT_FLAGSотладки настройки:#if !DEBUG func println(object: Any) {} func print(object: Any){} #endif
в Swift 2 / Xcode 7 вам больше не нужно / использовать
printlnно вы можете добавить строк:func print(_ items: Any..., separator separator: String = default, terminator terminator: String = default)
Swift 4
приведенный ниже код отлично работает для меня:
func print(_ items: Any...) { #if DEBUG items.forEach { item in Swift.print(item) } #endif }печать каждого элемента, как это избавляется от раздражающих скобок массива вокруг операторов печати:)
Swift 4 Xcode 10.0
может быть, вы могли бы использовать этот
func dPrint(_ message: @autoclosure () -> Any) { #if DEBUG print(message()) #endif }причина использования
@autoclosureэто то, что если вы передадите функцию в качестве параметра сообщения, функция будет вызываться только в режиме отладки, это приведет к снижению производительности.в отличие от
Swift.print(_ items: Any..., separator: String = default, terminator: String = default)функция, мое решение имеет только один параметр, потому что в большинстве случаев мы не передаем несколько параметров, поскольку функция печати показывает только информацию в консоли, мы можем просто конвертировать параметры для строки:"\(param1)"+"\(param2)", Да? надеюсь, вам понравится мое решение
мое решение-использовать этот код в AppDelegate перед классом
// Disable console log in live app #if !arch(x86_64) && !arch(i386) public func debugPrint(items: Any..., separator: String = " ", terminator: String = "\n") { } public func print(_ items: Any..., separator: String = " ", terminator: String = "\n") { } #endif class AppDelegate: UIResponder, UIApplicationDelegate { // App Delegate Code }
для моего решения я делаю это просто
import UIKit class DLog: NSObject { init(title:String, log:Any) { #if DEBUG print(title, log) #endif } }затем, чтобы показать, что это просто вызов
_ = DLog(title:"any title", log:Any)
выше все хорошие ответы. Вы могли бы просто использовать
Swift.debugPrint()вместо того, чтобы отключить все отпечатки в режиме выпуска.



Comments