Update value in Parse.com - swift

I am trying to update a value in my Parse.com table named: "currentUploaded".
This is my query from Parse.com code:
http://pastebin.com/Jr0EcJuy
Parse.com “currentUploads” class: http://i.stack.imgur.com/E8tND.png
This is the button i want to do the update value(as it is now, it create a new row in another class, but i just want to increase the "reportedCount" of the selected item instead:
#IBAction func reportContentAction(sender: AnyObject) {
let buttonPosition = sender.convertPoint(CGPointZero, toView: self.collectionView)
let indexPath = self.collectionView.indexPathForItemAtPoint(buttonPosition)
////
println(indexPath?.item)
////
let post = self.arrayOfDetails[indexPath!.item]
var alertMessage = NSString(format:"*User: %#\r *Text: %#\r *Created at %#", post.username, post.text, post.CreatedAt)
var reportAlert = UIAlertController(title: "Report Content", message:alertMessage as String, preferredStyle: UIAlertControllerStyle.Alert)
reportAlert.addAction(UIAlertAction(title: "Yes", style: .Default, handler: { (action: UIAlertAction!) in
println("Handle Report Logic here")
var currentUploads = PFObject(className: "banned")
currentUploads["username"] = post.username
currentUploads["imageText"] = post.text
currentUploads["imageFile"] = post.image
currentUploads["identifierForVendor"] = post.deviceID
currentUploads["flaggedBy"] = PFUser.currentUser()?.username
currentUploads["flaggedByUUID"] = UIDevice.currentDevice().identifierForVendor.UUIDString
currentUploads.saveInBackgroundWithBlock({ (success: Bool, error: NSError?) -> Void in
if error == nil{
//**Success saving, now save image.**//
currentUploads.saveInBackgroundWithBlock({ (success: Bool, error: NSError?) -> Void in
if error == nil{
// Take user home
print("Data uploaded")
// Show UIAlertView
let alert = UIAlertView()
alert.title = "Message"
alert.message = "You report has been sent. Thank you for your support."
alert.addButtonWithTitle("Close")
alert.show()
}
else{
print(error)
}
})
}
else{
print(error)
}
})
}))
reportAlert.addAction(UIAlertAction(title: "Cancel", style: .Default, handler: { (action: UIAlertAction!) in
println("Handle Cancel Logic here")
}))
presentViewController(reportAlert, animated: true, completion: nil)
}
I have also tried using this code when the user click yes on the popup, but it doesn't work:
reportAlert.addAction(UIAlertAction(title: "Yes", style: .Default, handler: { (action: UIAlertAction!) in
println("Handle Report Logic here")
var query = PFQuery(className: "currentUploads")
query.whereKey("imageFile", equalTo: post.image)
query.getFirstObjectInBackgroundWithBlock {
(myObject: PFObject?, error: NSError?) -> Void in
if (error != nil){
println(error)
//
}
else{
query.setValue("1", forKey: "reportedCount")
}
}
}))
Please, can someone show me how it should be correct? Have been struggling on this for many many hours now..

a small example
let someQuery = PFQuery(className: "banned")
someQuery.getObjectInBackgroundWithId(someclass.objectId) {
(updatedObject: PFObject?, error: NSError?) -> Void in
if error != nil {
print(error)
} else if let updatedObject = updatedObject {
updatedObject["NameOfTheFieldYouWantToChange"] = newValue
updatedObject.saveInBackground()
}
}
someclass.objectId — it's just an objectId value for the raw you want to update. I don't know where you are storing it.
"NameOfTheFieldYouWantToChange" — name of the field you want to change :)
newValue — new value for this field.
P.S. Also it seems that you are trying to put your Parse code to your ViewController class. Compiler won't care so it will work, but it's not a good practice. It would be much more simpler for you to put all these database operations to different class (MVC pattern).

Related

How to get the latest Document ID in Firestore using Swift iOS

I am giving users the possibility to set up Project-Details in an app.
Since there is also the opportunity to upload an image, i will have to make use of Firebase Storage. Because I want to give the users an overview of their projects combining the data and the uploaded picture I need to make a reference between the DocumentID in database and the ImageID in storage.
I thought about a two step approach: 1. Users are generating a Project -> User clicks "next" (document getting generated) 2. User uploads an image -> Image gets stored in Storage with Reference to the DocumentID of the just generated Project.
The goal is simply to link the Image to the Document ID of the project.
Can anyone give me a hint how to solve that problem? Here are my codes so far:
For the Project-Details:
// MARK: Store the Project Infos in Database
// Check the fields and validate that the data is correct. If everything is correct, this method returns nil. Otherwise, it returns the error message
func validateFields() -> String? {
// Check that all fields are filled in
if txtLocation.text?.trimmingCharacters(in: .whitespacesAndNewlines) == "" ||
txtProjectTitle.text?.trimmingCharacters(in: .whitespacesAndNewlines) == "" ||
txtProjectDescription.text?.trimmingCharacters(in: .whitespacesAndNewlines) == "" ||
endDate.text?.trimmingCharacters(in: .whitespacesAndNewlines) == "" ||
beginnDate.text?.trimmingCharacters(in: .whitespacesAndNewlines) == "" {
return "Please fill in all fields."
}
return nil
}
#IBAction func saveProject(_ sender: Any) {
let user = Auth.auth().currentUser
if let user = user {
let uid = user.uid
// Validate the fields
let error = validateFields()
if error != nil {
// There is something wrong with the fields, show error message
showError(error!)
} else {
// Create cleaned versions of the data
let projectTitle = txtProjectTitle.text!.trimmingCharacters(in: .whitespacesAndNewlines)
let projectLocation = txtLocation.text!.trimmingCharacters(in: .whitespacesAndNewlines)
let projectDescription = txtProjectDescription.text!.trimmingCharacters(in: .whitespacesAndNewlines)
let projectBeginn = beginnDate.text!.trimmingCharacters(in: .whitespacesAndNewlines)
let projectEnd = endDate.text!.trimmingCharacters(in: .whitespacesAndNewlines)
// Save stuff
let db = Firestore.firestore()
db.collection("Projects").addDocument(data: ["Project Title": projectTitle, "Project Location": projectLocation, "Project Description": projectDescription, "Project Start": projectBeginn, "Project Finish": projectEnd, "uid": uid]) { (error) in
if error != nil {
// Show error message
self.showError("Error saving user data")
}
}
}
} else { self.showError("Please log out and log in again")}
}
// Error Handling for save
func showError(_ message:String) {
errorLabel.text = message
errorLabel.alpha = 1
}
And for the Image upload
//MARK: Imagepicker
// Image Picker functions
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
let image = info[UIImagePickerController.InfoKey.originalImage] as? UIImage
newImage.image = image
picker.dismiss(animated: true, completion: nil)
}
func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
picker.dismiss(animated: true, completion: nil)
}
// MARK: - Actions
// Image Picker
#IBAction func addImage(_ sender: Any) {
let imagePickerController = UIImagePickerController()
imagePickerController.delegate = self
let actionSheet = UIAlertController(title: "Photo Source", message: "Choose a source", preferredStyle: .actionSheet)
actionSheet.addAction(UIAlertAction(title: "Camera", style: .default, handler: { (action: UIAlertAction) in imagePickerController.sourceType = .camera
self.present(imagePickerController, animated: true, completion: nil)
}))
actionSheet.addAction(UIAlertAction(title: "Photo Library", style: .default, handler: { (action: UIAlertAction) in imagePickerController.sourceType = .photoLibrary
self.present(imagePickerController, animated: true, completion: nil)
}))
actionSheet.addAction(UIAlertAction(title: "Cancel", style: .cancel, handler: nil))
self.present(actionSheet, animated: true, completion: nil)
}
//MARK: Upload Image
#IBAction func uploadImage(_ sender: Any) {
guard let image = newImage.image, let data = image.jpegData(compressionQuality: 1.0) else {
self.showError("Something went wrong")
return
}
let imageName = UUID().uuidString
let imageReference = Storage.storage().reference()
.child("imagesFolder")
.child(imageName)
imageReference.putData(data, metadata: nil) {(metadata, err) in
if let err = err {
self.showError("Something went wrong")
return
}
imageReference.downloadURL(completion: { (url, err) in
if let err = err {
self.showError("Something went wrong")
return
}
guard let url = url else {
self.showError("Something went wrong")
return
}
let dataReference = Firestore.firestore().collection("imageReferences").document()
let documentUid = dataReference.documentID
let urlString = url.absoluteString
let imageUID = documentUid
let data = ["Image UID": imageUID, "Image URL": urlString]
dataReference.setData(data, completion: {(err) in
if let err = err {
self.showError("Something went wrong")
return
}
UserDefaults.standard.set(documentUid, forKey: imageUID)
})
})
}
}
// Error Handling for save
func showError(_ message:String) {
errorLabel.text = message
errorLabel.alpha = 1
}
So in best case I could do this even in one View Controller without the need of a two step approach. If it is not possible I would like to put the generated Document ID in
let data = ["Image UID": imageUID, "Image URL": urlString]
of
let dataReference = Firestore.firestore().collection("imageReferences").document()
let documentUid = dataReference.documentID
let urlString = url.absoluteString
let imageUID = documentUid
let data = ["Image UID": imageUID, "Image URL": urlString]
dataReference.setData(data, completion: {(err) in
if let err = err {
self.showError("Something went wrong")
return
}
I would be very pleased if someone could help me. :)

Firebase Xcode Swift - stuck on downloadURL

I know the downloadURL function has been deprecated, but I can't seem to get the new completion function to work:
#IBAction func postButtonClicked(_ sender: Any) {
let mediaFolder = Storage.storage().reference().child("media")
if let data = UIImageJPEGRepresentation(postImage.image!, 0.5) {
mediaFolder.child("\(uuid).jpg").putData(data, metadata: nil, completion: { (metadata, error) in
if error != nil {
let alert = UIAlertController(title: "Error", message: error?.localizedDescription, preferredStyle: UIAlertControllerStyle.alert)
let okButton = UIAlertAction(title: "OK", style: UIAlertActionStyle.cancel, handler: nil)
alert.addAction(okButton)
self.present(alert, animated: true, completion: nil)
} else {
let imageURL = mediaFolder.downloadURL(completion: { (url, error) in
if error != nil {
print("error!!!!")
} else {
return url?.absoluteString
}
})
print(imageURL)
}
})
}
}
I just can't get this to work. I always get the error!!!!! message in the log and I'm not sure why. I've been struggling with this code for the past 3 hours and for some reason I just can't get the imageURL to print.
All I want is to get imageURL to equal url?.absoluteString
Any help would greatly be appreciated
You're not getting the URL to print out because you're not querying the right storage references.
First, check if the image is actually uploaded in the storage and then add the child Id to your mediaFolder in the else statement:
mediaFolder.child("\(uuid).jpg").downloadURL(completion: { (url, error) in
})

CNContact fetching should be faster

I am fetching contact from CNContact and it took .30 seconds to show thousands of contact in UI. My client want me to reduce time upto 0.01 second. He gave me example of Telegram app. Can any one help
Ex Code :
typealias ContactsHandler = (_ contacts : [CNContact] , _ error : NSError?) -> Void
extension CDContactsPickerVC {
func getContacts(_ completion: #escaping ContactsHandler) {
if contactsStore == nil {
//ContactStore is control for accessing the Contacts
contactsStore = CNContactStore()
}
let error = NSError(domain: "CDContactPickerErrorDomain", code: 1, userInfo: [NSLocalizedDescriptionKey: "No Contacts Access"])
switch CNContactStore.authorizationStatus(for: CNEntityType.contacts) {
case CNAuthorizationStatus.denied, CNAuthorizationStatus.restricted:
//User has denied the current app to access the contacts.
let productName = Bundle.main.infoDictionary!["CFBundleName"]!
let alert = UIAlertController(title: "Unable to access contacts", message: "\(productName) does not have access to contacts. Kindly enable it in privacy settings ", preferredStyle: UIAlertControllerStyle.alert)
let okAction = UIAlertAction(title: "Ok", style: UIAlertActionStyle.default, handler: { action in
completion([], error)
})
alert.addAction(okAction)
self.present(alert, animated: true, completion: nil)
case CNAuthorizationStatus.notDetermined:
//This case means the user is prompted for the first time for allowing contacts
contactsStore?.requestAccess(for: CNEntityType.contacts, completionHandler: { (granted, error) -> Void in
//At this point an alert is provided to the user to provide access to contacts. This will get invoked if a user responds to the alert
if (!granted ){
DispatchQueue.main.async(execute: { () -> Void in
completion([], error! as NSError?)
})
}
else{
self.getContacts(completion)
}
})
case CNAuthorizationStatus.authorized:
//Authorization granted by user for this app.
var contactsArray = [CNContact]()
let contactFetchRequest = CNContactFetchRequest(keysToFetch: allowedContactKeys())
do {
try contactsStore?.enumerateContacts(with: contactFetchRequest, usingBlock: { (contact, stop) -> Void in
//Ordering contacts based on alphabets in firstname
contactsArray.append(contact)
var key: String = "#"
//If ordering has to be happening via family name change it here.
if let firstLetter = contact.givenName[0..<1] , firstLetter.containsAlphabets() {
key = firstLetter.uppercased()
}
var contacts = [CNContact]()
if let segregatedContact = self.orderedContacts[key] {
contacts = segregatedContact
}
var identifierArray = [String]()
for contactDict in self.orderedContacts {
let contactArray = contactDict.value as [CNContact]
for cnObj in contactArray {
identifierArray.append(cnObj.identifier)
}
}
if identifierArray.contains(contact.identifier) {
// do nothing
}else {
contacts.append(contact)
self.orderedContacts[key] = contacts
}
})
self.sortedContactKeys = Array(self.orderedContacts.keys).sorted(by: <)
if self.sortedContactKeys.first == "#" {
self.sortedContactKeys.removeFirst()
self.sortedContactKeys.append("#")
}
completion(contactsArray, nil)
}
//Catching exception as enumerateContactsWithFetchRequest can throw errors
catch let error as NSError {
print(error.localizedDescription)
}
}
}
func allowedContactKeys() -> [CNKeyDescriptor]{
//We have to provide only the keys which we have to access. We should avoid unnecessary keys when fetching the contact. Reducing the keys means faster the access.
return [CNContactNamePrefixKey as CNKeyDescriptor,
CNContactGivenNameKey as CNKeyDescriptor,
CNContactFamilyNameKey as CNKeyDescriptor,
CNContactPhoneNumbersKey as CNKeyDescriptor,
CNContactEmailAddressesKey as CNKeyDescriptor,
]
}
// MARK: - Contact Operations
open func reloadContacts() {
DispatchQueue.global(qos: .background).async {
self.getContacts( {(contacts, error) in
if (error == nil) {
DispatchQueue.main.async(execute: {
self.emptyContactLabel.isHidden = contacts.count > 0 ? true : false
self.tableView.reloadData()
})
self.updateContactsInLocalDB(contacts: contacts)
}
})
}
}

How can I get all my contacts phone numbers into an array?

How can I get all my contacts phone numbers into an array? I need this, to send the array to my Server/DB to check, if one or more numbers exist in the Database.
I still work with Swift 2, later also with Swift 3.
This code works, but I think, it exist a much more better version.
// With help: http://stackoverflow.com/questions/37039103/how-to-fetch-only-mobile-numbers-in-swift-using-cncontacts
// With help: http://stackoverflow.com/questions/32669612/how-to-fetch-all-contacts-record-in-ios-9-using-contacts-framework/34095632
let store = CNContactStore()
store.requestAccessForEntityType(.Contacts, completionHandler: {
granted, error in
guard granted else {
let alert = UIAlertController(title: "Can't access contact", message: "Please go to Settings -> MyApp to enable contact permission", preferredStyle: .Alert)
alert.addAction(UIAlertAction(title: "OK", style: .Default, handler: nil))
self.presentViewController(alert, animated: true, completion: nil)
return
}
let keysToFetch = [CNContactFormatter.descriptorForRequiredKeysForStyle(.FullName), CNContactPhoneNumbersKey]
let request = CNContactFetchRequest(keysToFetch: keysToFetch)
var cnContacts = [CNContact]()
do {
try store.enumerateContactsWithFetchRequest(request){
(contact, cursor) -> Void in
cnContacts.append(contact)
}
} catch let error {
NSLog("Fetch contact error: \(error)")
}
var mobilenumbers: [String] = []
NSLog(">>>> Contact list:")
for contact in cnContacts {
let fullName = CNContactFormatter.stringFromContact(contact, style: .FullName) ?? "No Name"
NSLog("\(fullName): \(contact.phoneNumbers.description)")
// If phoneNo a Mobilenumber, then put into Array:
for phoneNo in contact.phoneNumbers {
if phoneNo.label == CNLabelPhoneNumberMobile {
let istEineMobileNummer = (phoneNo.value as! CNPhoneNumber).stringValue
mobilenumbers.append(istEineMobileNummer)
}
}
}
print("Print all Mobilenumbers:")
print(mobilenumbers)
})
You can attempt to do this by using the Contacts Framework.
You'll need to ask for the user's permission before accessing this information.

Retrieving texts Records in CloudKit with RecordID Using Swift

Purpose of the program
User need to enter the email and password in order to get logged in.
CloudKit is used to retrieve user credentials.
Hi everyone,
I need your help.
Fetching is not working. Also, this error is unresolved
Use of unresolved identifier 'errorHandler'
I have two texts that I want to fetch in my MasterViewController
The texts are:
#IBOutlet weak var userEmailAddressTextField: UITextField!
#IBOutlet weak var userPasswordTextField: UITextField!
MasterViewController Code:
Please go to fetching section
// signIn btn
#IBAction func btnSignInTapped(sender: UIButton)
{
let userEmailAddress = userEmailAddressTextField.text
let userPassword = userPasswordTextField.text
if(userEmailAddress!.isEmpty || userPassword!.isEmpty)
{
// Display an alert message
let myAlert = UIAlertController(title: "Alert", message:"All fields are required to fill in", preferredStyle: UIAlertControllerStyle.Alert);
let okAction = UIAlertAction(title: "OK", style: UIAlertActionStyle.Default, handler:nil)
myAlert.addAction(okAction);
self.presentViewController(myAlert, animated: true, completion: nil)
return
}
//************************Fetching Section
//loading system indicator
let accountID = CKRecordID!.self
let database = CKContainer.defaultContainer().privateCloudDatabase
var query = CKQuery(recordType:"RegisteredAccounts" , predicate: NSPredicate(value: true))
var operation = CKQueryOperation(query: query)
let spinningActivity = MBProgressHUD.showHUDAddedTo(self.view, animated: true)
spinningActivity.labelText = "SigningIn"
spinningActivity.detailsLabelText = "Please wait"
operation.recordFetchedBlock = { record in /*is this your record...*/ }
operation.queryCompletionBlock =
{ cursor, error in
self.handleCallback(error, errorHandler: {errorHandler(error: error)}, completionHandler:
{
// ready fetching records
if(userEmailAddress! == accountID || userPassword! == accountID)
{
//AlertMessage"You are loggedIn"
}
else{
userEmailAddress! != accountID || userPassword! != accountID
//AlertMessage"Your Credentials do not match"
}
})
}
operation.resultsLimit = CKQueryOperationMaximumResults;
database.addOperation(operation)
spinningActivity.hidden = true
}
Click here please for ScreenShot of the code
.......................
Changes After feedback
//loading system indicator
let database = CKContainer.defaultContainer().privateCloudDatabase
var query = CKQuery(recordType:"RegisteredAccounts" , predicate: NSPredicate(value: true))
var operation = CKQueryOperation(query: query)
//changes
//****default_Login
CKContainer.defaultContainer().fetchUserRecordIDWithCompletionHandler { (CKRecordID, error) in
if error != nil
{
if(userEmailAddress! == CKRecordID || userPassword! == CKRecordID)
{
//self.spinningIndicator("Loggedin")
self.alertMessage("LoggedIn")
}
}
else{
userEmailAddress! != CKRecordID || userPassword! != CKRecordID
//self.spinningIndicator("Credentials don't match.")
self.alertMessage("not matched")
}
}
operation.recordFetchedBlock = { record in /*is this your record...*/ }
operation.queryCompletionBlock =
{ cursor, error in
if error != nil
{
print(error)
}
else{
print(cursor)
}
}
operation.resultsLimit = CKQueryOperationMaximumResults;
database.addOperation(operation)
}
func spinningIndicator(userIndicator:String)
{
let spinningActivity = MBProgressHUD.showHUDAddedTo(self.view, animated: true)
spinningActivity.labelText=userIndicator
spinningActivity.detailsLabelText = "Please wait"
spinningActivity.hidden = true
}
func alertMessage(userAlert: String)
{
// Display an alert message
let myAlert = UIAlertController(title: "Alert", message:userAlert, preferredStyle: UIAlertControllerStyle.Alert);
let okAction = UIAlertAction(title: "OK", style: UIAlertActionStyle.Default, handler:nil)
myAlert.addAction(okAction);
self.presentViewController(myAlert, animated: true, completion: nil)
return
}
I am only prompted by this message self.alertMessage("not matched")
Why am I not prompted by this? self.alertMessage("LoggedIn")
The answer source for this question
is in techotopia
look for >Searching for Cloud Database Records
The answer is in performQuery method
#IBAction func performQuery(sender: AnyObject) {
let predicate = NSPredicate(format: "address = %#", addressField.text)
let query = CKQuery(recordType: "Houses", predicate: predicate)
publicDatabase?.performQuery(query, inZoneWithID: nil,
completionHandler: ({results, error in
if (error != nil) {
dispatch_async(dispatch_get_main_queue()) {
self.notifyUser("Cloud Access Error",
message: error.localizedDescription)
}
} else {
if results.count > 0 {
var record = results[0] as! CKRecord
self.currentRecord = record
dispatch_async(dispatch_get_main_queue()) {
self.commentsField.text =
record.objectForKey("comment") as! String
let photo =
record.objectForKey("photo") as! CKAsset
let image = UIImage(contentsOfFile:
photo.fileURL.path!)
self.imageView.image = image
self.photoURL = self.saveImageToFile(image!)
}
} else {
dispatch_async(dispatch_get_main_queue()) {
self.notifyUser("No Match Found",
message: "No record matching the address was found")
}
}
}
}))
}
The user will already be logged in into iCloud. You do not need an extra login.You can just get the id of the user and use that as the username.
If you do want to use this code, then you probably did not define the errorHandler function (its not in your sample code). Maybe you should first try this without the self.handleCallback. You an just remove that line (well, you should replace it for an if for the error) Did you use this structure for the .handleCallback? That structure works better if you keep your CloudKit code in a separate class and call those methods with a completion and error handler.
replace the line with the self.handleCallback with:
if error != nil {
Besides that you should also change your predicate. You are now querying all records. You want to limit it with a filter on the username.
And if you want to use the iCloud ID instead of your own login, then you could call this:
CKContainer.defaultContainer().fetchUserRecordIDWithCompletionHandler({recordID, error in