Bundle resource path is good; resource URL is nil

Narrative first, exhibits later…

Bundle calls that had previously gotten a resource URL from my iOS app's bundle now gets only nil. There is no Bundle or URL call that will return anything but nil. The file is conclusively present.



Environment

Xcode 11.7, targeting iOS 13.3, SwiftUI, Core Data (store deleted, coordinator reinitialized, obtained a moc, no change to the store).



Approach

I need to reconstruct my data, so I want to read a not-insanely-large JSON file. Before installing Xcode 11.7, this was no problem: Bundle would give me a URL for the file, nothing remarkable. That version of the read appears in the listing below after the /***...***/ line.

I'd let the project sit for a couple of weeks, during which I installed Xcode 11.7. (I'm allowing for the new version being a red herring.)

Now, Bundle$url(forResource:withExtension:) returns nil. I tried a number of workarounds and double-checks: The file is there, Bundle will supply a path string.

The path works, so I have a workaround, but this bothers me.



What I checked

  • Bundle$path(forResource:ofType:) returns a path that proves valid on the command line and in Finder.

  • Data can be recovered from that path.

  • Opening the .app package in Finder shows a file of that name in the top level of the package.

  • Same with the command line.

  • expr try FileManager.default.contentsOfDirectory(atPath: Bundle.main.bundlePath) on the LLDB command line shows the file name in the list. The file is there.

  • There was no way to initialize a URL from the path, URL(fileURLWithPath:), trying to get a URL for the bundle path… everything I could think of. Always nil.

  • Deleting all Simulator devices under ~Library did nothing.

  • Neither did removing and restoring the iPhone 8 simulator in the Devices and Simulators window.

  • Nor deleting DerivedData.

  • I routinely do sudo xcrun xcode-select -s /Applications/Xcode.app whenever I install a new Xcode.



Remaining confounders

  • When 11.7 opened the project, it downloaded and installed the Swift packages for Alamofire and KDTree.

  • The .app name has a space in it. Astonishing regression if that's it.

  • I haven't tried reproducing this in a fresh project, or the like. Gotta stop some time.



Code


Code Block
let countyMetadata: [CountyWithCentroid] = {
    var stage = "Path"
    do {
        let vanillaDecoder = JSONDecoder()
/****************** DOES WORK ******************/
        let pCentroidPath = Bundle.main
            .path(forResource:
"WithGeometryAndPopulation",
ofType: "json")
// =>
/*
/Users/fritza/Library/Developer/CoreSimulator/Devices/65C9CC3A-9A49-4131-BF4C-535702B73559/data/Containers/Bundle/Application/908E5688-04A5-417B-BF4B-3C482735E25B/County Trends.app/WithGeometryAndPopulation.json
*/
        let pData = FileManager.default
.contents(atPath: pCentroidPath!)
// => 1_585_677 bytes
        let pCentroidRecords = try vanillaDecoder
            .decode([CountyWithCentroid].self,
from: pData!)
// => 3140 elements
/******************* HAD WORKED ******************/
        stage = "URL"
        let cCentroidURL = Bundle.main
.url(forResource:
"WithGeometryAndPopulation",
withExtension: "json")
// => nil
        let cCentroidData = try Data(contentsOf: cCentroidURL!)
// => Dereference of nil.
        let cCentroidRecords = try vanillaDecoder
            .decode([CountyWithCentroid].self, from: cCentroidData)
        return cCentroidRecords
    }
    catch {
// ...
    }
    return []
}()

Replies

Oops, sorry: This has manifested on simulators for both iPhone 8 and iPhone 11, both running iOS 13.7.
Are ou sure you have the case correct? Modern versions of the simulator will enforce this because that’s how a real device works. For example, consider this code:

Code Block
let uOK = Bundle.main.url(forResource: "test", withExtension: "txt")
print(uOK?.path ?? "nil")
// prints: /Users/quinn/Library/Developer/CoreSimulator/Devices/53941C37-F3F2-4E69-A3D1-B747B554027C/data/Containers/Bundle/Application/CFE33B34-AB29-4F39-B118-C15C0212EDDF/xxsi.app/test.txt
let uNG = Bundle.main.url(forResource: "Test", withExtension: "txt")
print(uNG?.path ?? "nil")
// prints: nil


Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@apple.com"