I'm creating an app that allows the user to upload text and an image either taken from library or from the camera and uploads to parse. I get the text to upload no problem but it only will upload the image to parse 1 in 20 tries. Any thoughts? I've posted my code.
#IBAction func saveData(sender: AnyObject) {
var imageText = messageText.text
var uploadDate = NSDate()
let formatter = NSDateFormatter()
formatter.timeStyle = .MediumStyle
formatter.stringFromDate(uploadDate)
if messageText.text == nil {
print("Image not uploaded")
}else {
var posts = PFObject(className: "Memento")
posts["imageText"] = imageText
posts["uploadTime"] = uploadDate
posts["uploader"] = PFUser.currentUser()
posts.saveInBackgroundWithBlock({
(success: Bool, error: NSError?) -> Void in
if error == nil {
var imageData = UIImagePNGRepresentation(self.imagePreview.image!)
var parseImageFile = PFFile(name: "uploaded_image.png", data: imageData!)
posts["imageFile"] = parseImageFile
posts.saveInBackgroundWithBlock({
(success: Bool, error: NSError?) -> Void in
if error == nil {
print("data uploaded")
self.performSegueWithIdentifier("saveHome", sender: self)
}else {
print(error)
}
})
} else {
print(error)
}
})
}
}
Make sure to save the image file to Parse as well as adding it to your posts object.
#IBAction func saveData(sender: AnyObject) {
var imageText = messageText.text
var uploadDate = NSDate()
let formatter = NSDateFormatter()
formatter.timeStyle = .MediumStyle
formatter.stringFromDate(uploadDate)
if messageText.text == nil {
print("Image not uploaded")
} else {
// Save the image
//var imageData = UIImagePNGRepresentation(self.imagePreview.image!)
//var parseImageFile = PFFile(name: "uploaded_image.png", data: imageData!)
var parseImageFile = PFFile(name: "uploaded_image.jpg", data: UIImageJPEGRepresentation(self.imagePreview.image!, 0.6)!)!
parseImageFile.saveInBackgroundWithBlock { (success: Bool, error: NSError?) -> Void in
if (success) {
println("picture saved")
} else {
// Log details of the failure
println("Picture Save Error: \(error!) \(error!.userInfo)")
}
}
// Then save your posts object
var posts = PFObject(className: "Memento")
posts["imageText"] = imageText
posts["uploadTime"] = uploadDate
posts["uploader"] = PFUser.currentUser()
posts["imageFile"] = parseImageFile
posts.saveInBackgroundWithBlock({
(success: Bool, error: NSError?) -> Void in
if error == nil {
print("data uploaded")
self.performSegueWithIdentifier("saveHome", sender: self)
} else {
// Log details of the failure
println("Picture Save Error: \(error!) \(error!.userInfo)")
}
})
}
}
Related
Good evening,
I have run into the issue of getting the following error message from Cloudkit when trying to save a record to the public database:
"Server Rejected Request" (15/2027); server message = "Custom zones are not allowed in public DB";
I have been able to find the issue causing this error. Within this application I need to fetch zone changes on the private database so I have had to save my records to a custom zone in order to accomplish that fetch.
The following code is where I am saving to the custom zone on the private database:
let zoneID = CKManager.defaultManager.sharedZone?.zoneID
let deckSetToBeSaved = deckName.deckToCKRecord(zoneID)
privateDatabase.save(deckSetToBeSaved) { (record, error) in
DispatchQueue.main.async {
if let record = record {
deckName.cKRecordToDeck(record)
try? self.managedContext.save()
}
}
print("New record saved")
print(error as Any)
}
}
Here is my code for saving a record to the public database:
func shareDeckPlan(_ deck: Deck, completion: #escaping (Bool, NSError?) -> Void ) {
var records = [CKRecord]()
let deckRecord = deck.deckToCKRecord()
records.append(deckRecord)
let reference = CKReference(record: deckRecord, action: .deleteSelf)
for index in deck.cards {
let cardRecord = index.cardToCKRecord()
cardRecord["deck"] = reference
records.append(cardRecord)
}
let operation = CKModifyRecordsOperation(recordsToSave: records, recordIDsToDelete: nil)
operation.modifyRecordsCompletionBlock = {(savedRecords, deletedIDs, error) in
if error == nil {
DispatchQueue.main.async(execute: {
if let savedRecords = savedRecords {
for record in savedRecords {
if record.recordID.recordName == deck.ckRecordID {
deck.cKRecordToDeck(record)
}
for cards in deck.cards {
if record.recordID.recordName == cards.ckRecordID {
cards.ckRecordToCard(record)
}
}
}
}
let _ = try? self.managedContext.save()
DispatchQueue.main.async(execute: {
completion(true, error as NSError?)
})
})
} else {
DispatchQueue.main.async(execute: {
print(error!)
completion(false, error as NSError?)
})
}
}
operation.qualityOfService = .userInitiated
self.publicDatabase.add(operation)
}
The following code referes to the deckToCKRecord method:
func deckToCKRecord(_ zoneID:CKRecordZoneID? = nil) -> CKRecord {
let deckSetName: CKRecord
if let ckMetaData = ckMetaData {
let unarchiver = NSKeyedUnarchiver(forReadingWith: ckMetaData as Data)
unarchiver.requiresSecureCoding = true
deckSetName = CKRecord(coder: unarchiver)!
}
else {
if let zoneID = zoneID {
deckSetName = CKRecord(recordType: "Deck", zoneID: zoneID)
self.ckRecordID = deckSetName.recordID.recordName
} else {
deckSetName = CKRecord(recordType: "Deck")
self.ckRecordID = deckSetName.recordID.recordName
}
}
deckSetName["name"] = name! as CKRecordValue
deckSetName["cardCount"] = cards.count as CKRecordValue
return deckSetName
}
How can I save a record both to the private database in a custom zone and the public database successfully?
I am using the following code to attempt to create a shared private record:
#IBAction func testPress(_ sender: Any) {
let customZone = CKRecordZone(zoneName: "ShareZone")
let friendRecord = CKRecord(recordType: "Share", zoneID: customZone.zoneID)
let rootRecord = CKRecord(recordType: "Root", zoneID: customZone.zoneID)
model.privateDB.delete(withRecordZoneID: customZone.zoneID) { (nil, error) in
self.model.privateDB.save(customZone) { (nil, error) in
print("Custom Zone Error = \(error)")
self.model.privateDB.save(friendRecord, completionHandler: { (nil, error) in
self.model.privateDB.save(rootRecord, completionHandler: { (nil, error) in
self.shareTest(record: friendRecord, root: rootRecord)
})
})
}
}
}
func shareTest(record:CKRecord, root:CKRecord) {
record["Name"] = "Test" as CKRecordValue?
root["Name"] = "Test" as CKRecordValue?
let ckContainer = CKContainer.default()
let shareRecord = CKShare(rootRecord: root, share: record.recordID)
shareRecord[CKShareTitleKey] = "Name" as CKRecordValue?
let shareController = UICloudSharingController(share: shareRecord, container: ckContainer)
shareController.delegate = self
shareController.availablePermissions = [.allowReadOnly]
self.present(shareController, animated: false)
}
However I am returning the error when I press on a way to share the link:
CKError 0x6000002535f0: "Invalid Arguments" (12); "An added share is being saved without its rootRecord (CKRecordID: 0x608000224560; recordName=C0ADC819-57F7-4D99-A527-B21590F506AB, zoneID=ShareZone:defaultOwner)"
I looked at this answer Link who was having the same problem, but do not quite know how to get their solution to work as they didn't provide enough details.
Does anyone know what I am doing wrong?
I believe the error message is telling you need to save the share and root record at the same time.
let modifyRecordsOperation = CKModifyRecordsOperation( recordsToSave: [record, share], recordIDsToDelete: nil)
You should do this operation in the completion handler of the sharingController.
sharingController = UICloudSharingController {
controller, preparationCompletionHandler in
Edit: Your code would look something like this not tested code:
#IBAction func testPress(_ sender: Any) {
let privatedatabase = CKContainer.default().privateCloudDatabase
let newZoneName = UUID().uuidString
let recordZone = CKRecordZone(zoneName: "ShareZone")
privatedatabase.save(recordZone) { savedRecordZone, error in
if let error = error {
print("\(error.localizedDescription).")
} else if let savedRecordZone = savedRecordZone {
print("\(error.localizedDescription).")
let rootRecord = CKRecord(recordType: "RootRecord", zoneID: savedRecordZone.zoneID)
rootRecord["Name"] = "Test" as CKRecordValue?
privatedatabase.save(rootRecord) { record, error in
if let error = error {
print("\(error.localizedDescription).")
} else if let record = record {
print("successfully added rootRecord to cloud.")
self.shareTest( rootRecord: record)
}
}
}
}
}
func shareTest(rootRecord:CKRecord) {
let ckContainer = CKContainer.default()
let shareRecord = CKShare(rootRecord: rootRecord)
let sharingController = UICloudSharingController { controller, preparationCompletionHandler in
let share = CKShare(rootRecord: record)
share[CKShareTitleKey] = "Share Title" as CKRecordValue
share.publicPermission = .none
let modifyRecordsOperation = CKModifyRecordsOperation( recordsToSave: [rootRecord, share], recordIDsToDelete: nil)
modifyRecordsOperation.timeoutIntervalForRequest = 10
modifyRecordsOperation.timeoutIntervalForResource = 10
modifyRecordsOperation.modifyRecordsCompletionBlock = { records, recordIDs, error in
if let error = error {
print(error.localizedDescription)
}
if let records = records {
print("Share and Root records saved successfully")
}
preparationCompletionHandler(share, CKContainer(identifier: ckContainerID ), error)
}
myCloudDatabase.add(modifyRecordsOperation)
}
if let sharingController = sharingController {
sharingController.availablePermissions = [.allowReadOnly, .allowReadWrite, .allowPrivate]
sharingController.popoverPresentationController?.sourceView = sender
sharingController.delegate = self
self.present(sharingController, animated: true)
}
}
// MARK: UICloudSharingControllerDelegate
// --------------------------------------
func cloudSharingController(_ csc: UICloudSharingController, failedToSaveShareWithError error: Error) {
print("Failed to share to cloud: \(error)")
}
func itemTitle(for csc: UICloudSharingController) -> String? {
return "Please join rootRecord share."
}
func cloudSharingControllerDidStopSharing(_ csc: UICloudSharingController) {
print("Cloudkit stopped sharing")
}
func cloudSharingControllerDidSaveShare(_ csc: UICloudSharingController) {
print("Cloudkit started sharing rootRecord")
}
For some odd reason, my images have stopped saving to parse. Before, my code worked fine and I have not made any changes to it at all.
Here is my code:
var posts = PFObject(className: "Product")
posts["shortDescription"] = productShortDescription
posts["user"] = PFUser.currentUser()
posts["longDescription"] = productLongDescription
posts["title"] = productTitle
posts["price"] = productPrice
posts.saveInBackgroundWithBlock({
(success: Bool, error: NSError?) -> Void in
if error == nil {
//success saving, now save image
//create image data
var imageData = UIImagePNGRepresentation(self.newItemImageView.image)
//create parse file
var parseImageFile = PFFile(name: "upload_image.png", data: imageData)
posts["imagePNG"] = parseImageFile
posts.saveInBackgroundWithBlock({
(success: Bool, error: NSError?) -> Void in
if error == nil {
// take user home
println("data uploaded")
self.performSegueWithIdentifier("returnHomeAfterUpload", sender: self)
}else {
println(error)
}
})
}else {
println(error)
}
})
Everything else is stored perfectly, but what's the issue with my image data?
Thanks!
In your code you are not saving parseImageFile, so first parseImageFile.SaveInBackground and on success set it to posts and then save posts as well
Should be something like this
var posts = PFObject(className: "Product")
posts["shortDescription"] = productShortDescription
posts["user"] = PFUser.currentUser()
posts["longDescription"] = productLongDescription
posts["title"] = productTitle
posts["price"] = productPrice
posts.saveInBackgroundWithBlock({
(success: Bool, error: NSError?) -> Void in
if error == nil {
//success saving, now save image
//create image data
var imageData = UIImagePNGRepresentation(self.newItemImageView.image)
//create parse file
var parseImageFile = PFFile(name: "upload_image.png", data: imageData)
parseImageFile.saveInBackgroundWithBlock({
posts["imagePNG"] = parseImageFile
posts.saveInBackgroundWithBlock({
(success: Bool, error: NSError?) -> Void in
if error == nil {
// take user home
println("data uploaded")
self.performSegueWithIdentifier("returnHomeAfterUpload", sender: self)
}else {
println(error)
}
})
})
}else {
println(error)
}
})
I haven't test this code on editor you may find some syntax error, but it should be something like this...
so things is when you create parseImageFile and then saveInBackground and inside block set it posts and then save post again
I've checked your code and it's works fine.
let image = UIImage(named: "img.jpg")
let data = UIImagePNGRepresentation(image)
let file = PFFile(name: "img", data: data)
let parseObj = PFObject(className: "testClass")
parseObj["text"] = "hello"
parseObj["image"] = file
parseObj.saveInBackgroundWithBlock { (_, _) -> Void in }
Try this, if this code will be works - easiest way for you is remove "Product" table and create it again.
I'm creating an application with Parse as backend service. My users should be able to sign-up and login via Facebook.
I did this in the following (works absolutely fine).
#IBAction func registerWithFacebook(sender: UIButton) {
let permissions:[String] = ["user_about_me","user_relationships", "public_profile"]
PFFacebookUtils.logInWithPermissions(permissions, {
(user: PFUser!, error: NSError!) -> Void in
if user == nil {
NSLog("Uh oh. The user cancelled the Facebook login.")
} else if user.isNew {
NSLog("User signed up and logged in through Facebook!")
self.loadData()
self.performSegueWithIdentifier("initialToMain", sender: self)
} else {
NSLog("User logged in through Facebook!")
self.performSegueWithIdentifier("initialToMain", sender: self)
}
})
}
func loadData(){
let request:FBRequest = FBRequest.requestForMe()
request.startWithCompletionHandler { (connection:FBRequestConnection!, result:AnyObject!, error:NSError!) -> Void in
if error == nil{
if let dict = result as? Dictionary<String, AnyObject>{
let name:String = dict["name"] as AnyObject? as String
let email:String = dict["email"] as AnyObject? as String
println(name)
PFUser.currentUser().setValue(name, forKey: "username")
PFUser.currentUser().setValue(email, forKey: "email")
PFUser.currentUser().save()
}
}
}
}
Unfortunately I wasn't able to get the profile picture from the user who's signing up. How can I do that?
The picture is publicly available via the user id at the following url:
https://graph.facebook.com/USER_ID/picture
You can also request various sizes:
https://graph.facebook.com/USER_ID/picture?width=300&height=300
Here's the working solution:
func loadData(){
let request:FBRequest = FBRequest.requestForMe()
request.startWithCompletionHandler { (connection:FBRequestConnection!, result:AnyObject!, error:NSError!) -> Void in
if error == nil{
if let dict = result as? Dictionary<String, AnyObject>{
let name:String = dict["name"] as AnyObject? as String
let facebookID:String = dict["id"] as AnyObject? as String
let email:String = dict["email"] as AnyObject? as String
let pictureURL = "https://graph.facebook.com/\(facebookID)/picture?type=large&return_ssl_resources=1"
var URLRequest = NSURL(string: pictureURL)
var URLRequestNeeded = NSURLRequest(URL: URLRequest!)
NSURLConnection.sendAsynchronousRequest(URLRequestNeeded, queue: NSOperationQueue.mainQueue(), completionHandler: {(response: NSURLResponse!,data: NSData!, error: NSError!) -> Void in
if error == nil {
var picture = PFFile(data: data)
PFUser.currentUser().setObject(picture, forKey: "profilePicture")
PFUser.currentUser().saveInBackground()
}
else {
println("Error: \(error.localizedDescription)")
}
})
PFUser.currentUser().setValue(name, forKey: "username")
PFUser.currentUser().setValue(email, forKey: "email")
PFUser.currentUser().saveInBackground()
}
}
}
}
Im trying to capture an image using this iOS swift code , any help would be appreciated
Error
'NSInvalidArgumentException', reason: '*** +[AVCaptureStillImageOutput jpegStillImageNSDataRepresentation:] - NULL sample buffer.'
#IBAction func capture(sender: AnyObject) {
if let stillOutput = self.stillImageOutput as AVCaptureStillImageOutput? {
// we do this on another thread so that we don't hang the UI
println("image1")
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)) {
//find the video connection
var videoConnection : AVCaptureConnection?
for connecton in stillOutput.connections {
//find a matching input port
println("image2")
for port in connecton.inputPorts!{
println("image3")
if port.mediaType == AVMediaTypeVideo {
videoConnection = connecton as? AVCaptureConnection
break //for port
}
}
if videoConnection != nil {
println("image4")
println(videoConnection)
break// for connections
}
}
if videoConnection != nil {
println("image5")
stillOutput.captureStillImageAsynchronouslyFromConnection(videoConnection){
(imageSampleBuffer : CMSampleBuffer!, error: NSError!) in
//if(error != nil){
println("error")
println(error)
//}
println("imageBuffer")
println(imageSampleBuffer)
let imageDataJpeg = AVCaptureStillImageOutput.jpegStillImageNSDataRepresentation(imageSampleBuffer)
var pickedImage: UIImage = UIImage(data: imageDataJpeg)!
// var pickedImage: UIImage = UIImage(named: "hand.jpg")!
println("pic")
var handFlag = NSUserDefaults.standardUserDefaults().objectForKey(kleftHand) as NSString
var userName = NSUserDefaults.standardUserDefaults().objectForKey(KuserNameKey) as NSString
if (handFlag == "true"){
var LeftObject = PFObject(className: "LeftHandObject")
let imageDataLeft = UIImagePNGRepresentation(pickedImage)
let imageFileLeft = PFFile(name: "leftImage.png", data: imageDataLeft)
LeftObject["userName"] = userName
LeftObject["leftImage"] = imageFileLeft
LeftObject["goalObjId"] = NSUserDefaults.standardUserDefaults().objectForKey(kCurrentGoalObjectId) as NSString
LeftObject.saveInBackgroundWithBlock{
(successObjectLeft: Bool!, errorObjectLeft: NSError!) -> Void in
if(errorObjectLeft == nil){
println("SuccessLeft")
}
else{
println("ErrorLeft")
}
}
}
else{
var RightObject = PFObject(className: "RightHandObject")
let imageDataRight = UIImagePNGRepresentation(pickedImage)
let imageFileRight = PFFile(name: "rightImage.png", data: imageDataRight)
RightObject["userName"] = userName
RightObject["rightImage"] = imageFileRight
RightObject["goalObjId"] = NSUserDefaults.standardUserDefaults().objectForKey(kCurrentGoalObjectId) as NSString
RightObject.saveInBackgroundWithBlock{
(successObjectRight: Bool!, errorObjectRight: NSError!) -> Void in
if(errorObjectRight == nil){
println("SuccessRight")
}
else{
println("SuccessLeft")
}
}
}
}
}
self.captureSession.stopRunning()
}
}
println("take photo pressed")
}