How does Swift translate -[NSView print] to printView()?

I'd like to understand how/where a particular translation of an Objective-C API to Swift is defined. The NSView method

- (void)print:(id)sender;

used to be imported as

open func print(_ sender: Any?)

in Swift ≤ 3. Apparently in order to avoid conflicts with the global print() function, the translation changed to

open func printView(_ sender: Any?)

in Swift 4/Xcode 9.

There is a general translation mechanism (described in SE-0005 Better Translation of Objective-C APIs Into Swift), so there are two possibilities:

  • There were changes in the general translation mechanism, or
  • there is a “custom translation” for this particular API.

My guess would be the custom translation, but I could not find any occurrence of "printView" in the Swift source code. Also there is no NS_SWIFT_NAME annotation on the Objective-C declaration in NSView.h.

I also could not find anything related to this change in the Swift CHANGELOG or the Xcode 9 release notes, but of course I may have overlooked something.

Any insights on how/where this translation works, and what made it change between Swift 3 and Swift 4 are welcome.

I believe the mapping in this case is defined by the associated .apinotes file for the AppKit framework. From the linked read-me:

API notes provide a mechanism by which Objective-C APIs can be annotated with additional semantic information not present within the original Objective-C headers. This semantic information can then be used by the Swift compiler when importing the corresponding Objective-C module to provide a better mapping of Objective-C APIs into Swift.

The apinotes for AppKit can be found at the following path:

Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/System/Library/Frameworks/AppKit.framework/Versions/C/Headers/AppKit.apinotes

In this case, the print: selector for NSView has an entry for Swift version 3 that has the old mapping of print(_:):

---
Name: AppKit
SwiftVersions:
- Version: 3
  Classes:
    [...]
  - Name: NSView
    Methods:
    - Selector: "print:"
      MethodKind: Instance
      SwiftName: print(_:)

and a main entry that maps to printView(_:):

Classes:
- Name: NSView
  Methods:
  - Selector: "print:"
    MethodKind: Instance
    SwiftName: printView(_:)
4 Likes

That is the missing link, thanks!!! – I assume that the AppKit.apinotes file is not part of the Swift open source?

And – now knowing that the change is AppKit related – I found it documented in AppKit Release Notes for macOS 10.13:

print() methods in Swift

NSWindow, NSView, NSDocument’s print() instance methods have been renamed to printWindow(), printView(), and printDocument() respectively in Swift 4. This fixes the unexpected experience where adding debug logging to a subclass of one of these instances shows a print panel instead.

1 Like

Correct, it's a part of the macOS SDK itself – glad to be of help :)