"Fatal error: unexpectedly found nil while unwrapping an Optional value" while querying from CloudKit - fatal-error

I'm trying to get the current users first name from CloudKit using the following code:
func getUserFirstName() -> String{
var firstNameFromFunction: String?
var currentuserID : CKRecordID?
container.fetchUserRecordID(completionHandler: {
userID, error in
if ((error == nil)) {
self.currentuserID = userID!
}
})
container.discoverUserInfo(withUserRecordID: currentuserID!, completionHandler: {userInfo, error in
let firstNameFromFunction = (userInfo!.displayContact?.givenName)!
})
return firstNameFromFunction!
}
However when executed, the currentUserID is nil, and creating the fatal error. Does anyone know why currentUserID is nil?

Your App must successfully requestApplicationPermission for userDiscoverability before it can fetchUserRecordID.

The code to test if a value is nil looks like this. San maybe right with his answer; I would guess it may be nil too if the user isn't logged into his appleID on the device your running it on.
if self.currentuserID = userID {
// do something with self.currentuserID (the unwrapped value of userID)
} else {
// do something now that we know userID is nil
}

Related

How to update a document in firebase firestore using swift?

when i run the following code i get this error.
['FIRESTORE INTERNAL ASSERTION FAILED: Invalid document reference. Document references must have an even number of segments, but User has 1']
func saveLabel(uid: String, label: String){
let userRef = db.collection("User").document(uid)
userRef.updateData(["label": label]) { (error) in
if error == nil {
print("updated")
}else{
print("not updated")
}
}
}
This error almost certainly means that uid is empty. You should log it to make sure.

CKRecord fetch return 1 record with empty RecordID

Record from iCloud container is fetched, but there is no RecordID. At the same time in the panel on the site, I see it. I tried to extract the record from another application, I registered the necessary container in the settings - and it was extracted without error.
I do not understand - this is a bug Xcode? After all, the extraction code is identical in the second application, where everything works. And in the debugger at the bottom left you can see that RecordID is not empty.
Code:
privateDatabase.perform(query, inZoneWith: nil) { (results, error) -> Void in
if error != nil {
print(error!.localizedDescription)
result(false)
} else if results != nil, results!.count > 0, let me = results?[0] {
let RN = (me[.recordID] as! CKRecord.ID).recordName
Error:
Thread 2: Fatal error: Unexpectedly found nil while unwrapping an Optional value
Variables View Console:
_recordName __NSCFString * #"UA-kuka-2018-11-16 11:27:59" 0x00000001c0644320
The proper way to get the recordID of a CKRecord is to use the recordID property.
Assuming me is actually a CKRecord:
let RN = me.recordID.recordName

Convert any object to boolean in swift?

I am getting a dictionary as JSON response from server.From that dictionary there is a key "error" now i want to get the value of "error" key.I know that error always will be either 0 or 1.So i tried to get it as boolean but it did not work for me.Please suggest how can i convert its value to boolean.
let error=jsonResult.objectForKey("error")
//this does not work for me
if(!error)
{
//proceed ahead
}
Bool does not contain an initializer that can convert Int to Bool. So, to convert Int into Bool, you can create an extension, i.e.
extension Bool
{
init(_ intValue: Int)
{
switch intValue
{
case 0:
self.init(false)
default:
self.init(true)
}
}
}
Now you can get the value of key error using:
if let error = jsonResult["error"] as? Int, Bool(error)
{
// error is true
}
else
{
// error does not exist/ false.
}
Very Simple Way: [Updated Swift 5]
Create a function:
func getBoolFromAny(paramAny: Any)->Bool {
let result = "\(paramAny)"
return result == "1"
}
Use the function:
if let anyData = jsonResult["error"] {
if getBoolFromAny(anyData) {
// error is true
} else {
// error is false
}
}
Also, if you want one line condition, then above function can be reduced like:
if let anyData = jsonResult["error"], getBoolFromAny(anyData) {
// error is true
} else {
// error is false
}
Updated
Considering jsonResult as NSDictionary and error value is Bool. you can check it by following way.
guard let error = jsonResult.object(forKey: "error") as? Bool else{
// error key does not exist / as boolean
return
}
if !error {
// not error
}
else {
// error
}
Your error is neither 0 or 1. It is an optional object. It is nil if there was no key "error" in your JSON, otherwise it's probably an NSNumber.
It is most likely that nil means "no error" and if it's not nil and contains a zero it means "no error" and if it's not nil and contains a one it means "error" and if it's not nil and contains anything else then something is badly wrong with your json.
Try this:
let errorObject = jsonResult ["error"]
if errorObject == nil or errorObject as? NSInteger == 0
When I say "try", I mean "try". You're the responsible developer here. Check if it works as wanted with a dictionary containing no error, with a dictionary containing an error 0 or 1, and a dictionary containing for example error = "This is bad".
Check equality between error and 0 instead:
let error = jsonResult.objectForKey("error")
if error == 0 {
// proceed
}
Another Important point here is, you're using Swift and parsing the repsonse as NSDictionary. I can say that because you're using objectForKey method. Best practice would be to parse it as Swift Dictionary.
It may look like Dictionary<String:AnyObject> or [String:AnyObject]
Then you can check for the error as :
if let error = jsonResult["error"] where error == 0 {
//your code
}
Below code worked for me
if let error = jsonResult["error"] as? Int where Bool(error)
{
// error is true
print("error is true")
}
else
{
// error does not exist/ false.
print("error is false")
}

How do I get user record in CloudKit?

I can fetch the userRecordID, but I get an error whenever I try to fetch the record associated with that ID. Any suggestions? Code and error below:
myContainer.fetchUserRecordID { (thisID, thisError) in
if let userError = thisError {
print("DEBUG: error getting user id; \(userError)")
} else {
if let userID = thisID {
self.publicDatabase.fetch(withRecordID: userID, completionHandler: { (fetchedUser, fetchedError) in
if let thisError = fetchedError {
print("DEBUG: error getting user record; \(thisError)")
}
DEBUG: error getting user record; <CKError 0x174045010: "Internal Error" (1/5001); "Couldn't get a PCS object to unwrap encrypted data for field encryptedPublicSharingKey: (null)">
Error in the code, or my fault for trying beta software (iOS 10, Swift 3 & xCode-beta 8.0 beta 2 (8S162m)
From your example it is not clear if self.publicDatabase is equal to myContainer.publicCloudDatabase.
Make sure you fetch it from the same container's database, otherwise it will obviously not work.
myContainer.fetchUserRecordID { userID, error in
guard error == nil else {
print("DEBUG: error getting user id; \(userError)")
return
}
guard let userRecID = userID else {
print("DEBUG: Can't unwrap userID")
return
}
myContainer.publicCloudDatabase.fetch(withRecordID: userRecID, completionHandler: { (fetchedUser, fetchedError) in
//handle the error and the user
print("DEBUG: User fetch FINISHED!", fetchedUser)
})
}
I needed to change from publicDatabase to privateDatabase.
self.publicDatabase.fetch(withRecordID: userID, completionHandler: { (fetchedUser, fetchedError) in
to
self.privateDatabase.fetch(withRecordID: userID, completionHandler: { (fetchedUser, fetchedError) in

Swift Parse: can not retrieve the value of a bool in _User class

I am developing an app using swift and Parse. For some reasons I have implemented a Bool named "modified" in the _User class. I have been playing around with swift and Parse for a few months but this just does not make sense.
When I try to retrieve the value of the "modified" Bool I keep on getting "false" value even though it is set on "true" on Parse server. Here is the code:
var modified: Bool = PFUser.currentUser().objectForKey("modified") as! Bool
println("User Modified Bool is set to: \(modified)")
I have also tried with
self.modified = PFUser.currentUser().valueForKey("modified") as! Bool
println("User Modified Bool is set to: \(modified)")
and
self.modified = PFUser.currentUser()["modified"] as! Bool
println("User Modified Bool is set to: \(modified)")
Do I have to make a specific query or is there a way to access this value directly?
Edit
I have implemented a specific query. Still get a "false" value though
var queryMainUser: PFQuery = PFUser.query()
queryMainUser.whereKey("username", equalTo: PFUser.currentUser().username)
queryMainUser.findObjectsInBackgroundWithBlock { (mainUsersObjects, mainUsersError) -> Void in
if (mainUsersError == nil) {
var theRef = mainUsersObjects[0] as! PFObject
self.modified = theRef["modified"] as! Bool
println("Any improvement? \(self.modified)")
}
}
Edit 2
Following #danh advices, I tried updating the currentuser instance on the device by implementing this code:
var currentUser = PFUser.currentUser()
currentUser.fetchInBackgroundWithBlock { (object, error) -> Void in
println("Refreshed")
currentUser.fetchIfNeededInBackgroundWithBlock { (result, error) -> Void in
self.modified = currentUser.objectForKey("modified") as! Bool
var idOfUser: String = currentUser.objectId
println("User \(idOfUser) UPDATED")
println(self.modified)
if self.modified == true {
self.deleteData()
self.fetchAllObjects()
}
}
}
When running the console gives me this:
Refreshed
User xTbBw6cNzK UPDATED
false
Here is a screenshot I just took of the server side:
Thank you all for your attention
I am not sure what version of swift you are using. But if you are using Swift 2.0 and Xcode 7, this SHOULD do the job.
This will not work:
let modifiedStatus = PFUser.currentUser()?["modified"] // return value will be nil
This will work for sure:
let modifiedStatus = PFUser.currentUser()?.objectForKey("modified")
print(modifiedStatus) // true as per your table
I know this may sound strange, but some I struggle with something for hours later realising my silly mistake. So it is always good to move back of the current task and later recheck after few hours. So just make sure you cross check the following:
The key "modified" in the main user class of parse
You can retrieve other key values (just to see if nothing else is wrong other than your current retrieving of a key bool value(
Though I am on Swift 2.0, but for sure there is no major change from in this specific code when it comes to move from Swift 1.2 to Swift 2.0.
Just see and if it still doesn't work, we can discuss more on your setup.
I have initialised a "doneSetUp" var as a local variable, it is an int.
then I query the user which just logged in
checks if it exists...
check if the variable userDidSetUp exists in parse and if it does I am converting it to an int and assign it to the local variable doneSetUp I made
then I am using the "doneSetUp" variable which now has a value of 0(false) or 1(true) to decide if the user already setup his account or not and then segue the user to the correct view controller.
mention that all of this code is inside of my logininbackgroundwithblock function.
I hope that helped.
query?.getObjectInBackgroundWithId(user!.objectId!, block: {
(user, error) -> Void in
if let user = user{
if var userDidSetUp: AnyObject = user["doneSetUp"] {
self.doneSetUp = userDidSetUp as! Int
if self.doneSetUp == 0 {
self.performSegueWithIdentifier("procceedToSetup", sender: self)
}else{
self.performSegueWithIdentifier("procceedToApp", sender: self)
}
}
}
})
I know it's an old post, but here's what worked for me.
This is inside the viewDidLoad method.
PFUser.currentUser()?.fetchInBackgroundWithBlock({ (object, error) -> Void in
var modified = PFUser.currentUser()?.objectForKey("modified")?.boolValue
if modified == true {
print(modified) // Output console displays "true"
Hope this helps.

Resources