I have created an app using Swift 3 and Xcode 8.3.3 that records audio files and saves them to the app's Document directory. I would now like to save these files to iCloud to have them backed up. I have been able to save a simple record to iCloud using this code:
let database = CKContainer.default().publicCloudDatabase
func saveToCloud(myContent: String){
let myRecord = CKRecord(recordType: "AudioRecording")
myRecord.setValue(myContent, forKey: "content")
database.save(myRecord) { (record, error) in
print(error ?? "No error")
guard record != nil else {return}
print("Saved record to iCloud")
}
}
It seems like I should just need to add a line of code that would look something like this:
newNote.setValue(audioObject, forKey: "Audio")
But I'm not sure what object I need to pass it for audioObject and if iCloud will be able to handle the object. Any suggestions?
Using iOS 10.x Swift 3.0
You would save your audioObject as a blob of data; or in iCloud speak, an asset. Here is some basic code that saves an image, but it is the same principle, just a blob of data.
There is quite a bit more code here than you really need but I left it in to keep it all in context.
func files_saveImage(imageUUID2Save: String) {
var localChanges:[CKRecord] = []
let image2updated = sharedDataAccess.image2Cloud[imageUUID2Save]
let newRecordID = CKRecordID(recordName: imageUUID2Save)
let newRecord = CKRecord(recordType: "Image", recordID: newRecordID)
let theLinkID = CKReference(recordID: sharedDataAccess.iCloudID, action: .deleteSelf)
let thePath = sharedDataAccess.fnGet(index2seek: sharedDataAccess.currentSN)
newRecord["theLink"] = theLinkID
newRecord["theImageNo"] = image2updated?.imageI as CKRecordValue?
newRecord["theImagePath"] = sharedDataAccess.fnGet(index2seek: image2updated?.imageS as! Int) as CKRecordValue?
newRecord["theUUID"] = imageUUID2Save as CKRecordValue?
let theURL = NSURL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(NSUUID().uuidString+".dat")
do {
try image2updated?.imageD.write(to: theURL!)
} catch let e as NSError {
print("Error! \(e)");
return
}
newRecord["theImageBlob"] = CKAsset(fileURL: URL(string: (theURL?.absoluteString)!)!)
localChanges.append(newRecord)
let records2Erase:[CKRecordID] = []
let saveRecordsOperation = CKModifyRecordsOperation(recordsToSave: localChanges, recordIDsToDelete: records2Erase)
saveRecordsOperation.savePolicy = .changedKeys
saveRecordsOperation.perRecordCompletionBlock = { record, error in
if error != nil {
print(error!.localizedDescription)
}
// deal with conflicts
// set completionHandler of wrapper operation if it's the case
}
saveRecordsOperation.modifyRecordsCompletionBlock = { savedRecords, deletedRecordIDs, error in
self.theApp.isNetworkActivityIndicatorVisible = false
if error != nil {
print(error!.localizedDescription, error!)
} else {
print("ok")
}
}
saveRecordsOperation.qualityOfService = .background
privateDB.add(saveRecordsOperation)
theApp.isNetworkActivityIndicatorVisible = true
}
When you want to go the other way around, you decode your blob from iCloud with code like this snipit.
let imageAsset = record["theImageBlob"] as? CKAsset
if let _ = imageAsset {
if let data = NSData(contentsOf: (imageAsset?.fileURL)!) {
imageObject = data
}
}
Obviously again this example is dealing with image data, but you and I know its all data :) no mater what colour it is.
The only cavet here is speed, I am pretty sure assets are kept in a different forest to your run-of-the-mill iCloud objects, and accessing them can be a tad slower.
This is the same exact process if you wanted to save/read a video file
Here is how to write an audio file. Save it as a CKAsset:
func save(audioURL: URL) {
let record = CKRecord(recordType: "YourType")
let fileURL = URL(fileURLWithPath: audioURL.path)
let asset = CKAsset(fileURL: fileURL)
record["audioAsset"] = asset
CKContainer.default().publicCloudDatabase.save(record) { (record, err) in
if let err = err {
print(err.localizedDescription)
return
}
if let record = record { return }
print("saved: ", record.recordID)
}
}
Here is how to read the audio file from a CKAsset:
func fetchAudioAsset(with recordID: CKRecord.ID) {
CKContainer.default().publicCloudDatabase.fetch(withRecordID: recordID) {
[weak self](record, err) in
DispatchQueue.main.async {
if let err = err {
print(err.localizedDescription)
return
}
if let record = record { return }
guard let audioAsset = record["audioAsset"] as? CKAsset else { return }
guard let audioURL = audioAsset.fileURL else { return }
do {
self?.audioPlayer = try AVAudioPlayer(contentsOf: audioURL)
} catch {
print(error.localizedDescription)
}
}
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With