Accessing bundle resources

In my game app, I've been loading resources by building paths directly based on the Bundle resourcePath property, e.g. (error-handling omitted):


let path = "\(Bundle.main.resourcePath!)/data/text/example.txt"
do {
    let text =
        try String(contentsOfFile: path, encoding: String.Encoding.utf8)
} catch {
}


I have reasons for doing it this way having to do with a JavaScript scripting framework, and it's always worked fine.


However, I've seen multiple suggestions online to use URLs rather than strings for paths, and to use bundle functions such as url(forResource...) to acquire resource paths rather than building paths manually.


What I haven't found is an explanation of why it shouldn't be done the way I'm doing it. I understand that URLs offer features that string paths don't, but these features don't seem relevant for my particular use case. I could use URLs and the Bundle resourceURL property instead, but it still seems to be the case that building resource paths or URLs manually is discouraged, and that using functions such as url(forResource...) is recommended instead.


In short, my question is, is there actually anything wrong with using resourcePath or resourceURL in this way? Could this approach possibly fail in some circumstances? Why exactly is this approach discouraged?


I want to follow best practices, but I'd just like to have a better understanding of the underlying motivations behind these recommendations.


Edit: I should add that the resources in question aren't localized, so that isn't a factor in this particular case.

This was discussed in this thread:


https://forums.developer.apple.com/message/291601


It's by no means wrong to use paths, since they are intentionally "just" strings. If that's what you're conceptualizing, then go ahead. "Just" keep in mind that it's the strings that are subtly complex, not the paths. More so in Swift.


In the above code fragment, if you want to build a URL "manually", the best way is to go via URLComponents to add the relative path to the base URL.


Stepping up to url(forResource...) solves a different problem: it hardens your code against the case where resource files are automatically placed in various resource subdirectories according to type, when your app is built. In principle, the placement can depend on external factors such as target OS version. Using the higher-level API makes it not your problem to locate the correct subdirectory, and unifies your lookup code across types.

Thanks for your helpful reply.


My resources are stored in a folder hierarchy, e.g.:


data
  textures
    0.png
    1.png
    ...
  sounds
    0.wav
    1.wav
    ...


The entire data folder is added to the project and copied to the bundle as a whole in the 'Copy Bundle Resources' build phase. The bundle programming guide seems to suggest that creating custom subdirectories like this is ok.


If you think there's something fundamentally wrong with this approach, let me know.


Otherwise, it seems there are two issues at play. First is what you said about resources being automatically placed in different subdirectories during the build process. It seems like Apple's documentation gives good reason to think that if you've included a resource folder in your project, Xcode isn't going to disassemble it and store its contents differently. Let me know if you think I'm wrong about this.


The other issue is dealing with path components in string form. For example:


if let url = bundle.url(
    forResource: "example",
    withExtension: "txt",
    subdirectory: "data/text"
) { ... }


Here, even though you're using URLs and url(forResource...), you still have a fragment of a path ("data/text") in string form, including a path separator ("/").


In your other thread you mentioned possible issues related to character encoding. Is the above example using "data/text" unsafe? Could you perhaps give an example of the kind of thing that could go wrong when representing paths as strings?

>documentation gives good reason to think that if you've included a resource folder in your project, Xcode isn't going to disassemble it and store its contents


Noting this is in the cocoa forum...are you working on a macOS application?

Accessing bundle resources
 
 
Q