I'm just starting out trying sqlite.swift and databases with swift. I have prepared a database with tables and preloaded with data. I wish to select data and insert data from within the app.
The problem is that I don't understand where (in my project) to put my database.db file in order for the app to find it.
my connection code:
let path = NSSearchPathForDirectoriesInDomains(
.documentDirectory, .userDomainMask, true
).first!
do {
db = try Connection("\(path)/database.db")
} catch {
db = nil
print ("Unable to open database")
}
In terms of where this file should go, I would suggest the “application support directory”. See File System Programming Guide: Where You Should Put Your App’s Files, which says:
Put user data in Documents/. User data generally includes any files you might want to expose to the user—anything you might want the user to create, import, delete or edit. For a drawing app, user data includes any graphic files the user might create. For a text editor, it includes the text files. Video and audio apps may even include files that the user has downloaded to watch or listen to later.
Put app-created support files in the Library/Application support/ directory. In general, this directory includes files that the app uses to run but that should remain hidden from the user. This directory can also include data files, configuration files, templates and modified versions of resources loaded from the app bundle.
Also see the iOS Storage Best Practices video.
The above is for iOS. If inquiring about macOS, see File System Programming Guide: The Library Directory Stores App-Specific Files.
But regardless of the OS, the technique for referencing the application support directory is largely the same:
do {
let fileURL = try FileManager.default
.url(for: .applicationSupportDirectory, in: .userDomainMask, appropriateFor: nil, create: true)
.appendingPathComponent("database.db")
db = try Connection(fileURL.path)
} catch {
db = nil
print("Unable to open database: \(error)")
}
Related
Very new to MacOS development (as in, completely new). I've developed a MacOS app (SwiftUI / Swift) and now figuring out a very things related to deployment.
My app generates a text file, but I'd like to save it within the app's folder (or whatever it is called) - and not in a user specified folder, and read it when I want. I can read resources from the Assets.xcassets but I'd like to be able to save as well without making the user choose a location.
Is there a way I can write/read from the app folder (I'm struggling to explain as I'm very unfamiliar with this system)?
Yes you can create a directory inside your application support folder, name it with app’s bundle identifier or your company and store all files that are not accessible to the user there:
Use this directory to store all app data files except those associated
with the user’s documents. For example, you might use this directory
to store app-created data files, configuration files, templates, or
other fixed or modifiable resources that are managed by the app. An
app might use this directory to store a modifiable copy of resources
contained initially in the app’s bundle. A game might use this
directory to store new levels purchased by the user and downloaded
from a server. All content in this directory should be placed in a
custom subdirectory whose name is that of your app’s bundle identifier
or your company.
You should take some time and read the File System Basics documentation
do {
let applicationSupport = FileManager.default.urls(for: .applicationSupportDirectory, in: .userDomainMask).first!
let bundleID = Bundle.main.bundleIdentifier ?? "company name"
let appSupportSubDirectory = applicationSupport.appendingPathComponent(bundleID,isDirectory: true)
try FileManager.default.createDirectory(at: appSupportSubDirectory, withIntermediateDirectories: true, attributes: nil)
print(appSupportSubDirectory.path) // /Users/.../Library/Application Support/YourBundleIdentifier
} catch {
print(error)
}
Very new to MacOS development (as in, completely new). I've developed a MacOS app (SwiftUI / Swift) and now figuring out a very things related to deployment.
My app generates a text file, but I'd like to save it within the app's folder (or whatever it is called) - and not in a user specified folder, and read it when I want. I can read resources from the Assets.xcassets but I'd like to be able to save as well without making the user choose a location.
Is there a way I can write/read from the app folder (I'm struggling to explain as I'm very unfamiliar with this system)?
Yes you can create a directory inside your application support folder, name it with app’s bundle identifier or your company and store all files that are not accessible to the user there:
Use this directory to store all app data files except those associated
with the user’s documents. For example, you might use this directory
to store app-created data files, configuration files, templates, or
other fixed or modifiable resources that are managed by the app. An
app might use this directory to store a modifiable copy of resources
contained initially in the app’s bundle. A game might use this
directory to store new levels purchased by the user and downloaded
from a server. All content in this directory should be placed in a
custom subdirectory whose name is that of your app’s bundle identifier
or your company.
You should take some time and read the File System Basics documentation
do {
let applicationSupport = FileManager.default.urls(for: .applicationSupportDirectory, in: .userDomainMask).first!
let bundleID = Bundle.main.bundleIdentifier ?? "company name"
let appSupportSubDirectory = applicationSupport.appendingPathComponent(bundleID,isDirectory: true)
try FileManager.default.createDirectory(at: appSupportSubDirectory, withIntermediateDirectories: true, attributes: nil)
print(appSupportSubDirectory.path) // /Users/.../Library/Application Support/YourBundleIdentifier
} catch {
print(error)
}
I am trying to access a specific folder in a remote URL e.g.http://dev.servertest.com/sessions/id/video
from there, I want to grab all the videos from the folder and download them to the device.
I know how to download the videos from a remote URL to the directory but I can't work out to grab all the videos from the specific video folder.
Also, the server may change depending on the user using their own server but the rest of the structure should be the same "/sessions/id/video"
Below is the code I use to upload from a specific folder "ImportVideos" from my app directory if that helps.
func loadVideos(){
let fm = FileManager.default
let dirPaths = fm.urls(for: .documentDirectory, in: .userDomainMask)
let documentsPath = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0];
do {
let videoList = try fm.contentsOfDirectory(atPath: "\(documentsPath + "/ImportVideo")")
for filename in videoList {
videoSubtitles.append(filename) //this is used to populate my tableview
}
} catch let error {
print("error: \(error.localizedDescription)")
}
}
If someone could point me in the right direction that would be great. Thanks.
The HTTP protocol does not provide any means of getting a list of files in a directory. What you're trying to do is not generally possible without a manifest — a list of files that you want to download.
The easiest way to do that is to run a script on the server, e.g.
#!/bin/sh
FILES_DIR=/path/to/directory/on/server
cd "$FILES_DIR"
ls > allfiles.txt
Then have your app fetch the file http://example.com/path/to/allfiles.txt, then split it by newline, and fetch each file. This approach also provides the advantage of letting you later replace that text file with a script handler that serves different file lists to different clients, if desired, e.g. for supporting different versions of your app.
Alternatively, if your server supports WebDAV, then it is possible to configure the directory with WebDAV enabled and use a WebDAV library to find out what files are in the directory. However, this is probably not a good idea, because WebDAV is relatively complex and easy to misconfigure.
Finally, some web servers provide a way to enable "directory listings" — a web page that has links to all of the files in the directory. (Many people will tell you that this is a bad idea from a security perspective, though that is debatable.) It is possible, though inherently fragile, to parse such a page and extract the links. This approach is strongly discouraged, however, because it could break completely when you update to a new version of the web server software.
I have (finally) managed to get prototype app using Core Data to persist to an sqlite file. Quitting and restarting I see the same data. So all seems well.
I want to now start from scratch again so I went to delete the sqlite persisted data. I set up it's location as :
open lazy var applicationDocumentsDirectory: NSURL = {
// The directory the application uses to store the Core Data store file.
let urls = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)
return urls[urls.count-1] as NSURL
}()
let url = self.applicationDocumentsDirectory.appendingPathComponent("TrainingDiary.sqlite")
which places the .sqlite files in ~/Library/Containers/uk.me.stevenlord.Core-Data-Binding/Data/Documents
There are four files in there: iChats, TrainingDiary.sqlite, TrainingDiary.sqlite-shm and TrainingDiary.sqlite-wal
I close my app. Delete all there files. When I reopen my app the full Core Data model is still there and when I look back in this directory the files are back.
What am I missing ?
EDIT:
I've figured out whats happening though I still don't quite understand why this is how it works. The above code specifies where the Core Data should be saved:
which places the .sqlite files in
~/Library/Containers/uk.me.stevenlord.Core-Data-Binding/Data/Documents/TrainingDiary.sqlite
This it does however I've now found that the app also saves the following
~/Library/Containers/uk.me.stevenlord.Core-Data-Binding/Data/Library/Application Support/Core Data Binding/Core_Data_Binding.sqlite
My XCode9 project is called "Core Data Binding". If I delete this file and start up my app I get an app with no data as expected.
So the persistent store is not going to where I specified. So still confused.
I'm missing something still. But something different
I am writing a simple 3D program that creates some models I need to save. I can easily save and open the model:
if let dir = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first {
let path = dir.appendingPathComponent(file)
sceneView.scene.write(to: path, options: nil, delegate: nil, progressHandler: nil)
}
But where can I get the model out of iOS? (For images I used to save to Photo Album and the user can get the files from there, but what about 3D models?)
Probably the quickest solution would be to save the file out to an iCloud storage directory, using the UIDocument classes. Apple has some generation documentation on it at https://developer.apple.com/library/content/documentation/General/Conceptual/iCloudDesignGuide/Chapters/DesigningForDocumentsIniCloud.html.
Alternatives include writing to Dropbox or other cloud services (OneDrive, GoogleDrive, etc) using one of those SDK's for direct write access.