Swift Debugprint Vs Print

print() vs debugPrint() in swift

You use debugPrint when you want more information about what is being printed to the console. The additional information is usually useful for debugging.

print() - Writes the textual representations of the given items into the standard output.

debugPrint() - Writes the textual representations of the given items most suitable for debugging into the standard output.

Basically debugPrint adds additional information that is useful for debugging like type information etc.

An example:

print(1...5)
// Prints "1...5"

debugPrint(1...5)
// Prints "CountableClosedRange(1...5)"

swift debugPrint vs print

In general, the way people call print is with no namespace — they just say print. So if you declare a global print function with the same signature as the standard library print, it will effectively "override" the standard library print:

func print(_ items: Any..., separator: String = ", ", terminator: String = "\n") {
preconditionFailure("STOP using print()")
}

The way to hide(skip) print() and debugPrint() in Swift

You don't need to do all of that... this will be effectively the same thing:

func print(_ items: Any..., separator: String = " ", terminator: String = "\n") {
#if DEBUG
items.forEach {
Swift.print($0, separator: separator, terminator: terminator)
}
#endif
}

You might also want to take a look at this answer for a little more discussion: https://stackoverflow.com/a/38335438/6257435

Swift: print() vs println() vs NSLog()

A few differences:

  1. print vs println:

    The print function prints messages in the Xcode console when debugging apps.

    The println is a variation of this that was removed in Swift 2 and is not used any more. If you see old code that is using println, you can now safely replace it with print.

    Back in Swift 1.x, print did not add newline characters at the end of the printed string, whereas println did. But nowadays, print always adds the newline character at the end of the string, and if you don't want it to do that, supply a terminator parameter of "".

  2. NSLog:

    • NSLog adds a timestamp and identifier to the output, whereas print will not;

    • NSLog statements appear in both the device’s console and debugger’s console whereas print only appears in the debugger console.

    • NSLog in iOS 10-13/macOS 10.12-10.x uses printf-style format strings, e.g.

       NSLog("%0.4f", CGFloat.pi)

      that will produce:

      2017-06-09 11:57:55.642328-0700 MyApp[28937:1751492] 3.1416

    • NSLog from iOS 14/macOS 11 can use string interpolation. (Then, again, in iOS 14 and macOS 11, we would generally favor Logger over NSLog. See next point.)

    Nowadays, while NSLog still works, we would generally use “unified logging” (see below) rather than NSLog.

  3. Effective iOS 14/macOS 11, we have Logger interface to the “unified logging” system. For an introduction to Logger, see WWDC 2020 Explore logging in Swift.

    • To use Logger, you must import os:

      import os
    • Like NSLog, unified logging will output messages to both the Xcode debugging console and the device console, too

    • Create a Logger and log a message to it:

      let logger = Logger(subsystem: Bundle.main.bundleIdentifier!, category: "network")
      logger.log("url = \(url)")

      When you observe the app via the external Console app, you can filter on the basis of the subsystem and category. It is very useful to differentiate your debugging messages from (a) those generated by other subsystems on behalf of your app, or (b) messages from other categories or types.

    • You can specify different types of logging messages, either .info, .debug, .error, .fault, .critical, .notice, .trace, etc.:

      logger.error("web service did not respond \(error.localizedDescription)")

      So, if using the external Console app, you can choose to only see messages of certain categories (e.g. only show debugging messages if you choose “Include Debug Messages” on the Console “Action” menu). These settings also dictate many subtle issues details about whether things are logged to disk or not. See WWDC video for more details.

    • By default, non-numeric data is redacted in the logs. In the example where you logged the URL, if the app were invoked from the device itself and you were watching from your macOS Console app, you would see the following in the macOS Console:

      url = <private>

      If you are confident that this message will not include user confidential data and you wanted to see the strings in your macOS console, you would have to do:

      logger.log("url = \(url, privacy: .public)")
  4. Prior to iOS 14/macOS 11, iOS 10/macOS 10.12 introduced os_log for “unified logging”. For an introduction to unified logging in general, see WWDC 2016 video Unified Logging and Activity Tracing.

    • Import os.log:

      import os.log
    • You should define the subsystem and category:

      let log = OSLog(subsystem: Bundle.main.bundleIdentifier!, category: "network")
    • When using os_log, you would use a printf-style pattern rather than string interpolation:

      os_log("url = %@", log: log, url.absoluteString)
    • You can specify different types of logging messages, either .info, .debug, .error, .fault (or .default):

      os_log("web service did not respond", type: .error)
    • You cannot use string interpolation when using os_log. For example with print and Logger you do:

      logger.log("url = \(url)")

      But with os_log, you would have to do:

      os_log("url = %@", url.absoluteString)
    • The os_log enforces the same data privacy, but you specify the public visibility in the printf formatter (e.g. %{public}@ rather than %@). E.g., if you wanted to see it from an external device, you'd have to do:

      os_log("url = %{public}@", url.absoluteString)
    • You can also use the “Points of Interest” log if you want to watch ranges of activities from Instruments:

      let pointsOfInterest = OSLog(subsystem: Bundle.main.bundleIdentifier!, category: .pointsOfInterest)

      And start a range with:

      os_signpost(.begin, log: pointsOfInterest, name: "Network request")

      And end it with:

      os_signpost(.end, log: pointsOfInterest, name: "Network request")

      For more information, see https://stackoverflow.com/a/39416673/1271826.

Bottom line, print is sufficient for simple logging with Xcode, but unified logging (whether Logger or os_log) achieves the same thing but offers far greater capabilities.

The power of unified logging comes into stark relief when debugging iOS apps that have to be tested outside of Xcode. For example, when testing background iOS app processes like background fetch, being connected to the Xcode debugger changes the app lifecycle. So, you frequently will want to test on a physical device, running the app from the device itself, not starting the app from Xcode’s debugger. Unified logging lets you still watch your iOS device log statements from the macOS Console app.

Difference between Printable and DebugPrintable in Swift

In Xcode 6 Beta (Version 6.2 (6C101)) I find that both println and debugPrintln use description if-and-only-if the class descends from NSObject. I don't see that either uses debugDescription at all but when run in a Playground debugPrintln outputs only to the Console and doesn't appear in the playground itself.

import Foundation

class Tdesc: NSObject, Printable, DebugPrintable {
override var description: String {return "A description"}
override var debugDescription: String {return "A debugDescription"}
}

class Xdesc: Printable, DebugPrintable {
var description: String {return "A description"}
var debugDescription: String {return "A debugDescription"}
}

let t = Tdesc()
let x = Xdesc()

t.description

let z: String = "x\(t)"

println(t) // Displays "A description" in the Playground and Console

debugPrintln(t) // Displays nothing in the Playground but "A description" in the Console

x.description

let y: String = "x\(x)"

println(x) // Displays "__lldb_expr_405.Xdesc" in the Playground and Console

debugPrintln(x)

Swift print is not showing in Debug Console

The answer was that you can't print in live preview mode (even in debugging mode). You have to build and run the simulator to show the console logs.

Sorry for the more-than-novice question.

In Swift (5), how to I pass an Any... parameter to a print() statement without it printing as an array?

You can simply map your items into strings, join them with the separator and print the resulting string:

public enum Debug {
static func print(_ items: Any..., separator: String = " ", terminator: String = "\n") {
#if DEBUG
Swift.print(items.map({String(describing: $0)}).joined(separator: separator), terminator: terminator)
#endif
}
}

Or simply:

How to print() to Xcode console in SwiftUI?

You can easily add a print statement anywhere in a function builder by simply storing its return value in a wildcard, effectively ignoring it:

let _ = print("hi!")

No setup or other verbosity needed!

Why does this work while a regular print() doesn't?

The way SwiftUI's @ViewBuilder (and result builders in general) is that they consume any values in a closure that aren't used otherwise (e.g. if you just have 42 on its own line). The print function returns Void (nothing), which the builder would have to build into a view, so it fails. By instead assigning it to a variable (in this case _, basically a variable that you can never access), the Void is never offered to the view builder in the first place.

You could argue the builder should simply accept and ignore Void values, but the idea is that your builder closures should not have side effects (I'd remove print statements after finishing debugging too)—you should not rely on these closures being called at certain times.

Should I release an app to the App Store with print statements in it?

I assume you are using Swift, then print is completely safe, even for AppStore builds. You are not going to be rejected and it's not a security risk either.

print, unlike similar NSLog, is not going to produce any logs anywhere that would be visible to the user (e.g. in Xcode Device Console).

More info on the difference between print and NSLog: Swift: print() vs println() vs NSLog()



Related Topics



Leave a reply



Submit