Удалить println() для версии iOS Swift



Я хотел бы глобально игнорировать все println() вызывает мой Swift-код, если я не нахожусь в отладочной сборке. Я не могу найти никаких надежных пошаговых инструкций для этого и был бы признателен за руководство. есть ли способ сделать это глобально, или мне нужно окружить каждый println() с #IF DEBUG/#ENDIF заявления?

557   14  

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 изменено на print. К сожалению, теперь у него есть первый параметр variadic; это круто, но это означает, что вы не можете легко переопределить его, потому что Swift имеет нет оператора "splat", поэтому вы не можете передать variadic в коде (его можно создать только буквально). Но вы можете сделать уменьшенную версию, которая работает, если, как это обычно бывает, вы печатаете только одно значение:

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 выше, которые все еще действительны.

  1. The println() функция была заменена на print()

  2. использовать #if DEBUG макрос, то вы должны определить " Swift компилятор - Пользовательские флаги-другие флаги", чтобы содержать значение -D DEBUG

  3. Я бы рекомендовал переопределить 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 аргументов. Независимо от того, какой из них вы используете, это будет дорого:

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
}

вот где вы устанавливаете флаги компилятора :

enter image description here

пример вывода со всеми флагами выглядит так:

   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
    }

вот пример вывода, который он генерирует:

screenshot of output

объяснение:

  • зеленая галочка используется для быстрого просмотра ваших печатных (gLog) сообщений в консоли, где они иногда могут потеряться в море других сообщений

  • время/дата штамп

  • поток, на котором он запускается -- в моем случае это либо MainThread (который я называю UI), либо не MainThread (который я называю BG, для фонового потока)

  • имя файла, в котором находится сообщение gLog

  • функция в файле, в котором находится сообщение gLog

  • номер строки сообщения gLog

  • фактический глег сообщение, которое вы хотели бы распечатать

надеюсь, что это полезно кому-то еще!

XCode 8 представил несколько новое строительство.
В частности, один из упомянутых Active Compilation Conditions делает подобным образом то, что Другие Флаги настройки сделали.

"активные условия компиляции" - это новый параметр сборки для передачи флагов условной компиляции компилятору Swift.

согласно XCode 8 (проверено в 8.3.2) вы получите это по умолчанию:

enter image description here

так без любой конфигурации вы можете написать следующее:

#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)", Да? надеюсь, вам понравится мое решение

вы могли бы определить debug_println чье содержание будет примерно:

#if DEBUG
  println()
#endif

мое решение-использовать этот код в 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

    Ничего не найдено.