AWS dynamodb Query crashes most of the time - ios

i'm trying to download user data from AWS DynamoDB like this:
func downloadUserData(id: String) {
UIApplication.sharedApplication().networkActivityIndicatorVisible = true
let qe = AWSDynamoDBQueryExpression()
qe.hashKeyAttribute = "id"
qe.hashKeyValues = id
dynamoDBObjectMapper!.query(DDBUser.self, expression: qe).continueWithBlock { (task: AWSTask) -> AnyObject? in
if task.error != nil {
NSLog("🦁🦁🦁\(self)")
NSLog("🦁Fehler beim Laden der Userdaten: \(task.error)")
} else {
let paginatedOutput = task.result as! AWSDynamoDBPaginatedOutput
print("output \(paginatedOutput.items)")
for user in paginatedOutput.items as! [DDBUser] {
SessionController.sharedInstance.user = user
for (index, tacklId) in SessionController.sharedInstance.user.tacklIds.enumerate() {
if tacklId == "empty" {
SessionController.sharedInstance.user.tacklIds.removeAtIndex(index)
}
}
if !(SessionController.sharedInstance.user.endpoints.contains(SessionController.sharedInstance.currEndpoint!)) {
SessionController.sharedInstance.user.endpoints += [SessionController.sharedInstance.currEndpoint!]
}
}
NSLog("User Download Complete")
dispatch_async(dispatch_get_main_queue()) {
UIApplication.sharedApplication().networkActivityIndicatorVisible = false
self.userdataDelegate?.userdataDownloadComplete!()
}
}
return nil
}
}
Not alway, but most of the time, the Execution stops at this line:
for user in paginatedOutput.items as! [DDBUser] {
With this Error code:
exc_breakpoint (code=1, subcode=0x10015d440)
It even happens with Breakpoints disabled and i can't continue with the Execution.
The line before the break:
print("output \(paginatedOutput.items)")
works well. Could the problem be on another thread and it falsely shows me the error here? How to best debug this? Thank you

You are trying to use
let qe = AWSDynamoDBQueryExpression()
qe.hashKeyAttribute = "id"
qe.hashKeyValues = id
which is deprecated. I would suggest you use 'keyConditionExpression' and 'expressionAttributeValues' instead.
Thanks,
Rohan

Related

Records, Zone doesn't displayed in Dashboard and Delete Zone issue CloudKit

I have created a zone for privateCloudDatabase.
static var privateCloudDatabase: CKDatabase {
let container = CKContainer(identifier: "iCloud.<bundle>")
return container.privateCloudDatabase
}
static func createZone() {
let fetchZonesOperation = CKFetchRecordZonesOperation.fetchAllRecordZonesOperation()
fetchZonesOperation.fetchRecordZonesCompletionBlock = {
(recordZones: [CKRecordZone.ID : CKRecordZone]?, error: Error?) -> Void in
guard error == nil else {
return
}
for recordID in recordZones.keys {
if recordID.zoneName == zoneName {
print("Zone Already Created: \(recordID)")
} else if recordID.zoneName == "_defaultZone" {
print("Deafult Zone")
} else {
let customZone = CKRecordZone(zoneName: zoneName)
privateCloudDatabase.save(customZone) { zone, error in
if let error = error{
print("Zone creation error: \(String(describing: error))")
} else {
print("Zone created: \(String(describing: zone?.zoneID.zoneName))")
}
}
}
}
}
fetchZonesOperation.qualityOfService = .utility
privateCloudDatabase.add(fetchZonesOperation)
}
It works successfully and I got a success message but created Zone doesn't display in CloudKit Dashboard. It only shows the _default zone as of now.
The other issue is related to delete all data from Zone. For that, I used below code
let fetchZonesOperation = CKFetchRecordZonesOperation.fetchAllRecordZonesOperation()
fetchZonesOperation.fetchRecordZonesCompletionBlock = {
(recordZones: [CKRecordZone.ID : CKRecordZone]?, error: Error?) -> Void in
guard error == nil else {
return
}
guard let recordZones = recordZones else { return }
let deletionOperation = CKModifyRecordZonesOperation(recordZonesToSave: nil, recordZoneIDsToDelete: recordZones.keys.map { $0 })
deletionOperation.modifyRecordZonesCompletionBlock = { _, deletedZones, error in
guard error == nil else {
let error = error!
print("Error deleting records.", error)
return
}
print("Records successfully deleted in this zone.")
}
}
fetchZonesOperation.qualityOfService = .userInitiated
privateCloudDatabase.add(fetchZonesOperation)
Here I neither get any success message not get any error message. The other method I tried to delete all data from the zone is
let customZone = CKRecordZone(zoneName: zoneName)
let predicate = NSPredicate(value: true)
let query = CKQuery(recordType: recordType, predicate: predicate)
privateCloudDatabase.perform(query, inZoneWith: customZone.zoneID) { (records, error) in
if error == nil {
for record in records! {
removeRecord(record.recordID.recordName) { record, error in
}
}
}
}
Here, I get the success message but when I am trying to fetch data from the zone, I get all entries and that suggests data aren't deleted using any of the above methods. Any suggestions for these queries?
Whenever I have run into inexplicable errors and the absence of data updates in CloudKit, it was usually because of something silly like:
A typo in the container identifier so it was interacting with the wrong database on CloudKit.
The account on my Apple device that I was using was different than the account I was signing into in the CloudKit Dashboard.
Have you checked the CloudKit logs to confirm that these actions are hitting your database?

How can I set authentication required for access AWS DynamoDB

First I simply follow the given instruction for accessing the DynamoDB,
After that I build the downloaded sample project named DynamoDBObjectMapper-Sample I got given error log -
Error: Error Domain=com.amazonaws.AWSCognitoIdentityErrorDomain Code=8 "(null)" UserInfo={__type=NotAuthorizedException, message=Unauthenticated access is not supported for this identity pool.}
This error are print after executing following code-
UIApplication.shared.isNetworkActivityIndicatorVisible = true
let dynamoDBObjectMapper = AWSDynamoDBObjectMapper.default()
let queryExpression = AWSDynamoDBScanExpression()
queryExpression.exclusiveStartKey = self.lastEvaluatedKey
queryExpression.limit = 20
dynamoDBObjectMapper.scan(DDBTableRow.self, expression: queryExpression).continueWith(executor: AWSExecutor.mainThread(), block: { (task:AWSTask!) -> AnyObject! in
if self.lastEvaluatedKey == nil {
self.tableRows?.removeAll(keepingCapacity: true)
}
if let paginatedOutput = task.result {
for item in paginatedOutput.items as! [DDBTableRow] {
self.tableRows?.append(item)
}
self.lastEvaluatedKey = paginatedOutput.lastEvaluatedKey
if paginatedOutput.lastEvaluatedKey == nil {
self.doneLoading = true
}
}
UIApplication.shared.isNetworkActivityIndicatorVisible = false
self.tableView.reloadData()
if let error = task.error as NSError? {
print("Error: \(error)")
}
return nil
})
So please help me for set the authentication key-

Completion of setValue() causes crash Firebase, Swift 3

I am currently updating an App to Swift 3 and iOS 10. The Problem is whenever I use:
self.ref.setValue(value, withCompletionBlock: { (error: Error?, _:FIRDatabaseReference) in
//Code
})
The App crashes without any kind of information on why it does that. If I delete the completion, it works fine.
Try this code, i hope this will do the trick
// U can use this to set value to your database
func setValue() {
let myRef = FIRDatabase.database().reference().child("Your path")
let valueForChild: String = "newValue"
let newValue = ["childName": valueForChild] as [String: Any]
myRef.setValue(newValue) { (error, ref) in
if error != nil {
print(error?.localizedDescription ?? "Failed to update value")
} else {
print("Success update newValue to database")
}
}
}
// or this to update new value to your database
func updateValue() {
let myRef = FIRDatabase.database().reference().child("Your path")
let valueForChild: String = "newValue"
let newValue = ["childName": valueForChild] as [String: Any]
myRef.updateChildValues(newValue) { (error, ref) in
if error != nil {
print(error?.localizedDescription, "Failed to update value")
} else {
print("Success update newValue to database")
}
}
}

Check if a row exists in Parse, if it does update a column in the row instead of creating a new row each time. Swift

I have a className called SearchPreferences and it is empty until the current user makes a selection. When they make a selection a new row is created in this class with the updated info. The problem is if the user goes back and makes another selection I am creating a new row again instead of just updating the column. Here is the code that is saving the info but on a new row:`
let music = PFObject(className: "SearchPreferences")
music["music"] = table_data[indexPath.row]
// music["user"] = PFUser.currentUser()!.username!
music.saveInBackgroundWithBlock{(success, error) -> Void in
if error == nil {
music.saveInBackground()
print("success")
} else {
print("error")
}
}
`
All I can find is SQL and PHP online help. I tried the code below to call objId but I don't know it as its empty so it returns the below error.
The code below returns the error
No results matched the query. (Code: 101, Version: 1.7.5)
let query = PFQuery(className:"SearchPreferences")
query.getObjectInBackgroundWithId("musicSearch") {
(searchPreference: PFObject?, error: NSError?) -> Void in
if error != nil {
if let searchPreference = searchPreference {
searchPreference["musicSearch"] = self.table_data[indexPath.row]
searchPreference.saveInBackground()
if error == nil {
query.whereKeyDoesNotExist("musicSearch")
let searchPreference = PFObject(className: "SearchPreferences")
searchPreference["musicSearch"] = self.table_data[indexPath.row]
searchPreference.saveInBackgroundWithBlock{(success, error) -> Void in
The same can be send for this attempt:
var query = PFQuery(className:"SearchPreferences")
query.getObjectInBackgroundWithId("musicSearch") {
(searchPreference: PFObject?, error: NSError?) -> Void in
if error != nil {
print(error)
} else if let searchPreference = searchPreference {
searchPreference["musicSearch"] = self.table_data[indexPath.row]
searchPreference.saveInBackground()
}
}
I am trying to figure out how to either before running the query check if it is empty and if it is carry out my initial query. Parse docs only tell you how to save to classname _User not a second classname.
Here is an example on duplicated record update from parse community, you can use the same method to apply it with your code.
let adventureQuery = PFQuery(className: “Class Name“)
adventureQuery.limit = 1000
adventureQuery.addDescendingOrder(“Column Name”)
adventureQuery.getFirstObjectInBackground { (Success, error) in
Success?.setValue(self.toolsTitleTextField.text, forKey: "toolsTitle")
Success?.setValue(self.locationTextField.text, forKey: "location")
Success?.setValue(self.dateTextField.text, forKey: "createrDate")
Success?.saveInBackground(block: { (success, error) in
if (success){
Utility.showAlert("Success!", message: "Insert SuccessFully", viewController: self)
}
else{
let viewController = self.storyboard?.instantiateViewController(withIdentifier: "") as! ViewController
self.navigationController?.pushViewController(viewController, animated: true)
}
})
}

CKQueryOperation error: This operation has been rate limited

Client received error 1298: This operation has been rate limited error from CloudKit when downloading records with CKQueryOperation, only once, during Apple review. How can I fix this issue?
Here is to code, nothing special:
let query = CKQuery(recordType: "Movie", predicate: NSPredicate(format: "creationDate > %#", d!))
let qo = CKQueryOperation(query: query)
let fb: (CKRecord!) -> () = {record in
temporaryContext.performBlockAndWait({
let fr = NSFetchRequest(entityName: "Movie")
fr.predicate = NSPredicate(format: "recordName = %#", record.recordID.recordName)
let a = temporaryContext.executeFetchRequest(fr, error: nil) as! [Movie]
if a.count == 0 {
let m = NSEntityDescription.insertNewObjectForEntityForName("Movie", inManagedObjectContext: temporaryContext) as! Movie
m.title = record.valueForKey("title") as! String
m.image = (record.valueForKey("image") as! CKAsset).fileURL.description
m.imageSize = Int32(record.valueForKey("imageSize") as! Int)
m.recordName = record.recordID.recordName
}
})
}
let c: ()->() = {
temporaryContext.performBlockAndWait({
let success = temporaryContext.save(nil)
})
Utility.managedObjectContext().performBlockAndWait({
let success = Utility.managedObjectContext().save(nil)
})
NSUserDefaults.standardUserDefaults().setBool(true, forKey: "moviesDownloaded")
NSUserDefaults.standardUserDefaults().synchronize()
dispatch_semaphore_signal(self.sema)
}
let cb: (CKQueryCursor!, NSError!) -> () = {cursor, error in
if error == nil {
if cursor != nil {
let qo2 = Utility.qo(cursor, recordFetchedBlock: fb, completion: c)
publicDatabase.addOperation(qo2)
} else {
c()
}
} else {
Utility.log("error 1298: \(error.localizedDescription)")
dispatch_sync(dispatch_get_main_queue(), {
self.status.backgroundColor = UIColor.orangeColor()
})
NSThread.sleepForTimeInterval(0.5)
dispatch_semaphore_signal(self.sema)
}
}
qo.recordFetchedBlock = fb
qo.queryCompletionBlock = cb
publicDatabase.addOperation(qo)
dispatch_semaphore_wait(self.sema, DISPATCH_TIME_FOREVER)
I try to put this whole code into a loop like:
for i in 1 ... 2 {
var rateLimited = false
...
if error == nil {
} else {
NSThread.sleepForTimeInterval(3)
rateLimited = true
}
...
if !rateLimited {
break
}
}
Do you think it will work?
If you get CKErrorRequestRateLimited the error will have a CKErrorRetryAfterKey key in the error's userInfo dictionary. You should wait at least that amount of time before retrying your operation.
Waiting with a sleep is a bad idea because it can cause unexpected hangs in your application, especially if that code runs on your main thread. Use dispatch_after or a NSTimer to re-send your operation.
You will also get this error if you are not logged in to your iCloud account.

Resources