How to access related files in the Mac Sandbox

I’m building an app which needs to load Objective C files.
If the user gives me access to the ‘.m’ file, I need to be able to open the ‘.h’ file.

You don’t get this ability without a bit of a dance. I didn’t find any clear tutorial or example, so I’m adding one now.

Firstly – define the related filetypes that you want to access by adding the file extension to document types in your info.plist
Here, I have added h as an an extension type, and set NSIsRelatedItemType to true.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "">
<plist version="1.0">
            <string>Header File</string>

Now, you can access the file – but only by using a FilePresenter.
And the file presenter _must_ be registered with NSFileCoordinator

class RelatedFilePresenter: NSObject, NSFilePresenter {
    var primaryPresentedItemURL: URL?
    var presentedItemURL: URL?
    var presentedItemOperationQueue: OperationQueue = OperationQueue.main
    enum Fail:Error {
        case unableToConstrucURL
    init(primaryItemURL: URL) {
        self.primaryPresentedItemURL = primaryItemURL

    func readDataFromRelated(fileExtension:String,
                             completion:(Result<Data, Error>)->Void) {
        presentedItemURL = primaryPresentedItemURL?.deletingPathExtension().appendingPathExtension(fileExtension)
        guard let url = presentedItemURL else {
        let fc = NSFileCoordinator(filePresenter: self)
        var error:NSError?
        fc.coordinate(readingItemAt: url,
                      options: .withoutChanges,
                      error: &error) { (url) in
            do {
                let data = try Data(contentsOf: url, options: .uncached)
            } catch  {
        if let error {

This class provides a method to read the data from a related file, but you could adapt it for any other operation.

You can then read the data with something like

let filePresenter = RelatedFilePresenter(primaryItemURL: mFileURL)
filePresenter.readDataFromRelated(fileExtension: "h") { result in
    if case .success(let data) = result {
        //do something with data