Is there anyway to insert entities with relationship? I get error "Illegal attempt to establish a relationship 'content' between objects in different contexts"
addUsers(users: [userData])
func addUsers(users: [User]) {
let taskContext = container.viewContext
taskContext.perform {
let batchInsertRequest = self.newBatchInsertRequest(with: users)
if let fetchResult = try? taskContext.execute(batchInsertRequest),
let batchInsertResult = fetchResult as? NSBatchInsertResult,
let success = batchInsertResult.result as? Bool, success {
return
}
}
}
crash happens in below code
private func newBatchInsertRequest(with users: [Users]) -> NSBatchInsertRequest {
var index = 0
let total = message.count
let batchInsertRequest = NSBatchInsertRequest(entity: WaUser.entity(), managedObjectHandler: { managedObject in
guard index < total else { return true }
let user = users[index]
if let waUser = managedObject as? WaUser {
waUser.name = user.name
let waUserInfo = waUserInfo(context: self.container.viewContext)
waUserInfo.pass = "12345"
waUserInfo.key = "asdfgh"
waUser.info = waUserInfo **//crash occurs here**
}
index += 1
return false
})
return batchInsertRequest
}
I want to pull details from local database but when I do the necessary operations, it returns null as a result. I can't understand where I went wrong.
var chosenCar=""
var chosenCarId : UUID?
the arrays I created, I transfer data to these arrays, there is no problem with that, I did a test
if chosenCar != "" {
//core data
let appDelegate = UIApplication.shared.delegate as! AppDelegate
let context = appDelegate.persistentContainer.viewContext
let fetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: "CarsInformation")
let idString = chosenCarId?.uuidString
fetchRequest.predicate = NSPredicate(format: "id = %#", idString!)
fetchRequest.returnsObjectsAsFaults = false
do {
let results = try context.fetch(fetchRequest)
if results.count > 0 {
for result in results as! [NSManagedObject] {
if let name = result.value(forKey: "models") as? String {
modelTextField.text = name
}
if let year = result.value(forKey: "year") as? Int {
yearTextField.text = String(year)
}
if let price = result.value(forKey: "price") as? Int {
priceTextField.text = String(price)
}
if let imageData = result.value(forKey: "image") as? Data {
let image = UIImage(data: imageData)
imageView.image = image
}
}
}
} catch{
print("error")
}
} else {
modelTextField.text = ""
priceTextField.text = ""
yearTextField.text = ""
}
After doing these operations, I can't get the result I want.
I am trying to fetch data from firebase firestore. The problem i have is that my fetch is returning the results x4 times. For example when i do print(name) it print the users name x4 times.
I think there may be a loop that is not working correctly?
// fetches and returns all conversations for the user with passed in uid
public func getAllConversations(for uid: String, completion: #escaping(Result<[Conversation], Error>) -> Void) {
let CurrentUser = Auth.auth().currentUser?.uid
let db = Firestore.firestore()
let ConversationRef = db.collection("users").document(CurrentUser!).collection("conversations").document(
"jVymlfbpuAYQQ9Brf8SbUZ7KCGg1")
// get the otherUserUId TO DO
ConversationRef.getDocument { snapshot, error in
if error != nil {
print("Error connecting to database")
} else {
if let document = snapshot {
if document.exists {
let data = document.data()
print(data)
let conversations: [Conversation] = data!.compactMap ({ dictionary in
guard let conversationId = data!["id"] as? String,
let name = data!["name"] as? String,
let otherUserUid = data!["other_user-uid"] as? String,
let latestMessage = data!["latest-message"] as? [String:Any],
let date = latestMessage["date"] as? String,
let message = latestMessage["message"] as? String,
let isRead = latestMessage["is-read"] as? Bool
else {
return nil
}
print(name)
let latestMessageObject = LatestMessage(date: date, text: message, isRead: isRead)
return Conversation(id: conversationId, name: name, otherUserUid: otherUserUid, latestMessage: latestMessageObject)
})
completion(.success(conversations))
}
else {
completion(.failure(DatabaseError.failedToFetch))
return
}
}
}
}
}
Please note that ConversationRef.getDocument{..} will only Return One Specific Document, which you’re Referring here :
let ConversationRef = db.collection("users").document(CurrentUser!).collection("conversations").document("jVymlfbpuAYQQ9Brf8SbUZ7KCGg1”)
So the let data = document.data()
will be single [String:Any] object(in this case Single ‘Conversation’),
not the Array of Dictionaries(eg: [Conversations]).
Try doing it this way:
// fetches and returns all conversations for the user with passed in uid
public func getAllConversations(for uid: String, completion: #escaping(Result<Conversation, Error>) -> Void) {
let CurrentUser = Auth.auth().currentUser?.uid
let db = Firestore.firestore()
let ConversationRef = db.collection("users").document(CurrentUser!).collection("conversations").document(
"jVymlfbpuAYQQ9Brf8SbUZ7KCGg1")
// get the otherUserUId TO DO
ConversationRef.getDocument { snapshot, error in
if error != nil {
print("Error connecting to database")
} else {
if let document = snapshot {
if document.exists {
if let data = document.data() {
if let conversationId = data["id"] as? String,
let name = data["name"] as? String,
let otherUserUid = data["other_user-uid"] as? String,
let latestMessage = data["latest-message"] as? [String:Any],
let date = latestMessage["date"] as? String,
let message = latestMessage["message"] as? String,
let isRead = latestMessage["is-read"] as? Bool {
print(name)
let latestMessageObject = LatestMessage(date: date, text: message, isRead: isRead)
let conversations = Conversation(id: conversationId, name: name, otherUserUid: otherUserUid, latestMessage: latestMessageObject)
completion(.success(conversations))
}
}
}
else {
completion(.failure(DatabaseError.failedToFetch))
return
}
}
}
}
}
// fetches and returns all conversations for the user with passed in uid
public func getAllConversations(for uid: String, completion: #escaping(Result<[Conversation], Error>) -> Void) {
let CurrentUser = Auth.auth().currentUser?.uid
let db = Firestore.firestore()
let ConversationRef = db.collection("users").document(CurrentUser!).collection("conversations")
ConversationRef.addSnapshotListener { snapshot, error in
if error != nil {
print("Error connecting to database")
} else {
guard let snap = snapshot else {
completion(.failure(DatabaseError.failedToFetch))
return
}
for document in snap.documents {
let data = document.data()
print(data)
guard let conversationId = data["id"] as? String,
let name = data["name"] as? String,
let otherUserUid = data["other_user-uid"] as? String,
let latestMessage = data["latest-message"] as? [String:Any],
let date = latestMessage["date"] as? String,
let message = latestMessage["message"] as? String,
let isRead = latestMessage["is-read"] as? Bool else {
return
}
print(name)
let latestMessageObject = LatestMessage(date: date, text: message, isRead: isRead)
let conversations = [Conversation(id: conversationId, name: name, otherUserUid: otherUserUid, latestMessage: latestMessageObject)]
completion(.success(conversations))
}
}
}
}
My swift code below when loaded places 3 items in the core data entity named "UserName". When the user enters a number into textfield enterT I want the label labelName to display it. So when the user enters 1 the label should display jessica biel because Jesical Biel is the first name entered. Someone stated the suggestion below to solve this problem. I dont know exactly how to do this.I have added a gif below.
Convert the entered number to Int. If this succeeds pass the integer to joke and fetch the record matching the idx attribute.
https://github.com/redrock34/index-fetch
import UIKit
import CoreData
class ViewController: UIViewController,UITextFieldDelegate {
#IBOutlet var labelName : UILabel!
#IBOutlet var enterT : UITextField!
lazy var context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
override func viewDidLoad() {
super.viewDidLoad()
openDatabse()
fetchData()
enterT.delegate = self
}
func textFieldDidEndEditing(_ textField: UITextField) {
guard let index = Int(textField.text!) else {
// display an alert about invalid text
return
}
joke(at: index - 1)
}
func joke(at index : Int) {
let fetchRequest = NSFetchRequest<Users>(entityName: "Users")
fetchRequest.predicate = NSPredicate(format: "idx == %d", Int32(index))
do {
if let user = try context.fetch(fetchRequest).first {
labelName.text = user.username
}
} catch {
print("Could not fetch \(error) ")
}
}
func openDatabse()
{
let names = ["kim kardashian", "jessica biel", "Hailey Rienhart"]
for i in 0..<names.count {
let newUser = Users(context: context)
newUser.username = names[i]
newUser.idx = Int32(i + 1)
}
print("Storing Data..")
do {
try context.save()
} catch {
print("Storing data Failed", error)
}
}
func fetchData()
{
print("Fetching Data..")
let request = NSFetchRequest<NSFetchRequestResult>(entityName: "Users")
request.returnsObjectsAsFaults = false
do {
let result = try context.fetch(request)
for data in result as! [NSManagedObject] {
let userName = data.value(forKey: "username") as! String
print("User Name is : "+userName)
}
} catch {
print("Fetching data Failed")
}
}}
Of course you have to assign values to the idx attribute and you have to assign the result of the fetch to the label.
First replace
let appDelegate = UIApplication.shared.delegate as! AppDelegate //Singlton instanc
var context:NSManagedObjectContext!
with
lazy var context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
Then replace both openDatabse and saveData with
func openDatabse()
{
let names = ["kim kardashian", "jessica biel", "Hailey Rienhart"]
for i in 0..<names.count {
let newUser = Users(context: context)
newUser.name = names[i]
newUser.idx = Int32(i + 1)
}
print("Storing Data..")
do {
try context.save()
} catch {
print("Storing data Failed", error)
}
}
Finally add a line in joke to display the value
func joke(at index : Int) {
let fetchRequest = NSFetchRequest<Users>(entityName: "Users")
fetchRequest.predicate = NSPredicate(format: "idx == %d", Int32(index))
do {
if let user = try context.fetch(fetchRequest).first {
labelName.text = user.username
}
} catch {
print("Could not fetch \(error) ")
}
}
It creates the records and assigns the proper indexes. Then entering a number in the text field should work.
But – once again – on each launch of the app the 3 records are inserted again with the same names and indexes. Be aware of that!
I am trying to save data into firebase, by first generating a child using .childByAutoId() and then update the child with the necessary data. But it doesn't seem to work as expected.
The structure I am trying to achieve is
events
attendees
-L0P1D5arR0OkBf8h
userEmail: "user#user.com"
userName: "User name"
userPhone: "0864567182"
Here's what I have done so far:
guard let fee = events?["eventFee"] else {
return
}
guard let key = events?["eventKey"] else {
return
}
guard let eventTitle = events?["title"] else {
return
}
if fee == "0" {
var values = [String: String]()
self.ref = Database.database().reference()
let attendeekey = ref.child("events").child(key).child("attendees").childByAutoId().key
let userDetails = UserDetails()
for user in userDetails.currentUserDetails {
guard let userEmail = user.email else {
return
}
guard let firstName = user.firstName, let lastName = user.lastName else {
return
}
guard let userPhone = user.phoneNo else {
return
}
let userName = "\(firstName) \(lastName)"
values = ["userEmail": userEmail, "userName": userName, "userPhone": userPhone as! String]
}
ref.updateChildValues(["events/\(key)/attendees/\(attendeekey)": values], withCompletionBlock: {
(err, ref) in
if err != nil {
self.displayAlertMessage(message: err as! String, title: "Oops!")
//print(err ?? "An error occured")
return
}
let message = "You have successfully registered for \(eventTitle)"
self.displayAlertMessage(message: message, title: "Success!")
})
}
Is anything wrong with my approach?