Swift: print() vs println() vs NSLog()
A few differences:
print
vsprintln
: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 usingprintln
, you can now safely replace it withprint
.Back in Swift 1.x,
print
did not add newline characters at the end of the printed string, whereasprintln
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 aterminator
parameter of""
.NSLog
:NSLog
adds a timestamp and identifier to the output, whereasprint
will not;NSLog
statements appear in both the device’s console and debugger’s console whereasprint
only appears in the debugger console.NSLog
in iOS 10-13/macOS 10.12-10.x usesprintf
-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 favorLogger
overNSLog
. See next point.)
Nowadays, while
NSLog
still works, we would generally use “unified logging” (see below) rather thanNSLog
.Effective iOS 14/macOS 11, we have
Logger
interface to the “unified logging” system. For an introduction toLogger
, see WWDC 2020 Explore logging in Swift.To use
Logger
, you must importos
:import os
Like
NSLog
, unified logging will output messages to both the Xcode debugging console and the device console, tooCreate a
Logger
andlog
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
andcategory
. 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:
os_log("url = \(url, privacy: .public)")
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
andcategory
: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 withprint
andLogger
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 println and print in Swift
In the new swift 2, the println has been renamed to print which as an option "terminator" argument.
(udpated 2015-09-16 with the new terminator: "")
var fruits = ["banana","orange","cherry"]
// #1
for f in fruits{
print(f)
}
// #2
for f in fruits{
print("\(f) ", terminator: "")
}
#1 will print
banana
orange
cherry
#2 will print
banana orange cherry
swift print not printing to console
Found the issue
deep in the project, hidden among lines of code...I found!
public func debugPrint(_ items: Any..., separator: String = " ", terminator: String = "\n") {}
public func print(_ items: Any..., separator: String = " ", terminator: String = "\n") {}
Actually, it was at the top of AppDelegate...oops
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
Why print() in Swift does not log the time stamp as NSLog in objective C
Because print
is not NSLog
. It is as simple as that.
NSLog
is a logging tool in Foundation that writes to the Apple System Log facility which appears on the console.
print(…)
is a print function in the Swift Standard Library that writes to standard out, which appears on the console in debug sessions.
You could add Date()
to your print
parameter to print the current time and date. (Or Date().description(with: Locale.current)
to get it in your local time zone.)
Or you could just use NSLog
which is available in Swift too (if you import Foundation).
How can I get similar print result of NSLog for int enum in swift?
print
uses String.init(describing:)
under the hood to convert whatever you give it to a String
, so you can do that too:
NSLog("%@", String(describing: type))
But really though, the enum should conform to CustomStringConvertible
:
enum ImportType: Int, CustomStringConvertible {
case First = 1
case None
case Original
var description: String {
switch self {
case .First:
return "First"
case .None:
return "None"
case .Original:
return "Original"
}
}
}
and you should not rely on this default behaviour of String(describing:)
, because its behaviour is not specified unless the type conforms to TextOutputStreamable
, CustomStringConvertible
or CustomDebugStringConvertible
. See here for more info.
How to NSLog an Optional Int in Swift?
Just use the string interpolation syntax:
let d: Int? = 5
NSLog("\(d)")
Using print() from static function in Swift
I found the issue and feel a little dumb. The second instance of the app was just passing command line parameters to the first instance (using the observer) and quitting. The print function was being run by the first instance (not the one running in Terminal).
To fix this, I have to print text before the second instance of the app quits so that stdout is pointed to Terminal (duh).
Sorry if I wasted anyone's time!
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.
Related Topics
What Does "Fatal Error: Unexpectedly Found Nil While Unwrapping an Optional Value" Mean
How to Resolve: 'Keywindow' Was Deprecated in iOS 13.0
Segue and Button Programmatically Swift
How to Compare One Value Against Multiple Values - Swift
Xcode Swift Am/Pm Time to 24 Hour Format
Get Terminal Output After a Command Swift
Swiftui View and @Fetchrequest Predicate With Variable That Can Change
How to Make My Exponentiation Operator Work With All Numeric Types in Swift
Protocol Doesn't Conform to Itself
How to Run a Terminal Command in a Swift Script? (E.G. Xcodebuild)
Accessing an Enumeration Association Value in Swift
Differences in Nsdatecomponents Syntax
Getting Keyboard Size from Userinfo in Swift
Calculate Age from Birth Date Using Nsdatecomponents in Swift