Empty Core Data Sqlite Database in mail attachment - swift

I am trying to export Core Data Local Sqlite Database from iPhone to System through mail.
I can see .sqlite database as attachment. But it is empty, no data in any table.
I am doing this with below code.
if MFMailComposeViewController.canSendMail(){
let composer = MFMailComposeViewController()
composer.setToRecipients(["test#gmail.com"])
composer.setSubject("Sending Local Database File")
composer.setMessageBody("Hello,\nPlease find the attached local database file in this email.\n and Kindly check it and let us know.", isHTML: false)
composer.mailComposeDelegate = self
let documentsDirectory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!
let fileURL = documentsDirectory.appendingPathComponent("Project.sqlite")
print("Database File URL is - \(fileURL)")
do {
let attachmentData = try Data(contentsOf: fileURL)
composer.addAttachmentData(attachmentData, mimeType: "application/x-sqlite3", fileName: "Project.sqlite")
self.present(composer, animated: true)
} catch {
print(error)
}
}
Or is there any way to export core data sqlite database from app other than connecting device to MAC or Any system through cable (except iTunes/XCode)?
can we export it directly from app?

Related

Permission error when saving to documentDirectory

I am trying to save favourites to document directory, the code works fine when I run it in simulator however when I build it to my device I am getting the following error.
You don’t have permission to save the file
“Documents.LikedDepartments” in the folder
“F36073C0-AC1E-46CA-BC1E-E03F9F316E1D”.
Also it might be worth noting that when I change use .cachesDirectory instead of .documentDirectory it works fine.
How can I grant write access for the documents directory ?
import Foundation
extension FileManager {
static var documentsDirectory: URL {
let paths = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)
print(paths)
return paths[0]
}
}
let savePath = FileManager.documentsDirectory.appendingPathExtension("LikedDepartments")
func save() {
let favourites = calculateFavourites()
do {
let data = try JSONEncoder().encode(favourites)
try data.write(to:savePath, options: [.atomic, .completeFileProtection])
} catch {
print("\(error)")
}
}
Cool file extension .LikedDepartments
Use appendingPathComponent instead.
https://developer.apple.com/documentation/foundation/nsstring/1417069-appendingpathcomponent

Swift - Zip Files from directory without creating a directory inside zip directory

I'm working with Swift 5.0 and I want to zip 3 files without installing additional dependencies.
Currently I'm able to zip these 3 Files, which all are in the same "root" directory. But if I open the created and exported zip-file (final.zip), than I get the folder (root) in which the 3 files were saved. I don't want this "root" folder. I want to see my data directly inside the final.zip
Below is my code. Can someone help me out?
let fm = FileManager.default
let baseDirectoryUrl = fm.urls(for: .documentDirectory, in: .userDomainMask).first!.appendingPathComponent("root", isDirectory: true)
if !manager.fileExists(atPath: baseDirectoryUrl.relativePath) {
try! manager.createDirectory(
at: baseDirectoryUrl,
withIntermediateDirectories: true,
attributes: nil
)
}
// path of data
let data1_path = baseDirectoryUrl.appendingPathComponent("data1.vec3")
let data2_path = baseDirectoryUrl.appendingPathComponent("data2.vec3")
let data3_path = baseDirectoryUrl.appendingPathComponent("data3.json")
// write wData1 to data1_path
try! wData1.write(to: data1_path)
// write wData2 to data2_path
try! wData2.write(to: data2_path)
// write wData3 to data3_path
try! wData3.write(to: data3_path)
// this will hold the URL of the zip file
var archiveUrl: URL?
// if we encounter an error, store it here
var error: NSError?
let coordinator = NSFileCoordinator()
// zip up the root directory
// this method is synchronous and the block will be executed before it returns
// if the method fails, the block will not be executed though
// if you expect the archiving process to take long, execute it on another queue
coordinator.coordinate(readingItemAt: baseDirectoryUrl, options: [.forUploading], error: &error) { (zipUrl) in
// zipUrl points to the zip file created by the coordinator
// zipUrl is valid only until the end of this block, so we move the file to a temporary folder
let tmpUrl = try! fm.url(
for: .itemReplacementDirectory,
in: .userDomainMask,
appropriateFor: zipUrl,
create: true
).appendingPathComponent("export.zip", isDirectory: false)
try! fm.copyItem(at: zipUrl, to: tmpUrl)
// store the URL so we can use it outside the block
archiveUrl = tmpUrl
}
if let archiveUrl = archiveUrl {
// bring up the share sheet so we can send the archive with AirDrop for example
let avc = UIActivityViewController(activityItems: [archiveUrl], applicationActivities: nil)
avc.popoverPresentationController?.barButtonItem = navigationItem.rightBarButtonItem
present(avc, animated: true)
} else {
print(error)
}
You can use this zip package in your app with shouldKeepParent: false
https://github.com/weichsel/ZIPFoundation#in-memory-archives

How to save video data to document directory in swift?

I want to save video data to document directory.
I know how to create document directory my folder.
But how to save data that document directory??
let fileManager = FileManager.default
if let tDocumentDirectory = fileManager.urls(for: .documentDirectory, in: .userDomainMask).first {
let filePath = tDocumentDirectory.appendingPathComponent("\(FOLDER_NAME)")
if !fileManager.fileExists(atPath: filePath.path) {
do {
try fileManager.createDirectory(atPath: filePath.path, withIntermediateDirectories: true, attributes: nil)
} catch {
print("Couldn't create document directory")
}
}
print("Document directory is \(filePath)")
}
Now, I have (FOLDER_NAME) folder. But How to save video data to (FOLDER_NAME) folder??
And How to I get saved video file path?
I apologize for my stupidity.
In your Info.plist, add the following permissions:
Supports opening documents in place: YES
Application supports iTunes file sharing: YES
let videoFilename = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0] + "/" + getFileName() //return your filename from the getFileName function
videoNSData.write(toFile: videoFilename, atomically: true)
Then, inside Files, you can get a folder named with your app name, where you can access your saved video file (with the specified filename).

Save audio files from remote URL and load them locally in AKPlayer

There are arrays of MP3 files on remote URL. What I'd like to try is to temporarily and selectively save them on user's device and play them with Audio Player (I'm experimenting with Audiokit's AKPlayer). Here's what I've written:
guard let remote = URL(string: "http://myserver.com/test.mp3"),
let data = NSData(contentsOf: remote) else {
AKLog("Remote failed to load.")
return
}
let cachedFile = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first as URL?
try? data.write(to: remote)
let player = AKPlayer(url: cachedFile!)
AudioKit.output = player
try? AudioKit.start()
This code only works when I assign AudioPlayer's url at local files. But in this version, it says "failed call=ExtAudioFileOpenURL((CFURLRef)fileURL, &_extAudioFile". I am kind of stuck understanding downloading and loading remote files. Could anybody inform me about this? Much appreciated. <3

How can I read a file in a swift playground

Im trying to read a text file using a Swift playground with the following
let dirs : String[]? = NSSearchPathForDirectoriesInDomains(NSSearchPathDirectory.DocumentDirectory, NSSearchPathDomainMask.UserDomainMask, true) as? String[]
if (dirs != nil) {
let directories:String[] = dirs!;
let dir = directories[0]; //documents directory
let path = dir.stringByAppendingPathComponent(file);
//read
let content = String.stringWithContentsOfFile(path, encoding: NSUTF8StringEncoding, error: nil)
}
However this fails with no error. It seems the first line stops the playground from outputting anything below
You can also put your file into your playground's resources. To do this: show Project Navigator with CMD + 1. Drag and drop your file into the resources folder. Then read the file:
On Xcode 6.4 and Swift 1.2:
var error: NSError?
let fileURL = NSBundle.mainBundle().URLForResource("Input", withExtension: "txt")
let content = String(contentsOfURL: fileURL!, encoding: NSUTF8StringEncoding, error: &error)
On Xcode 7 and Swift 2:
let fileURL = NSBundle.mainBundle().URLForResource("Input", withExtension: "txt")
let content = try String(contentsOfURL: fileURL!, encoding: NSUTF8StringEncoding)
On Xcode 8 and Swift 3:
let fileURL = Bundle.main.url(forResource: "Input", withExtension: "txt")
let content = try String(contentsOf: fileURL!, encoding: String.Encoding.utf8)
If the file has binary data, you can use NSData(contentsOfURL: fileURL!) or Data(contentsOf: fileURL!) (for Swift 3).
While the answer has been supplied for a quick fix, there is a better solution.
Each time the playground is opened it will be assigned a new container. This means using the normal directory structure you would have to copy the file you want into the new container every time.
Instead, inside the container there is a symbolic link to a Shared Playground Data directory (/Users/UserName/Documents/Shared Playground Data) which remains when reopening the playground, and can be accessed from multiple playgrounds.
You can use XCPlayground to access this shared folder.
import XCPlayground
let path = XCPlaygroundSharedDataDirectoryURL.appendingPathComponent("foo.txt")
The official documentation can be found here: XCPlayground Module Reference
Cool post on how to organize this directory per-playground: Swift, Playgrounds, and XCPlayground
UPDATE: For swift 4.2 use playgroundSharedDataDirectory. Don't need to import anything.
Looks like:
let path = playgroundSharedDataDirectory.appendingPathComponent("file")
1. Access a file that is located in the Resources folder of your Playground
With Swift 3, Bundle has a method called url(forResource:withExtension:). url(forResource:withExtension:) has the following declaration:
func url(forResource name: String?, withExtension ext: String?) -> URL?
Returns the file URL for the resource identified by the specified name and file extension.
You can use url(forResource:withExtension:) in order to read the content of a json file located in the Resources folder of an iOS or Mac Playground:
import Foundation
do {
guard let fileUrl = Bundle.main.url(forResource: "Data", withExtension: "json") else { fatalError() }
let data = try Data(contentsOf: fileUrl)
let json = try JSONSerialization.jsonObject(with: data, options: [])
print(json)
} catch {
print(error)
}
You can use url(forResource:withExtension:) in order to read the content of a text file located in the Resources folder of an iOS or Mac Playground:
import Foundation
do {
guard let fileUrl = Bundle.main.url(forResource: "Text", withExtension: "txt") else { fatalError() }
let text = try String(contentsOf: fileUrl, encoding: String.Encoding.utf8)
print(text)
} catch {
print(error)
}
As an alternative to let image = UIImage(named: "image"), you can use url(forResource:withExtension:) in order to access an image located in the Resources folder of an iOS Playground:
import UIKit
do {
guard let fileUrl = Bundle.main.url(forResource: "Image", withExtension: "png") else { fatalError() }
let data = try Data(contentsOf: fileUrl)
let image = UIImage(data: data)
} catch {
print(error)
}
2. Access a file that is located in the ~/Documents/Shared Playground Data folder of your computer
With Swift 3, PlaygroundSupport module provides a global constant called playgroundSharedDataDirectory. playgroundSharedDataDirectory has the following declaration:
let playgroundSharedDataDirectory: URL
The path to the directory containing data shared between all playgrounds.
You can use playgroundSharedDataDirectory in order to read the content of a json file located in the ~/Documents/Shared Playground Data folder of your computer from an iOS or Mac Playground:
import Foundation
import PlaygroundSupport
do {
let fileUrl = PlaygroundSupport.playgroundSharedDataDirectory.appendingPathComponent("Data.json")
let data = try Data(contentsOf: fileUrl)
let json = try JSONSerialization.jsonObject(with: data, options: [])
print(json)
} catch {
print(error)
}
You can use playgroundSharedDataDirectory in order to read the content of a text file located in the ~/Documents/Shared Playground Data folder of your computer from an iOS or Mac Playground:
import Foundation
import PlaygroundSupport
do {
let fileUrl = PlaygroundSupport.playgroundSharedDataDirectory.appendingPathComponent("Text.txt")
let text = try String(contentsOf: fileUrl, encoding: String.Encoding.utf8)
print(text)
} catch {
print(error)
}
You can use playgroundSharedDataDirectory in order to access an image located in the ~/Documents/Shared Playground Data folder of your computer from an iOS Playground:
import UIKit
import PlaygroundSupport
do {
let fileUrl = PlaygroundSupport.playgroundSharedDataDirectory.appendingPathComponent("Image.png")
let data = try Data(contentsOf: fileUrl)
let image = UIImage(data: data)
} catch {
print(error)
}
Swift 3 (Xcode 8)
The code below works in both iOS and macOS playgrounds. The text file ("MyText.txt" in this example) must be in the Resources directory of the playground. (Note: You may need to open the navigator window to see the directory structure of your playground.)
import Foundation
if let fileURL = Bundle.main.url(forResource:"MyText", withExtension: "txt")
{
do {
let contents = try String(contentsOf: fileURL, encoding: String.Encoding.utf8)
print(contents)
} catch {
print("Error: \(error.localizedDescription)")
}
} else {
print("No such file URL.")
}
This works for me. The only thing I changed was to be explicit about the file name (which is implied in your example) - perhaps you have a typo in the off-screen definition of the "file" variable?
let dirs = NSSearchPathForDirectoriesInDomains(NSSearchPathDirectory.DocumentDirectory, NSSearchPathDomainMask.UserDomainMask, true) as? [String]
let file = "trial.txt" // My change to your code - yours is presumably set off-screen
if let directories = dirs {
let dir = directories[0]; //documents directory
let path = dir.stringByAppendingPathComponent(file);
//read
let content = NSString(contentsOfFile: path, usedEncoding: nil, error: nil)
// works...
}
Update Swift 4.2
As #raistlin points out, this would now be
let dirs = NSSearchPathForDirectoriesInDomains(
FileManager.SearchPathDirectory.documentDirectory,
FileManager.SearchPathDomainMask.userDomainMask,
true)
or, more tersely:
let dirs = NSSearchPathForDirectoriesInDomains(.documentDirectory,
.userDomainMask, true)
Select the .playground file.
Open Utility inspector, In the playground press opt-cmd-1 to open the File Inspector. You should see the playground on the right. If you don't have it selected, press cmd-1 to open the Project Navigator and click on the playground file.
Under 'Resource Path' in Playground Settings choose 'Relative To Playground' and platform as OSX.
On Mavericks with Xcode 6.0.1 you can read using iOS platform too.
import UIKit
let dirs : [String]? = NSSearchPathForDirectoriesInDomains(NSSearchPathDirectory.DocumentDirectory, NSSearchPathDomainMask.UserDomainMask, true) as? [String]
let myDir = "/Shared Playground Data"
let file = "README.md" // My change to your code - yours is presumably set off-screen
if (dirs != nil) {
let directories:[String] = dirs!;
let dir = directories[0] + myDir; // iOS playground documents directory
let path = dir.stringByAppendingPathComponent(file);
//read
let content = String.stringWithContentsOfFile(path, encoding: NSUTF8StringEncoding, error: nil)
// works...
println(content!)
}
Remember, you need to create a directory called "Shared Playground Data" in your Documents directory. Im my case I used this command: mkdir "/Users/joao_parana/Documents/Shared Playground Data" and put there my file README.md
String.stringWithContentsOfFile is DEPRECATED and doesn't work anymore with Xcode 6.1.1
Create your documentDirectoryUrl
let documentDirectoryUrl = NSFileManager.defaultManager().URLsForDirectory(.DocumentDirectory, inDomains: .UserDomainMask).first! as NSURL
To make sure the file is located there you can use the finder command Go To Folder e copy paste the printed documentDirectoryUrl.path there
println(documentDirectoryUrl.path!)
// should look like this: /Users/userName/Library/Containers/com.apple.dt.playground.stub.OSX.PLAYGROUNDFILENAME-5AF5B25D-D0D1-4B51-A297-00015EE97F13/Data/Documents
Just append the file name to the folder url as a path component
let fileNameUrl = documentDirectoryUrl.URLByAppendingPathComponent("ReadMe.txt")
var fileOpenError:NSError?
Check if the file exists before attempting to open it
if NSFileManager.defaultManager().fileExistsAtPath(fileNameUrl.path!) {
if let fileContent = String(contentsOfURL: fileNameUrl, encoding: NSUTF8StringEncoding, error: &fileOpenError) {
println(fileContent) // prints ReadMe.txt contents if successful
} else {
if let fileOpenError = fileOpenError {
println(fileOpenError) // Error Domain=NSCocoaErrorDomain Code=XXX "The file “ReadMe.txt” couldn’t be opened because...."
}
}
} else {
println("file not found")
}
I was unable to read a file with ease in playground and ended up just creating a command line app in Xcode. This seemed to work for me very well.
The other answers, relying on "playgroundSharedDataDirectory" never works for me, especially if using an iOS playground.
let documentsDirectoryShareURL = PlaygroundSupport.playgroundSharedDataDirectory.absoluteURL
let fileManager = FileManager()
try? fileManager.copyItem(at: URL(fileURLWithPath: "/Users/rufus/Documents/Shared Playground Data/"), to: documentsDirectoryShareURL)
I just do the above now. I can populate my documents/shared folder, and it is just manually automatically copied to the playgrounds documents directory.
My code will not overwrite files that exist there. You could enhance this if you need it to look at file timestamps and then copy if necessary etc.
Swift 5.7.1 - Xcode 14.1
func readFile() -> [String] {
if let fileURL = Bundle.main.url(forResource: "File", withExtension: "txt") {
do {
let content = try String(contentsOf: fileURL)
var x = content.components(separatedBy: "\n")
x.removeAll { data in
data.isEmpty
}
return x
} catch {
print(error)
}
}
return [String]()
}
//Usage:
let input = readFile()