简体   繁体   中英

Bundle.main.path(forResource:ofType:inDirectory:) returns nil

Try not to laugh or cry -- I'm just getting back into coding after 20 years out...

I've spent more than 4 hours looking at references and trying code snippets to get Bundle.main.path to open my text file so I can read in data for my app (my next step is to appropriately parse it).

if let filepath = Bundle.main.path(forResource: "newTest", ofType: "txt")
{
    do
    {
        let contents = try String(contentsOfFile: filepath)
        print(contents)

    }
    catch
    {
        print("Contents could not be loaded.")
    }
}
else
{
    print("newTest.txt not found.")
}

The result is: "newTest.txt not found." regardless of how I try to drag&drop the file into the project, create the file inside Xcode or use the File -> Add Files to... menu item.

The issue is that the file isn't being copied to your app bundle. To fix it:

  • Click your project
  • Click your target
  • Select Build Phases
  • Expand Copy Bundle Resources
  • Click '+' and select your file.

Double check the Options in the add files menu when adding the file. The target in Add to targets must be ticked to add it to the bundle:

In case you are actually in another bundle (test for instance), use:

guard let fileURL = Bundle(for: type(of: self)).url(forResource: fileName withExtension:"txt") else {
        fatalError("File not found")
}

Click on your file on your navigation panel and open the Right Panel/ Property Inspector.

在此处输入图片说明

Ensure that you add to target membership

Swift 3.0

let fileNmae = "demo"
        
let path = Bundle.main.path(forResource: fileName, ofType: "txt")
    do {
        let content = try String(contentsOfFile:path!, encoding: String.Encoding.utf8)
        print(content)
    } catch {
        print("nil")
    }

SWift 2.0

do{
      if let path = NSBundle.mainBundle().pathForResource("YOURTXTFILENAME", ofType: "txt"){
             let data = try String(contentsOfFile:path, encoding: NSUTF8StringEncoding)
             let myStrings = data.componentsSeparatedByCharactersInSet(NSCharacterSet.newlineCharacterSet())
              print(myStrings)
       }
  } catch let err as NSError {
            //do sth with Error
            print(err)
  }

Output :

Hello Hems
Good Morning
I m here for you dude.
Happy Coding.

It's crazy how much time such a simple problem can cost.

Some answers here helped me but I always tried:

Bundle.main.url(forResource: selectedTitle, withExtension: "mp3")

For some reason that doesn't work, but getting the path and translating it to a URL afterwards works:

let path = Bundle.main.path(forResource: selectedTitle, ofType: "mp3")
let url = URL(fileURLWithPath: path!)

Ah, so just found myself dealing with the exact same problem as the OP.

The problem is that the solutions given here and here do not work when the code is being executed in a playground, since the Options menu of add files looks different for it does not show the Add to targets field:

在此处输入图片说明

When inside a .playground file, instead press the Hide or show the Navigator button on the top-right of your Xcode window (visual impression)--> 在此处输入图片说明

Then, once the Navigator folds open on the left-side of the Xcode window, simply drag & drop your file to the Resources directory of your playground.

If your setup looks anything like the following you should be ok:

在此处输入图片说明

This was helpful for me: xcode - copy a folder structure into my app bundle

Mark "create folder references" option when you create assets in nested folders.

Then find path to the file like this:

let path = Bundle(for: type(of : self)).path(forResource: "some_folder_a/some_folder_b/response.json", ofType: nil)

Same problem, slightly different situation & solution. I'm following a tutorial that said to use the following code:

    // Start the background music:
    if let musicPath = Bundle.main.path(forResource:
        "Sound/BackgroundMusic.m4a", ofType: nil) {
        print("SHOULD HEAR MUSIC NOW")
        let url = URL(fileURLWithPath: musicPath)

        do {
            musicPlayer = try AVAudioPlayer(contentsOf: url)
            musicPlayer.numberOfLoops = -1
            musicPlayer.prepareToPlay()
            musicPlayer.play()
        }
        catch { print("Couldn't load music file") }
    }
}

I had the same issue as others but none of the solutions fixed the issue. After experimenting, all I did was remove Sound from the path in the following call and everything worked:

Bundle.main.path(forResource: "BackgroundMusic.m4a", ofType: nil)

It would seem that the tutorial was in error by telling me to include Sound in the path.

I added file.txt to my project and it was automatically added to the Copy Bundle Files of my project. For me, I had to remove the extension from the forResource and it worked.

let path = Bundle.main.path(forResource: "file", ofType: "txt") // not forResource: "file.txt"

I think you don't want the inDirectory: method. Try this instead:

if let filepath = Bundle.main.path(forResource: "newTest", ofType: "txt") {

My problem was in one module, created with Cocoapods. Every pod install/update, the files (json files) were there in the project, but never were find inside the Bundle. After pod install/update, I removed (deleted references) the files and add again to the project.

Always pay attention to target where you add the files.

The answer is simply to not use Assets.xcassets to store your audio file, and add your audio file, ie) BeTheFirstAudio.m4a (made with QuickTime), directly to the PROJECT NAVIGATOR (circled, pink) list of files (photo 1)

在此处输入图片说明

WARNING! Be sure to check the "CREATE GROUPS" and "ADD TO TARGETS" checkboxes when the pop-up appears after dragging your audio file from your Finder window.

在此处输入图片说明

After that, your code should work to play the audio (including .m4a extensions from QuickTime)

 import AVFoundation

 class AudioPlayer: NSObject {


     private var audioPlayer: AVAudioPlayer!

     override init() {
         super.init()
    
         // get URL for the default audio
         let audioURL = Bundle.main.url(forResource: "BeTheFirstAudio", withExtension: "m4a")

         audioPlayer = try! AVAudioPlayer(contentsOf: audioURL!)
     }

Apple engineers should be ashamed that this problem is even a question in StackOverflow; developers should be able to add the audio file to Assets.xcassets and Bundle.main.url should be able to find it. The fact that this simple concept is difficult has probably cost a lot of time for developers. Attention @Apple

If you are using R.swift try this:

I was still having issues specially with a plist file that got changed during build times and since my project is using R.swift I changed the code to be

Bundle.main.path(forResource: R.file.myplistfile)

and that worked like a charm.

Worth to mention

If you are running unit test or ui test, use their bundle id. Because they are not using main bundle, so you would never find your file by calling Bundle.main.path(forResource: "newTest", ofType: "txt") .

Use your test target bundle id. In my case I'm trying to read data from a CSV file. Replace TestReadFileUITests with your class name which extends from XCTestCase .

Here is the actual bundle id used when I run a UI test case. You could see it is not from main bundle.

(lldb) po testBundle
NSBundle </Users/zhouhaibo/Library/Developer/CoreSimulator/Devices/448D1FCB-8311-4D3F-BEEF-934052C3470F/data/Containers/Bundle/Application/905C2326-8313-410F-9DC2-9D84B9C6D757/TestReadFileUITests-Runner.app/PlugIns/TestReadFileUITests.xctest> (loaded)

(lldb) po filePath
"/Users/zhouhaibo/Library/Developer/CoreSimulator/Devices/448D1FCB-8311-4D3F-BEEF-934052C3470F/data/Containers/Bundle/Application/905C2326-8313-410F-9DC2-9D84B9C6D757/TestReadFileUITests-Runner.app/PlugIns/TestReadFileUITests.xctest/Patients_2022-09-02.csv"
let testBundle = Bundle(for: TestReadFileUITests.self)
guard let filePath = testBundle.path(forResource: fileName, ofType: fileType) else {
    print("CSV file not found.")
    return [:]
}
class TestReadFileUITests: XCTestCase {

    func testDemo() {
        let _ = DataManager.readData()
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM