Having problems retrieving a record from CloudKit..
My firstName and lastName of my CKRecord are showing up as "N/A" which the safety value from a nil coalescing as you'll see below
I double and triple checked (and beyond) that all the spellings were right.. so I'm good there. Here is my retrieve method..
func getProfile() {
//GETTING USER RECORD ID
CKContainer.default().fetchUserRecordID { id, error in
guard let id = id, error == nil else {
print(error?.localizedDescription)
return }
//GETTING RECORD ID
CKContainer.default().publicCloudDatabase.fetch(withRecordID: id) { record, error in
guard let record = record, error == nil else { return }
let profileReference = record["userProfile"] as! CKRecord.Reference
let profileRecordID = profileReference.recordID
print("Profile reference is",profileReference)
//PASSING REFERENCE TO GET CLIENT SIDE MODEL
CKContainer.default().publicCloudDatabase.fetch(withRecordID: profileRecordID) { profileRecord, error in
guard let profileRecord = profileRecord, error == nil else {
print(error!.localizedDescription)
return
}
//FOR SOME REASON MY PROFILE IS NOT RECEIVING THE RIGHT VALUES FOR FIRST AND LAST NAME, IT JUST SHOWS "N/A"
DispatchQueue.main.async {
let profile = Profile(record: profileRecord)
print("Retrieved Record is: ",profileRecord)
print("Retrieved name is: \(profile.firstName)")
firstName = profile.firstName
lastName = profile.lastName
}
}
}
}
}
And here is the model..
struct Profile {
let profileID: CKRecord.ID
let firstName: String
let lastName: String
init(record: CKRecord) {
profileID = record.recordID
firstName = record["firstName"] as? String ?? "N/A"
lastName = record["lastName"] as? String ?? "N/A"
}
}
I can change the record name on the website. I couldn't find a way with the code.
let cloudsave = CKRecord(recordType: "iEmotion")
let recordName = CKRecord.ID(recordName: "1")
privateDatabase.save(cloudsave) { (savedRecord, error) in
if error == nil {
print("SUCCESSFUL") }
else {"ERROR"}
}
I don't want it saved as a UUID.
This should help:
let recordName = CKRecord.ID(recordName: "1")
let cloudsave = CKRecord(recordType: "iEmotion", recordID: recordName)
privateDatabase.save(cloudsave) { (savedRecord, error) in
if error == nil {
print("SUCCESSFUL") }
else {"ERROR"}
}
I'm a noob, bear with me:
func createEmployeeCode() -> String? {
let email = UserDefaults.standard.object(forKey: "email_Saved") as? String
let employeeCode = UserDefaults.standard.object(forKey: "employeeCode_Saved") as? String
if let emailString = email,
let employeeCodeString = employeeCode {
return (emailString+employeeCodeString)
}
return (emailString+employeeCodeString) //ERROR: Use of unresolved identifier 'employeeCodeString' & Use of unresolved identifier 'emailString'
}
I understand the reason the error shows is because I'm trying to return something that is in a different scope here, but how else can I get the function to return the 2 strings together without the "Optional[...]" tag?
Here's how I'd expect it to be done in a normal production app
(You wouldn't do any of this in a normal production app! But this is the "idiom" you're looking for.)
func createCodeIfPossible() -> String? {
guard let e = UserDefaults.standard.object(forKey: "email_Saved") else {
print("serious problem, there's no email saved")
// at this point the app is completely buggered, so give up
return ""
}
guard let c = UserDefaults.standard.object(forKey: "employeeCode_Saved") else {
print("serious problem, there's no code saved")
// at this point the app is completely buggered, so give up
return ""
}
return e + c
}
Do note that the return is largely meaningless - in the app in question, if one of the guards breaks you are "totally screwed". I'd probably just return a blank string (or more likely something like "name_error") since at this point the app architecture is hopelessly broken.
(Sidenote: use UserDefaults.standard.string(forKey:).)
The issue is that you can't know if those strings DO both exist or not--if they do, you already have a great if let that returns your answer. The question now is what do you want to do if one or both are nil? Maybe you'd like to return nil from the entire function. If so,
func createEmployeeCode() -> String? {
let email = UserDefaults.standard.string(forKey: "email_Saved")
let employeeCode = UserDefaults.standard.string(forKey: "employeeCode_Saved")
if let emailString = email,
let employeeCodeString = employeeCode {
return (emailString+employeeCodeString) //successful unwrapping, let's concatenate!
}
return nil //if one or both `if let`s fail, we end up here
}
Of course, you could do whatever you'd like in that "bad" case. Maybe you'd like to show whatever string you DO have. In that case:
func createEmployeeCode() -> String {
let email = UserDefaults.standard.string(forKey: "email_Saved")
let employeeCode = UserDefaults.standard.string(forKey: "employeeCode_Saved")
return (email ?? "") + (employeeCode ?? "") //this works in the "good" case, too, and uses the nil coalescing operator `??`
}
In this case, you can see that the return value is no longer optional. This is because even if neither string exists, it'll concatenate two empty strings. If this feels icky, you could keep your optional return value and do a quick check before returning:
if email == nil && employeeCode == nil { return nil }
func createEmployeeCode() -> String {
var finalString = String()
if let email = UserDefaults.standard.string(forKey: "email_Saved"), let employeeCode = UserDefaults.standard.string(forKey: "employeeCode_Saved") {
finalString = email + employeeCode
}
return finalString
}
When assign back the values from userDefaults you've been trying to get as an object instead of string
func createEmployeeCode() -> String? {
let email:String = UserDefaults.standard.string(forKey: "email_Saved") ?? ""
let employeeCode:String = UserDefaults.standard.string(forKey: "employeeCode_Saved") ?? ""
let emailString = "\(email)\(employeeCode)"
return emialString
}
There are different ways to solve this depending on what you're trying to achieve.
If you always want to create an employeeCode (even if the code will be empty):
Try using a "nil coalescing operator".
func createEmployeeCode() -> String {
let email = UserDefaults.standard.object(forKey: "email_Saved") as? String ?? ""
let employeeCode = UserDefaults.standard.object(forKey: "employeeCode_Saved") as? String ?? ""
return (email+employeeCode)
}
To explain what's happening here:
We're unwrapping email, if we don't find email then we default the value to an empty string, "".
We do the same with employeeCode.
This isn't a way I would solve every unwrap issue though, but it suits your usecase of email and employeeCode because you're always wanting to return something based on your original question. I've also changed the return type to non-optional.
If an employee code must always contain an email and and a code then we want to return nil if one of those isn't found.
Try using the guard statement. The guard statement is perfect for validation and very readable:
func createEmployeeCode() -> String? {
guard let email = UserDefaults.standard.object(forKey: "email_Saved") as? String else { return nil }
guard let employeeCode = UserDefaults.standard.object(forKey: "employeeCode_Saved") as? String else { return nil }
return (email+employeeCode)
}
Try this function:
func createEmployeeCode() -> String {
let email = UserDefaults.standard.object(forKey: "email_Saved") as? String
let employeeCode = UserDefaults.standard.object(forKey: "employeeCode_Saved") as? String
return [email, employeeCode].compactMap { $0 }.joined(separator: "")
}
It will return email or employeeCode or email+employeeCode in case one of them is nil or both are present, or empty String in case if both are missed out!
I'm still learning to code so please don't shoot me for asking a question. I have tried to find an answer however I haven't found anything on stack overflow that can help, nor within a couple of books I have...
I am using Xcode 11.3. I am trying to copy an address variable from inside a reverse geolocation function to a global variable. However, because the function uses guard statements and nested if's, Xcode wants me to place 'self' infront of my syntax when I try and assign the address. This is fine in that it works, however when the method has finished the global variable is empty and it seems that the address value is only held whilst that method/procedure is executing.
Is there anyway to get the data into a 'global variable' and not to some instance running inside the method? I have added comments at the base of the code where I am trying to give my global variable the contents of the address location (street number, street name and suburb).
My function (method):
// Uses MapKit Delegate
func mapView(_ mapView: MKMapView, regionDidChangeAnimated animated: Bool) {
//let center = getCenterLocation(for: theMapView)
let center = getCenterLocation(for: theMapView)
let geoCoder = CLGeocoder()
guard let previousLocation = self.previousLocation else { return }
guard center.distance(from: previousLocation) > 100 else { return }
self.previousLocation = center
// The next little bit is mainly error checking stuff
geoCoder.reverseGeocodeLocation(center) { [weak self] (placemarks, error) in
guard let self = self else { return }
if let _ = error {
//TODO: Show alert informing the user
self.myAlertToolbar()
return
}
guard let placemark = placemarks?.first else {
//TODO: Show an alert to the user
self.myAlertToolbar()
return
}
let streetNumber = placemark.subThoroughfare ?? ""
let streetName = placemark.thoroughfare ?? ""
let suburb = placemark.locality ?? ""
if streetName == "" {
DispatchQueue.main.async {
self.addressLabelOutlet.text = "\(suburb)"
}
} else {
DispatchQueue.main.async {
// I want to be able to assign the streetNumber streetName and suburb over to a
// global variable without using self.blahblahblah
self.addressLabelOutlet.text = "\(streetNumber) \(streetName), \(suburb)"
self.myGlobalAddressVariable = String(streetNumber) + streetName + ", " + suburb
print("Address is \(self.myGlobalAddressVariable)")
}
}
}
}
I am making a simple app, and implementing the userInformation part. The user can edit his info, but I have trouble that if user doesn't put any info, it will crash when I try to retrieve data from an undefined column.
This is my code to retrieve the user data.now I can check a specific value, but still, I got a error with 'undefined' one.
var query = PFQuery(className: "Note")
query.getObjectInBackgroundWithId("kg8KhAWCms", block: {
(obj, error)in
if let obj = obj! as? PFObject {
let nickname = (obj.objectForKey("text")) as! String
if (nickname != nil) {
///// I have a error message that binary operator'!=' cannot be applied to operands of type 'String' and 'NiLiteralConvertible'
self.nickNameLabel.text = nickname
}else{
self.nickNameLabel.text = "you don't have a nick name"
}
} else {
print(error)
}
})
what is the 'NiLiteralConvertible' ?
and I've tried this as well,
var query = PFQuery(className: "Note")
query.getObjectInBackgroundWithId("kg8KhAWCms", block: {
(obj, error)in
if let obj = obj! as? PFObject {
let nickname = (obj.objectForKey("text")) as! String
if !(nickname.isEmpty) {
self.nickNameLabel.text = nickname
}else{
self.nickNameLabel.text = "you don't have a nick name"
}
} else {
print(error)
}
})
So I am asking how can I handle retrieving undefined value before crash? (please write full code for me)
///like this
if (undefined in parse == somekindOfType) {
print("yes")
}
You can't use nickname != nil because you have already said that it cannot be nil with let nickname = (obj.objectForKey("text")) as! String.
The as! String unwraps the obj.objectForKey("text") and at which it cannot be nil or you will get an error.
I suggest using the following:
if let nickname = obj.objectForKey("text") as? String {
self.nickNameLabel.text = nickname
}
else{
self.nickNameLabel.text = "you don't have a nick name"
}
Perhaps this would be beneficial to read: Swift Literal Convertibles