`NSBundle.mainBundle().URLForResource` always returns `nil` - ios

I am new to Swift and am using Xcode 6.
I am attempting to read data from the app's plist file, but it is not working.
The data.plist file is included in Xcode's Supporting Files group.
I am using the code below:
var dataList = NSDictionary(contentsOfURL:NSBundle.mainBundle().URLForResource("data", withExtension:"plist"))
however the NSURL:
NSBundle.mainBundle().URLForResource("data", withExtension:"plist")
always returns nil.
I don't know what is wrong.

Generally you would want to use this code to create your plist. This finds the the path to your plist and then moves it into the documents directory if it isn't already there. If you don't move it, you are not allowed to write to it, hence this chunk of code is vital. To fetch the information from the plist, use the second bit of code. Obviously if you have an array rather than a dictionary, you would have to alter it to deal with that.
var path = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true)[0] as NSString
path = path.stringByAppendingPathComponent("data.plist")
let fileManager = NSFileManager.defaultManager()
if !fileManager.fileExistsAtPath(path) {
let sourcePath = NSBundle.mainBundle().pathForResource("data", ofType: "plist")
fileManager.copyItemAtPath(sourcePath, toPath: path, error: nil)
}
.
let dict = NSMutableDictionary(contentsOfFile: path) as NSMutableDictionary

Related

How to read a multidimensional String Array from a plist in Swift?

I'm using the following code to save a 2D String array to a plist:
func saveFavourites(favouriteStops: [[String]]) {
let directories = NSSearchPathForDirectoriesInDomains(.libraryDirectory, .userDomainMask, true)
if let library = directories.first {
if let libraryUrl = URL(string: library) {
let favouritesUrl = libraryUrl.appendingPathComponent("favourites.plist")
// Write favourites to disk
let favsArray = favouriteStops as NSArray
print(favsArray)
favsArray.write(toFile: favouritesUrl.path, atomically: true)
}
}
}
The above snippet properly creates the .plist file (confirmed by looking at the simulator's filesystem in ~/Library/Developer/CoreServices). However, when I try reading it back to a NSArray with the following snippet, it results in nil:
let directories = NSSearchPathForDirectoriesInDomains(.libraryDirectory, .userDomainMask, true)
if let library = directories.first {
if let libraryUrl = URL(string: library) {
let favouritesUrl = libraryUrl.appendingPathComponent("favourites.plist")
// favsToLoad is nil
let favsToLoad = NSArray(contentsOf: favouritesUrl)
// Do stuff with favsToLoad, if it would load properly
}
}
You're doing two very basic things wrong.
First, never make a URL from a file path by saying URL(string); this is a file on disk, so you must use URL.fileURL.
Second, don't start with a file path at all! Obtain the directory as a URL right from the start.
(Also, though I do not know whether this is the source of the issue, do not read and write directly in the Library directory. Use the Documents directory, the Application Support directory, or similar.)
So, for example, I would write:
let fm = FileManager.default
let docsurl = try fm.url(for:.documentDirectory, in: .userDomainMask, appropriateFor: nil, create: false)
let favouritesurl = docsurl.appendingPathComponent("favourites.plist")
I see your problem. You misspelled "favorites". :)
But seriously...
Plists can only contain a very small set of "property list objects": (dictionaries, arrays, strings, numbers (integer and float), dates, binary data, and Boolean values).
If your array's "object graph" (the objects the array contains and any container objects inside the array recursively contain) contain anything other than the above types, the save will fail.
I don't honestly know what gets saved when it fails. Have you tried opening the plist file in a text editor and looking at it?
My guess is that something other than a string has snuck into your array, it's not one of the above types, and THAT'S why it's failing.

Cannot write to Documents folder on iOS10.3 using Swift3 [duplicate]

How is it possible?
let exists = NSFileManager.defaultManager().fileExistsAtPath(path.absoluteString)
print("exists: \(exists)") //false
This is path.absoluteString
//file:///Users/kuna/Library/Developer/CoreSimulator/Devices/92BD140D-5C14-43C4-80D6-904BB9594ED6/data/Containers/Data/Application/5B818832-BB19-4047-A7F8-1487F36868D6/Documents/wishlists/68/147/128/IMG_0006.PNG
And you can see it is there where it should be:
What is going on?
(The code in this answer has been updated for Swift 3 and later.)
Apparently your path variable is a NSURL (describing a file path). To get the path as
a string, use the path property, not absoluteString:
let exists = FileManager.default.fileExists(atPath: path.path)
absoluteString returns the URL in a string format, including
the file: scheme etc.
Example:
let url = URL(fileURLWithPath: "/path/to/foo.txt")
// This is what you did:
print(url.absoluteString)
// Output: file:///path/to/foo.txt
// This is what you want:
print(url.path)
// Output: /path/to/foo.txt
If you want to check if a path exist,you should check path
let url = NSURL(string: "balabala")
let path = url?.path
//Check path

filemanager.createFileAtPath works not correctly

I try to create a PLIST-File with the NSFileManager and the method createFileAtPath. In the end, the file was created, it has the size of 0 Bytes, and i even can see the specific PLIST-Icon for that file in the Finder.
But when i want to open it (for example with Xcode) it says:The data couldn't be read because it isn't in the correct format.
I want to write to this file but when its not in the correct format i can't do this.
There is something wrong with the File-creation but i don't know what it is.
I hope you can help me with this.
Here is my code:
pListPath = NSURL(fileURLWithPath: reportsPath.path!).URLByAppendingPathComponent("myReports.plist", isDirectory: false)
let data: NSData = NSData()
var isDir: ObjCBool = false
if fileManager.fileExistsAtPath(pListPath.path!, isDirectory: &isDir)
{
print("File already exits")
}
else
{
let success = fileManager.createFileAtPath(pListPath.path!, contents: data, attributes: nil)
print("Was file created?: \(success)")
print("plistPath: \(pListPath)")
}
reports.path = .../UserDir/.../Documents/Reports
Any help is highly appreciated.
filemanager.createFileAtPath works absolutely correctly,
but you're creating an empty file by writing an empty NSData object to disk.
NSData objects are not implicitly serialized to a property list.
Either use the NSPropertyListSerialization class or – simpler - write an empty dictionary to disk.
let dictionary = NSDictionary()
let success = dictionary.writeToURL(pListPath, atomically: true)
print("Was file created?: \(success)")
print("plistPath: \(pListPath)")
PS: you don't need to create an URL from an URL
pListPath = reportsPath.URLByAppendingPathComponent("myReports.plist", isDirectory: false)
but I recommend to use more descriptive variable names to distinguish String paths and NSURL e.g. pListURL and reportsURL

NSBundle.mainBundle().pathForResource returns nil

I am trying to write a simple IO wrapper for Swift.
To test this I have a file named "Test.txt" in my project root.
I have added this file to Build Phases within Build Bundle Resources, as suggested by everyone else who has had this problem.
I have implemented a very simple File class with one read function with the intent to output the contents of the file.
class File2{
let resourceName: String
let type: String
let bundle = NSBundle.mainBundle()
init(resourceName: String, type: String = "txt"){
self.resourceName = resourceName
self.type = type
println(self.bundle)
}
func read(){
let path = self.bundle.pathForResource("Test.txt", ofType: "txt") //Hard coded these in just to make sure Strings contained no whitespace
println(path) //This returns nil...why?
var error:NSError?
//print(String(contentsOfFile:path!, encoding:NSUTF8StringEncoding, error: &error)!)
//return String(contentsOfFile:path!, encoding:NSUTF8StringEncoding, error: &error)!
}
}
When I print the contents of the bundle I get a URI to a specific location on my filesystem, which I assume is the virtual location of the app in the simulator. Navigating to it reveals that it does indeed contain my "Test.txt" file.
Now all I want to do is get the path to that file.
I do this by calling: self.bundle.pathForResource("Test.txt", ofType: "txt")
This returns "nil"
Why? :)
Do not include the .txt in the name parameter, pass it as the extension parameter.
From the documentation:
extension
The filename extension of the file to locate.
If you specify an empty string or nil, the extension is assumed not to exist and the file is the first file encountered that exactly matches name.
Swift3
let bundle = Bundle.main
let path = bundle.path(forResource: "Test", ofType: "txt")
Swift1 & Swift2
let bundle = NSBundle.mainBundle()
let path = self.bundle.pathForResource("Test", ofType: "txt")
Objective-C
NSBundle* bundle = [NSBundle mainBundle];
NSString* path = [bundle pathForResource:#"Test" ofType:#"txt"];
In swift 3.0, write with
let path = Bundle.main.path(forResource: "Test", ofType: "txt")
Replace your
let path = self.bundle.pathForResource("Test.txt", ofType: "txt")
with
let path = NSBundle.mainBundle().pathForResource("Test", ofType: "txt")
Replace
let path = self.bundle.pathForResource("Test.txt", ofType: "txt")
with
let path = self.bundle.pathForResource("Test", ofType: "txt")
Another reason for NSBundle.mainBundle().pathForResource returns nil is file is not properly added to the target. When you drag and drop the file in bundle, please make sure that "Add To Target" checkbox and "Copy items if needed" checkbox is selected.
For those of you who are trying to access resources in Unit Tests, I faced a problem where the resource was not found in the main bundle and my solution was to search for the path in all bundles, this way I don't have to specify a bundle identifier, where fileName is a string passed into the function and of course the type can be anything you'd want.
NSString *path;
for (NSBundle *bundle in [NSBundle allBundles]) {
path = [bundle pathForResource:fileName ofType:#"json"];
if (path) {
break; // Here is your path.
}
}
The ofType parameter appended to the resource name, so replace this line:
let path = self.bundle.pathForResource("Test.txt", ofType: "txt")
to something like this:
let path = self.bundle.pathForResource("Test", ofType: "txt")
The Build Bundle Resources is also necessary to check.

NSlogging/println SQLite db file location in Swift

So I want to figure out where my swift IOS app is storing its SQLite db file. I know that the applicationsDocumentsDirectory stores the directory. I need to find a way to print it in the console or NSLog it. I am new to swift and IOS development so I'm having trouble here. I tried just calling the variable in another class and also just NSLogging it within the clojure with no success. Any ideas?
Here is the variable.
lazy var applicationDocumentsDirectory: NSURL = {
// The directory the application uses to store the Core Data store file. This code uses a directory named "arux-software.onsite_childcare" in the application's documents Application Support directory.
let urls = NSFileManager.defaultManager().URLsForDirectory(.DocumentDirectory, inDomains: .UserDomainMask)
return urls[urls.count-1] as NSURL
}()
There is an easier way to get the sqlite location:
println(NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true)[0] as NSString)
gives output with no time stamp like this:
/Users/tooti/Library/Developer/CoreSimulator/Devices/AB5B3350-F891-420B-88D5-E8F8E578D39B/data/Containers/Data/Application/38FBDC42-0D09-4A10-A767-17B576882117/Documents
And
NSLog(NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true)[0] as NSString )
gives output with a time stamp, like this:
2015-01-23 23:31:57.373 RAACTutor[6551:140531] /Users/tooti/Library/Developer/CoreSimulator/Devices/AB5B3350-F891-420B-88D5-E8F8E578D39B/data/Containers/Data/Application/38FBDC42-0D09-4A10-A767-17B576882117/Documents
You can do it in two ways.
First Way
1. we can get reference to the application document directory using NSSearchPathForDirectoriesInDomains() method.
let documentsPath = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true).last! as String
The constant .documentDirectory says we are looking for Document directory.
The constant .userDomaininMask to restrict our search to our application's sandbox.
Prefered way to refer to a file or directory is with a URL.
let documentsURL = URL(string: documentsPath)!
print(documentsURL)
Second Way
2. using FileManager.default.url function.
let fileManager = FileManager.default
do {
let documentsURL = try fileManager.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: true)
print(documentsURL)
} catch let error as NSError {
print("Could not save \(error), \(error.userInfo)")
}

Resources