Valid File Path for Archiverootobject and Unarchiverootobject

Valid file path for archiverootobject and unarchiverootobject

You can save it to a subdirectory folder named with your bundleID inside the application support folder or you can also save it to the preferences folder located inside the library directory:

let preferencesDirectoryURL = FileManager.default.urls(for: .libraryDirectory, in: .userDomainMask).first!.appendingPathComponent("Preferences", isDirectory: true)
let fileURL = preferencesDirectoryURL.appendingPathComponent("fileName.plist")
print(fileURL.path) // "/var/folders/.../Library/Preferences/fileName.plist

How to get the url for a video saved in temporary directory

Since you don't seem to want your file to be visible to users or persisted between app launches, the Temporary directory sounds perfectly fine for your use case:

var tempVideoFileUrl: URL {
return FileManager.default.temporaryDirectory.appendingPathComponent("my_video_name")
}

func storeVideoToTemporaryFolder(videoData: Data) {
guard !FileManager.default.fileExists(atPath: tempVideoFileUrl.path) else {
return
}
do {
try videoData.write(to: tempVideoFileUrl)
}
catch {
fatalError()
}
}

func loadVideoFromTemporaryFolder() -> Data? {
if let data = try? Data(contentsOf: tempVideoFileUrl) {
return data
}
return nil
}

Worth mentioning though, the system may (and most likely will) purge this directory after the app is exited. It's recommended that you remove any temporary directories/files after they're no longer needed.

So in your case, you can simply remove it once you finished uploading to Firebase Storage:

func deleteVideoFromTemporaryFolder() {
do {
try FileManager.default.removeItem(at: videoFileUrl)
}
catch {
fatalError()
}
}

If you prefer to keep your file around between app launches though, you could use Application Support directory. But since Application Support and Documents directories gets automatically backed up, you may want to exclude your file from iCloud backup by setting its URL's isExcludedFromBackupKey key:

var applicationSupportVideoFileUrl: URL {
let applicationSupportFolderUrl = try! FileManager.default.url(for: .applicationSupportDirectory, in: .userDomainMask, appropriateFor: nil, create: true)
return applicationSupportFolderUrl.appendingPathComponent("my_video_name")
}

func excludeFromCloudBackup(url: URL) {
var targetUrl = url
var isAlreadyExcludedFromBackup: Bool
do {
let storedRessourceValues = try targetUrl.resourceValues(forKeys: [URLResourceKey.isExcludedFromBackupKey])
isAlreadyExcludedFromBackup = storedRessourceValues.isExcludedFromBackup ?? false
}
catch {
fatalError()
}
guard !isAlreadyExcludedFromBackup else {
return
}
var ressourceValues = URLResourceValues()
ressourceValues.isExcludedFromBackup = true
do {
try targetUrl.setResourceValues(ressourceValues)
}
catch {
fatalError()
}
}

Edit: To get the data from your PHAsset, this should work:

import Photos

func loadVideoData(phAsset: PHAsset, completion: @escaping (Data?)->()) {
guard phAsset.mediaType == .video else {
return completion(nil)
}
let options = PHVideoRequestOptions()
options.isNetworkAccessAllowed = true
options.deliveryMode = .highQualityFormat
PHCachingImageManager().requestAVAsset(forVideo: phAsset, options: options) { (avAsset, _, _) in
guard let avUrlAsset = avAsset as? AVURLAsset else {
return
}
var videoData: Data?
do {
videoData = try Data(contentsOf: avUrlAsset.url)
} catch {
fatalError()
}
DispatchQueue.main.async {
completion(videoData)
}
}
}

Then simply call this method and store your video in the Temporary folder:

loadVideoData(phAsset: yourPhAsset) { [weak self] videoData in
guard let strongSelf = self else { return }
guard let videoData = videoData else {
return
}
strongSelf.storeVideoToTemporaryFolder(videoData: videoData)
}

Saving array using NSUserDefaults crashes app

Looks like your code should work fine even with some really weird forced casting going on in your decoder method. Try like this:

class Task: NSObject, NSCoding {
var name = String()
var notes = String()
var date: NSDate
var taskCompleted: Bool
init(name: String, notes: String, date: NSDate, taskCompleted: Bool){
self.name = name
self.notes = notes
self.date = date
self.taskCompleted = taskCompleted
}
required init(coder decoder: NSCoder){
self.name = decoder.decodeObjectForKey("name") as! String
self.notes = decoder.decodeObjectForKey("notes") as! String
self.date = decoder.decodeObjectForKey("date") as! NSDate
self.taskCompleted = decoder.decodeBoolForKey("taskCompleted")
}
func encodeWithCoder(coder: NSCoder) {
coder.encodeObject(name, forKey: "name")
coder.encodeObject(notes, forKey: "notes")
coder.encodeObject(date, forKey: "date")
coder.encodeBool(taskCompleted, forKey: "taskCompleted")
}
}

Testing with plist files:

let task1 = Task(name: "task1", notes: "note a", date: NSDate(), taskCompleted: false)
let task2 = Task(name: "task2", notes: "note b", date: NSDate(), taskCompleted: true)

let documentsDirectory = NSFileManager.defaultManager().URLsForDirectory(.DocumentDirectory, inDomains: .UserDomainMask).first!
let fileURL = documentsDirectory.URLByAppendingPathComponent("data.plist")

if let filePath = fileURL.path {
NSKeyedArchiver.archiveRootObject([task1,task2], toFile: filePath)
if let loadedArray = NSKeyedUnarchiver.unarchiveObjectWithFile(filePath) as? [Task] {
print(loadedArray.count)

print(loadedArray.first?.name ?? "")
print(loadedArray.first?.notes ?? "")
print(loadedArray.first!.date )
print(loadedArray.first!.taskCompleted)

print(loadedArray.last?.name ?? "")
print(loadedArray.last?.notes ?? "")
print(loadedArray.last!.date )
print(loadedArray.last!.taskCompleted)
}
}

Retrieve array function not working

The value of the parameter toFile in the method archiveRootObject and the parameter in unarchiveObjectWithFile must be a valid file path..

archiveRootObject returns true if the operation was successful, otherwise false



Related Topics



Leave a reply



Submit