Trouble fetching database path - swift

Integrated SQLITE Database, below is my code which I have written,
AppDelegate.swift
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
self.copyDatabaseIfNeeded()
return true
}
func copyDatabaseIfNeeded() {
let fileManager = FileManager.default
let dbPath = getDBPath()
var success: Bool = fileManager.fileExists(atPath: dbPath!)
if !success {
let defaultDBPath = URL(fileURLWithPath: Bundle.main.resourcePath ?? "").appendingPathComponent(APPLICATION_DB).absoluteString
success = ((try?fileManager.copyItem(atPath: defaultDBPath, toPath: dbPath!)) != nil)
if !success {
print("Failed to create writable database!")
}
}
}
func getDBPath() -> String? {
let paths = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)
let documentsDir = paths[0]
return URL(fileURLWithPath: documentsDir).appendingPathComponent(APPLICATION_DB).absoluteString
}
It always print below output,
Tried clean + Build Project
Uninstall the application, reinstall it
Remove derived data
none of the above has worked.
Also, my sqlite file is there in project target -> Build Phases -> Copy Bundle Resources : below screenshot for reference.
I am not sure whether hierarchy of my file matters or not, attaching screenshot of that as well.
Can anyone help me why I am getting issue in fetching file path of my database file?

Try this.
func copyDatabaseIfNeeded() {
// Move database file from bundle to documents folder
let fileManager = FileManager.default
let documentsUrl = fileManager.urls(for: .documentDirectory,
in: .userDomainMask)
guard documentsUrl.count != 0 else {
return // Could not find documents URL
}
let finalDatabaseURL = documentsUrl.first!.appendingPathComponent("SQL.sqlite")
if !( (try? finalDatabaseURL.checkResourceIsReachable()) ?? false) {
print("DB does not exist in documents folder")
let documentsURL = Bundle.main.resourceURL?.appendingPathComponent("SQL.sqlite")
do {
try fileManager.copyItem(atPath: (documentsURL?.path)!, toPath: finalDatabaseURL.path)
} catch let error as NSError {
print("Couldn't copy file to final location! Error:\(error.description)")
}
} else {
print("Database file found at path: \(finalDatabaseURL.path)")
}
}

Related

How to pre-load Core Data with a SQLite file that have references to images that were saved using "external storage"?

My goal is pre-loading Core Data, at the first app launch. So far I ran a simulation and filled Core Data with data. (I had checked "allow external Storage").
I went into application_support and copied: MyApp.sqlite-wal, MyApp.sqlite-shm, .MyApp_SUPPORT/_EXTERNAL_DATA/ and MyApp.sqlite.
Then I added the MyApp.sqlite file in my app bundle and added this code in my app delegate:
lazy var persistentContainer: NSPersistentContainer = {
let modelName = "MyApp"
var container: NSPersistentContainer!
container = NSPersistentContainer(name: modelName)
// Preloading
let appName: String = "MyApp"
var persistentStoreDescriptions: NSPersistentStoreDescription
let storeUrl = self.getDocumentsDirectory().appendingPathComponent("MyApp.sqlite")
if !FileManager.default.fileExists(atPath: (storeUrl.path)) {
let seededDataUrl = Bundle.main.url(forResource: appName, withExtension: "sqlite")
try! FileManager.default.copyItem(at: seededDataUrl!, to: storeUrl)
}
let description = NSPersistentStoreDescription()
description.shouldInferMappingModelAutomatically = true
description.shouldMigrateStoreAutomatically = true
description.url = storeUrl
container.persistentStoreDescriptions = [description]
//End Preloading
container.loadPersistentStores(completionHandler: { (storeDescription, error) in
if let error = error as NSError? {
fatalError("Unresolved error \(error), \(error.userInfo)")
}
})
return container
}()
It works but It looks like it doesn't find the images that were saved in external storage. They're present in .MyApp_SUPPORT/_EXTERNAL_DATA as references.
Where should I add the references?
Load everything is my goal.
If you have a file named MyApp.sqlite with external binary storage in some directory (here, the app bundle), Core Data puts those files in a sub-directory named .MyApp_SUPPORT/_EXTERNAL_DATA/. You need to recursively copy that directory and everything in its sub-directories.
Using that path is not a good idea, though, because it's undocumented and could change without warning. Also, this will miss MyApp.sqlite-wal and MyApp.sqlite-shm, if they exist.
A better idea is to put the seed store in a custom directory of its own, and copy everything from that directory. Instead of just having MyApp.sqlite, you'd have a directory named MyAppSeedData which would contain MyApp.sqlite. It would also contain all the other stuff Core Data needs like the external binary files. Use the same FileManager function to copy the MyAppSeedData directory (because it will recursively copy every file) and you should be fine.
The code to copy the folder would be something like this:
if let sourceDirURL = Bundle.main.url(forResource: "Source Folder", withExtension: nil) {
let destinationDirURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!.appendingPathComponent("TestFolder")
if !FileManager.default.fileExists(atPath: destinationDirURL.path) {
do {
try FileManager.default.copyItem(at: sourceDirURL, to: destinationDirURL)
} catch {
print("Error copying directory: \(error)")
}
}
}
You could then add the SQLite file name to the end of destinationDirURL and use it for Core Data.
Step 1: Create "MyAppSeedData" dir and paste MyApp.sqlite, the MyApp_SUPPORT, the MyApp.sqilte-smh, MyApp.sqilte-wal files inside.
Step 2: Drag MyAppSeedData to the bundle under AppDelegate and tick the box add target.
Step 3: These functions must be in AppDelegate file:
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool
{
//If first launch condition == true {
seedData()
//}
return true
}
func seedData() {
let fm = FileManager.default
//Destination URL: Application Folder
let libURL = fm.urls(for: .libraryDirectory, in: .userDomainMask).first!
let destFolder = libURL.appendingPathComponent("Application Support").path
//Or
//let l1 = NSSearchPathForDirectoriesInDomains(.applicationSupportDirectory, .userDomainMask, true).last!
//
//Starting URL: MyAppSeedData dir
let folderPath = Bundle.main.resourceURL!.appendingPathComponent("MyAppSeedData").path
let fileManager = FileManager.default
let urls = fileManager.urls(for: .applicationSupportDirectory, in: .userDomainMask)
if let applicationSupportURL = urls.last {
do{
try fileManager.createDirectory(at: applicationSupportURL, withIntermediateDirectories: true, attributes: nil)
}
catch{
print(error)
}
}
copyFiles(pathFromBundle: folderPath, pathDestDocs: destFolder)
}
func copyFiles(pathFromBundle : String, pathDestDocs: String) {
let fm = FileManager.default
do {
let filelist = try fm.contentsOfDirectory(atPath: pathFromBundle)
let fileDestList = try fm.contentsOfDirectory(atPath: pathDestDocs)
for filename in fileDestList {
try FileManager.default.removeItem(atPath: "\(pathDestDocs)/\(filename)")
}
for filename in filelist {
try? fm.copyItem(atPath: "\(pathFromBundle)/\(filename)", toPath: "\(pathDestDocs)/\(filename)")
}
} catch {
print("Error info: \(error)")
}
}
// MARK: - Core Data stack
lazy var persistentContainer: NSPersistentContainer = {
let modelName = "MyApp"
var container: NSPersistentContainer!
container = NSPersistentContainer(name: modelName)
container.loadPersistentStores(completionHandler: { (storeDescription, error) in
if let error = error as NSError? {
fatalError("Unresolved error \(error), \(error.userInfo)")
}
})
return container
}()

Is it possible to load images recovered from a server in runtime into a plane object?

I have been asked to build an app that shows a catalog with AR, so what I need to do is pretty simple: when an user chooses a product I must load the image recovered in base64 from the server into a plane object. Is this possible with swift - arkit ? Or are all the sprites/images/textures required to be previously loaded into the assets folder?
You can definitely download resources from a server, save them to the device (e.g in NSDocumentsDirectory), and then load with the file URL. I do it for a similar use case as yours -at least it sounds so, per the description you gave-
EDIT
Here's the relevant code. I use Alamofire to download from the server and ZIPFoundation for unzipping. I believe that if you just need to download an image, it'll be a bit simpler, probably not needing the unzip part.
let modelsDirectory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0]
func loadNodeWithID(_ id: String, completion: #escaping (SCNNode?) -> Void) {
// Check that assets for that model are not already downloaded
let fileManager = FileManager.default
let dirForModel = modelsDirectory.appendingPathComponent(id)
let dirExists = fileManager.fileExists(atPath: dirForModel.path)
if dirExists {
completion(loadNodeWithIdFromDisk(id))
} else {
let dumbURL = "http://yourserver/yourfile.zip"
downloadZip(from: dumbURL, at: id) {
if let url = $0 {
print("Downloaded and unzipped at: \(url.absoluteString)")
completion(self.loadNodeWithIdFromDisk(id))
} else {
print("Something went wrong!")
completion(nil)
}
}
}
}
func loadNodeWithIdFromDisk(_ id: String) -> SCNNode? {
let fileManager = FileManager.default
let dirForModel = modelsDirectory.appendingPathComponent(id)
do {
let files = try fileManager.contentsOfDirectory(atPath: dirForModel.path)
if let objFile = files.first(where: { $0.hasSuffix(".obj") }) {
let objScene = try? SCNScene(url: dirForModel.appendingPathComponent(objFile), options: nil)
let objNode = objScene?.rootNode.firstChild()
return objNode
} else {
print("No obj file in directory: \(dirForModel.path)")
return nil
}
} catch {
print("Could not enumarate files or load scene: \(error)")
return nil
}
}
func downloadZip(from urlString: String, at destFileName: String, completion: ((URL?) -> Void)?) {
print("Downloading \(urlString)")
let fullDestName = destFileName + ".zip"
let destination: DownloadRequest.DownloadFileDestination = { _, _ in
let fileURL = modelsDirectory.appendingPathComponent(fullDestName)
return (fileURL, [.removePreviousFile, .createIntermediateDirectories])
}
Alamofire.download(urlString, to: destination).response { response in
let error = response.error
if error == nil {
if let filePath = response.destinationURL?.path {
let nStr = NSString(string: filePath)
let id = NSString(string: nStr.lastPathComponent).deletingPathExtension
print(response)
print("file downloaded at: \(filePath)")
let fileManager = FileManager()
let sourceURL = URL(fileURLWithPath: filePath)
var destinationURL = modelsDirectory
destinationURL.appendPathComponent(id)
do {
try fileManager.createDirectory(at: destinationURL, withIntermediateDirectories: true, attributes: nil)
try fileManager.unzipItem(at: sourceURL, to: destinationURL)
completion?(destinationURL)
} catch {
completion?(nil)
print("Extraction of ZIP archive failed with error: \(error)")
}
} else {
completion?(nil)
print("File path not found")
}
} else {
// Handle error
completion?(nil)
}
}
}

Existing Realm Database notworking in swift 3.1 xcode 8

I created the application use existing database realm 2.3.0 and swift 3.1 xcode 8.3.
But when I try to access the realm database. there is an error.
Could not access database: Error Domain=io.realm Code=2 "Unable to open a realm at path '/Users/dodipurnomo/Library/Developer/CoreSimulator/Devices/858C796B-CBA8-424B-9A97-0893304B758B/data/Containers/Data/Application/A2D910EE-AAC5-4836-9FE7-97F744E802E5/Documents/Conversio.realm': Unsupported Realm file format version." UserInfo={NSFilePath=/Users/dodipurnomo/Library/Developer/CoreSimulator/Devices/858C796B-CBA8-424B-9A97-0893304B758B/data/Containers/Data/Application/A2D910EE-AAC5-4836-9FE7-97F744E802E5/Documents/Conversio.realm,
Above is an error message when I try to execute the database.
As for the class to hendleing the database realm is as follows:
import RealmSwift
import UIKit
class DBManager{
//MARK: - Singleton shared intance
static let sharedIntance = DBManager()
//MARK: - overide init function in realm
static var realm: Realm {
get {
do {
let realm = try Realm()
return realm
}
catch {
print("Could not access database: ", error)
}
return self.realm
}
}
public static func write(realm: Realm, writeClosure: () -> ()) {
do {
try realm.write {
writeClosure()
}
} catch {
print("Could not write to database: ", error)
}
}
public static func query(realm: Realm,queryClosure: () -> ()){
}
func save(entityList: [Object], shouldUpdate update: Bool = false) {
DBManager.realm.beginWrite()
for entity in entityList {
if let key = type(of: entity).primaryKey(), let value = entity[key] , update {
if let existingObject = DBManager.realm.object(ofType: type(of: entity), forPrimaryKey: value as AnyObject) {
let relationships = existingObject.objectSchema.properties.filter {
$0.type == .array
}
for relationship in relationships {
if let newObjectRelationship = entity[relationship.name] as? ListBase , newObjectRelationship.count == 0 {
entity[relationship.name] = existingObject[relationship.name]
}
}
}
}
DBManager.realm.add(entity, update: update)
}
do {
try DBManager.realm.commitWrite()
} catch let writeError {
debugPrint("Unable to commit write: \(writeError)")
}
DBManager.realm.refresh()
}
}
And I set the Realm in appdelegate as follows:
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
let desPath = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true).first!
let fullDesPath = URL(fileURLWithPath: desPath).appendingPathComponent("Conversio.realm")
var config = Realm.Configuration()
config.deleteRealmIfMigrationNeeded = true
config.fileURL = fullDesPath
Realm.Configuration.defaultConfiguration = config
chekDB()
return true
}
//chek database
func chekDB() {
let bundleDB = Bundle.main.path(forResource: "Conversio", ofType: "realm")
let desPath = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true).first!
let fileManager = FileManager.default
let fullDesPath = URL(fileURLWithPath: desPath).appendingPathComponent("Conversio.realm")
let fullDestPathString = String(describing: fullDesPath)
if fileManager.fileExists(atPath: fullDesPath.path){
print("Database file is exis !")
print(fileManager.fileExists(atPath: bundleDB!))
}else{
do{
try fileManager.copyItem(atPath: bundleDB!, toPath: fullDesPath.path)
}catch{
print("error encured while copying file to directori \(fullDestPathString)")
}
}
}
The error message you're getting means that realm file was created with newer version of Realm, so update Realm to the latest version.
Also keep in mind if you open realm with Realm Browser that uses a newer version of realm it asks you to convert the file format. If you do that you can open this realm with older version of realm-cocoa.

Swift 3: Reading content of folder? [duplicate]

What is wrong with my code for getting the filenames in the document folder?
func listFilesFromDocumentsFolder() -> [NSString]?{
var theError = NSErrorPointer()
let dirs = NSSearchPathForDirectoriesInDomains(NSSearchPathDirectory.DocumentDirectory, NSSearchPathDomainMask.AllDomainsMask, true) as? [String]
if dirs != nil {
let dir = dirs![0] as NSString
let fileList = NSFileManager.defaultManager().contentsOfDirectoryAtPath(dir, error: theError) as [NSString]
return fileList
}else{
return nil
}
}
I thought I read the documents correctly and I am very sure about what is in the documents folder, but "fileList" does not show anything? "dir" shows the path to the folder.
Swift 5
do {
// Get the document directory url
let documentDirectory = try FileManager.default.url(
for: .documentDirectory,
in: .userDomainMask,
appropriateFor: nil,
create: true
)
print("documentDirectory", documentDirectory.path)
// Get the directory contents urls (including subfolders urls)
let directoryContents = try FileManager.default.contentsOfDirectory(
at: documentDirectory,
includingPropertiesForKeys: nil
)
print("directoryContents:", directoryContents.map { $0.localizedName ?? $0.lastPathComponent })
for url in directoryContents {
print(url.localizedName ?? url.lastPathComponent)
}
// if you would like to hide the file extension
for var url in directoryContents {
url.hasHiddenExtension = true
}
for url in directoryContents {
print(url.localizedName ?? url.lastPathComponent)
}
// if you want to get all mp3 files located at the documents directory:
let mp3s = directoryContents.filter(\.isMP3).map { $0.localizedName ?? $0.lastPathComponent }
print("mp3s:", mp3s)
} catch {
print(error)
}
You would need to add those extensions to your project
extension URL {
var typeIdentifier: String? { (try? resourceValues(forKeys: [.typeIdentifierKey]))?.typeIdentifier }
var isMP3: Bool { typeIdentifier == "public.mp3" }
var localizedName: String? { (try? resourceValues(forKeys: [.localizedNameKey]))?.localizedName }
var hasHiddenExtension: Bool {
get { (try? resourceValues(forKeys: [.hasHiddenExtensionKey]))?.hasHiddenExtension == true }
set {
var resourceValues = URLResourceValues()
resourceValues.hasHiddenExtension = newValue
try? setResourceValues(resourceValues)
}
}
}
This solution works with Swift 4 (Xcode 9.2) and also with Swift 5 (Xcode 10.2.1+):
let fileManager = FileManager.default
let documentsURL = fileManager.urls(for: .documentDirectory, in: .userDomainMask)[0]
do {
let fileURLs = try fileManager.contentsOfDirectory(at: documentsURL, includingPropertiesForKeys: nil)
// process files
} catch {
print("Error while enumerating files \(documentsURL.path): \(error.localizedDescription)")
}
Here's a reusable FileManager extension that also lets you skip or include hidden files in the results:
import Foundation
extension FileManager {
func urls(for directory: FileManager.SearchPathDirectory, skipsHiddenFiles: Bool = true ) -> [URL]? {
let documentsURL = urls(for: directory, in: .userDomainMask)[0]
let fileURLs = try? contentsOfDirectory(at: documentsURL, includingPropertiesForKeys: nil, options: skipsHiddenFiles ? .skipsHiddenFiles : [] )
return fileURLs
}
}
// Usage
print(FileManager.default.urls(for: .documentDirectory) ?? "none")
A shorter syntax for SWIFT 3
func listFilesFromDocumentsFolder() -> [String]?
{
let fileMngr = FileManager.default;
// Full path to documents directory
let docs = fileMngr.urls(for: .documentDirectory, in: .userDomainMask)[0].path
// List all contents of directory and return as [String] OR nil if failed
return try? fileMngr.contentsOfDirectory(atPath:docs)
}
Usage example:
override func viewDidLoad()
{
print(listFilesFromDocumentsFolder())
}
Tested on xCode 8.2.3 for iPhone 7 with iOS 10.2 & iPad with iOS 9.3
Apple states about NSSearchPathForDirectoriesInDomains(_:_:_:):
You should consider using the FileManager methods urls(for:in:) and url(for:in:appropriateFor:create:) which return URLs, which are the preferred format.
With Swift 5, FileManager has a method called contentsOfDirectory(at:includingPropertiesForKeys:options:). contentsOfDirectory(at:includingPropertiesForKeys:options:) has the following declaration:
Performs a shallow search of the specified directory and returns URLs for the contained items.
func contentsOfDirectory(at url: URL, includingPropertiesForKeys keys: [URLResourceKey]?, options mask: FileManager.DirectoryEnumerationOptions = []) throws -> [URL]
Therefore, in order to retrieve the urls of the files contained in documents directory, you can use the following code snippet that uses FileManager's urls(for:in:) and contentsOfDirectory(at:includingPropertiesForKeys:options:) methods:
guard let documentsDirectory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first else { return }
do {
let directoryContents = try FileManager.default.contentsOfDirectory(at: documentsDirectory, includingPropertiesForKeys: nil, options: [])
// Print the urls of the files contained in the documents directory
print(directoryContents)
} catch {
print("Could not search for urls of files in documents directory: \(error)")
}
As an example, the UIViewController implementation below shows how to save a file from app bundle to documents directory and how to get the urls of the files saved in documents directory:
import UIKit
class ViewController: UIViewController {
#IBAction func copyFile(_ sender: UIButton) {
// Get file url
guard let fileUrl = Bundle.main.url(forResource: "Movie", withExtension: "mov") else { return }
// Create a destination url in document directory for file
guard let documentsDirectory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first else { return }
let documentDirectoryFileUrl = documentsDirectory.appendingPathComponent("Movie.mov")
// Copy file to document directory
if !FileManager.default.fileExists(atPath: documentDirectoryFileUrl.path) {
do {
try FileManager.default.copyItem(at: fileUrl, to: documentDirectoryFileUrl)
print("Copy item succeeded")
} catch {
print("Could not copy file: \(error)")
}
}
}
#IBAction func displayUrls(_ sender: UIButton) {
guard let documentsDirectory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first else { return }
do {
let directoryContents = try FileManager.default.contentsOfDirectory(at: documentsDirectory, includingPropertiesForKeys: nil, options: [])
// Print the urls of the files contained in the documents directory
print(directoryContents) // may print [] or [file:///private/var/mobile/Containers/Data/Application/.../Documents/Movie.mov]
} catch {
print("Could not search for urls of files in documents directory: \(error)")
}
}
}
Simple and dynamic solution (Swift 5):
extension FileManager {
class func directoryUrl() -> URL? {
let paths = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)
return paths.first
}
class func allRecordedData() -> [URL]? {
if let documentsUrl = FileManager.directoryUrl() {
do {
let directoryContents = try FileManager.default.contentsOfDirectory(at: documentsUrl, includingPropertiesForKeys: nil)
return directoryContents.filter{ $0.pathExtension == "m4a" }
} catch {
return nil
}
}
return nil
}}
This code prints out all the directories and files in my documents directory:
Some modification of your function:
func listFilesFromDocumentsFolder() -> [String]
{
let dirs = NSSearchPathForDirectoriesInDomains(FileManager.SearchPathDirectory.documentDirectory, FileManager.SearchPathDomainMask.allDomainsMask, true)
if dirs != [] {
let dir = dirs[0]
let fileList = try! FileManager.default.contentsOfDirectory(atPath: dir)
return fileList
}else{
let fileList = [""]
return fileList
}
}
Which gets called by:
let fileManager:FileManager = FileManager.default
let fileList = listFilesFromDocumentsFolder()
let count = fileList.count
for i in 0..<count
{
if fileManager.fileExists(atPath: fileList[i]) != true
{
print("File is \(fileList[i])")
}
}
Swift 2.0 Compability
func listWithFilter () {
let fileManager = NSFileManager.defaultManager()
// We need just to get the documents folder url
let documentsUrl = fileManager.URLsForDirectory(.DocumentDirectory, inDomains: .UserDomainMask)[0] as NSURL
do {
// if you want to filter the directory contents you can do like this:
if let directoryUrls = try? NSFileManager.defaultManager().contentsOfDirectoryAtURL(documentsUrl, includingPropertiesForKeys: nil, options: NSDirectoryEnumerationOptions.SkipsSubdirectoryDescendants) {
print(directoryUrls)
........
}
}
}
OR
func listFiles() -> [String] {
var theError = NSErrorPointer()
let dirs = NSSearchPathForDirectoriesInDomains(NSSearchPathDirectory.DocumentDirectory, NSSearchPathDomainMask.AllDomainsMask, true) as? [String]
if dirs != nil {
let dir = dirs![0]
do {
let fileList = try NSFileManager.defaultManager().contentsOfDirectoryAtPath(dir)
return fileList as [String]
}catch {
}
}else{
let fileList = [""]
return fileList
}
let fileList = [""]
return fileList
}

How do I delete a file in my apps documents directory?

Given, a file of path [[self documentsDirectory] stringByAppendingPathComponent:#"myFiles/aFile.txt"], How do I delete a file in my apps documents directory?
NSFileManager is a very handy tool:
[[NSFileManager defaultManager] removeItemAtPath: pathToFile error: &error];
With Swift 3, FileManager has a method called removeItem(at:). removeItem(at:) has the following declaration:
func removeItem(at URL: URL) throws
Removes the file or directory at the specified URL.
The code fragment below shows how to delete a file using removeItem(at:):
do {
try FileManager.default.removeItem(at: fileUrl)
} catch {
print("Could not delete file: \(error)")
}
As a complete example, the following UIViewController subclass implementation shows how to copy a file from the app bundle to a specific url in the document directory, delete a file at a specific url in document directory and check if a file exists at a specific url in document directory:
import UIKit
class ViewController: UIViewController {
#IBAction func copyFile(_ sender: UIButton) {
// Get app bundle file url
guard let bundleFileUrl = Bundle.main.url(forResource: "Movie", withExtension: "mov") else { return }
// Create a destination url in document directory for file
guard let documentsDirectory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first else { return }
let documentDirectoryFileUrl = documentsDirectory.appendingPathComponent("Movie.mov")
// Copy bundle file to document directory
if !FileManager.default.fileExists(atPath: documentDirectoryFileUrl.path) {
do {
try FileManager.default.copyItem(at: bundleFileUrl, to: documentDirectoryFileUrl)
} catch {
print("Could not copy file: \(error)")
}
}
}
#IBAction func deleteFile(_ sender: UIButton) {
// Get destination url in document directory for file
guard let documentsDirectory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first else { return }
let documentDirectoryFileUrl = documentsDirectory.appendingPathComponent("Movie.mov")
// Delete file in document directory
if FileManager.default.fileExists(atPath: documentDirectoryFileUrl.path) {
do {
try FileManager.default.removeItem(at: documentDirectoryFileUrl)
} catch {
print("Could not delete file: \(error)")
}
}
}
#IBAction func checkIfFileExist(_ sender: UIButton) {
// Get destination url in document directory for file
guard let documentsDirectory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first else { return }
let outputUrl = documentsDirectory.appendingPathComponent("Movie.mov")
// Print if file exists in document directory or not
FileManager.default.fileExists(atPath: outputUrl.path) ? print("File exists") : print("File does not exist")
}
}
For Swift 3.x and Xcode 8.x
itemName - Name which you store the file in document directory
file extension - the extension of the file
func removeItemForDocument(itemName:String, fileExtension: String) {
let fileManager = FileManager.default
let NSDocumentDirectory = FileManager.SearchPathDirectory.documentDirectory
let NSUserDomainMask = FileManager.SearchPathDomainMask.userDomainMask
let paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, true)
guard let dirPath = paths.first else {
return
}
let filePath = "\(dirPath)/\(itemName).\(fileExtension)"
do {
try fileManager.removeItem(atPath: filePath)
} catch let error as NSError {
print(error.debugDescription)
}}