74

In Objective-C, we could use the __LINE__ and __PRETTY_FUNCTION__ macros. These are not exposed in the Swift language. Is there another way to get similar information in Swift?

Pang
  • 9,564
  • 146
  • 81
  • 122
phoganuci
  • 4,984
  • 9
  • 39
  • 50

4 Answers4

155
Literal Type Value
#file String The path to the file in which it appears.
#fileID String The name of the file and module in which it appears.
#filePath String The path to the file in which it appears.
#line Int The line number on which it appears.
#column Int The column number in which it begins.
#function String The name of the declaration in which it appears.
#dsohandle UnsafeRawPointer The dynamic shared object (DSO) handle in use where it appears.

See documentation for more information

Example:

print("Function: \(#function), line: \(#line)") 

With default values in parameters you can also create a function:

public func track(_ message: String, file: String = #file, function: String = #function, line: Int = #line ) { 
    print("\(message) called from \(function) \(file):\(line)") 
}

which can be used like this

track("enters app")
Adil Hussain
  • 30,049
  • 21
  • 112
  • 147
hfossli
  • 22,616
  • 10
  • 116
  • 130
  • 3
    Swift 2.2 changes are now released and should be the new approved answer :) – Bersaelor Mar 22 '16 at 13:19
  • 1
    `#` is happening in 2.2. – Zigii Wong Mar 23 '16 at 07:04
  • #namespace is not a identifier. – c0ming Apr 25 '16 at 01:47
  • Why have all of those parameters? you wouldn't want to actually change them right? – Joey Nelson Aug 19 '20 at 01:31
  • Yep, you would only use them to capture call site information like file and line number. So normal usage would be `track("enters app")` without specifying the others. – hfossli Sep 17 '20 at 18:47
  • Starting Swift 5.8, the #file magic identifier is used to get the format Module/Filename, e.g. MyApp/ContentView.swift. Previously, #file contained the whole path to the Swift file, e.g. /Users/xyz/Desktop/MyExperiment/MyExperiment/ContentView.swift, which is unnecessarily long. Currently the newly introduced behavior is not enabled by default. To enable the new #file behavior you should add -enable-upcoming-feature ConciseMagicFile to Other Swift Flags in Xcode. If you’d like to have the old behavior after this flag is enabled, you can use #filePath instead. – grow4gaurav Mar 31 '23 at 15:32
101

The Swift Language Reference defines a few "special literals" that offer this behavior:

Literal Type Value
#file String The name of the file in which it appears.
#line Int The line number on which it appears.
#column Int The column number in which it begins.
#function String The name of the declaration in which it appears.
Adil Hussain
  • 30,049
  • 21
  • 112
  • 147
nathan
  • 5,466
  • 3
  • 27
  • 24
8

You can get just the file name this way

Swift 5

let errorLocation =  (#file as NSString).lastPathComponent
print(errorLocation)

or get with separator from last component

let errorLocation = filePath.components(separatedBy: "/").last!
print(errorLocation)

Output

ViewController.swift
Yunus T.
  • 569
  • 7
  • 13
0

If you want to get call-site position of a function, you need to pass filename and line as a default parameters.

Trace.swift

func trace(_ msg: String, file: String = #fileID, line: Int = #line) {
    let pos = "\(file.split(on: "/").last!):\(line)"
    print("\(pos): \(msg))
}

Foo.swift

func bar() {
    trace("baz!")
}

Output

Foo.swift:8: baz!
4emodan
  • 955
  • 1
  • 9
  • 17