Referencing Entity Attribute in Swift 3 (Core Data) - ios

I'm following a very simple swift course and while everything works for the instructor the same code does not execute on my side and I'm trying to understand why is that happening.
The app is very simple, is consists of adding tasks to a TableView with a name and a switch to determine if those are important (in which case an emoji is added to the name)
While trying to access and modify the "name" attribute of my "Taskentity" core data entity, the editor gives me the error "Value of type "Taskentity" has no member "name"".
The code is the following :
import UIKit
class AddTaskViewController: UIViewController {
#IBOutlet weak var textField: UITextField!
#IBOutlet weak var isImp: UISwitch!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
#IBAction func btnTapped(_ sender: Any) {
let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
let task = Taskentity(context: context)
task.name = textField.text! // **!error!**
task.isImportant = isImp.isOn
(UIApplication.shared.delegate as! AppDelegate).saveContext()
navigationController!.popViewController(animated: true)
}
}
And my Core Data file looks like this :
Thanks for any help!

Your screen shot shows the problem perfectly. You have named the attribute corename, not name. So naturally the name name is not its name!

You have a problem with you attributes. The one titled 'corename' which is a string should be renamed to 'name' Xcode cannot tell what .name means because you have nothing that Devi gets what it is.
I have attached how your code should look to fix this problem:
import UIKit
class AddTaskViewController: UIViewController {
#IBOutlet weak var textField: UITextField!
#IBOutlet weak var isImp: UISwitch!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
#IBAction func btnTapped(_ sender: Any) {
let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
let task = Taskentity(context: context)
task.corename = textField.text! // **!error!**
task.isImportant = isImp.isOn
(UIApplication.shared.delegate as! AppDelegate).saveContext()
navigationController!.popViewController(animated: true)
}
}

Related

How to pass Item from initial (one time) first time view controller to main view controller and save that data using core data

I have been working on this issue for two days now and sadly I cannot figure out the issue to my problem. I'm trying to take one item from my initial one time view controller and send that to my main view controller where it will be saved within the main view controller and will appear upon that controller when reloading the app.
Here is my app delegate code for the "first time" view controller
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
if UserDefaults.standard.bool(forKey: "firstTimer") {
let storyBoard = UIStoryboard.init(name: "Main", bundle: nil)
let mainView = storyBoard.instantiateViewController(withIdentifier: "MainViewControllerID")
let nav = UINavigationController(rootViewController: mainView)
nav.navigationBar.isHidden = true
self.window?.rootViewController = nav
}
return true
}
containers and saveContext are default
import UIKit
import CoreData
class FirstTimeViewController: UIViewController {
let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
private var appDelegate = UIApplication.shared.delegate as! AppDelegate
private var player = [Player]()
#IBOutlet weak var nameTextField: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
// This View Controller will only be used once upon the first time the app is being used.
// MARK: Make func that prepares for segue on initial opening of app
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "toMainViewController" {
let mainViewController = segue.destination as! UINavigationController
let destination = mainViewController.topViewController as! MainViewController
if let newPlayer = self.nameTextField.text{
destination.name.name = newPlayer
destination.playerData.name = newPlayer
saveItems()
}
}
}
#IBAction func continueButtonPressed(_ sender: UIStoryboardSegue) {
UserDefaults.standard.set(true, forKey: "firstTimer")
let mainPlayer = PlayerData()
let player1 = Player(entity: Player.entity(), insertInto: context)
player1.name = mainPlayer.name
performSegue(withIdentifier: "toMainViewController", sender: self)
saveItems()
}
func saveItems() {
do {
try context.save()
print("File Successfully saved!")
}catch {
print("Error saving Context \(error)")
}
}
// MARK: Function to Save and Load data??
/*
// MARK: - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
// Get the new view controller using segue.destination.
// Pass the selected object to the new view controller.
}
*/
func loadItems() {
let request = Player.fetchRequest() as NSFetchRequest<Player>
do {
player = try context.fetch(request)
print("Info loaded")
} catch {
print("Error fetching data from context \(error)")
}
}
}
MainViewController being sent the information. I only want to send one item and save it to that main view controller.
import UIKit
import Foundation
import CoreData
class MainViewController: UIViewController {
//set up model object, buttons, and labels
// let player: Player!
let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
private var appDelegate = UIApplication.shared.delegate as! AppDelegate
// lazy var nameText = Player(context: context)
// var playerInfo = [Player]()
lazy var player = [Player]()
let playerData = PlayerData()
var name = ""
#IBOutlet weak var playerName: UILabel!
#IBOutlet weak var currentLevel: UILabel!
#IBOutlet weak var xpCounter: UILabel!
#IBOutlet weak var playerProfileImage: UIImageView!
override func viewDidLoad() {
super.viewDidLoad()
// loadItems()
// name = playerData.name
if let nameOfPlayer = name.name {
print("This is what we see: \(nameOfPlayer)")
playerName.text = nameOfPlayer
}
appDelegate.saveContext()
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
// loadView()
}
#IBAction func menuButtonPressed(_ sender: Any) {
}
func loadItems() {
let request = Player.fetchRequest() as NSFetchRequest<Player>
do {
player = try context.fetch(request)
print("Info loaded")
} catch {
print("Error fetching data from context \(error)")
}
}
// MARK : Add Name to Main View
// MARK : Add Xp To Main View
// MARK : Add UI Image to profile image view
// MARK: (Optional) Create a 'Choose a task button to segue to the task tab'
// MARK: Program the Progress Bar to update on xp gained and reset on level up
// MARK: Function to Save and Load data??
}
If dataSource code needed I will add upon request.
Thanks!
Code is wrong. You should do more check
This is what I was able to achieve:
import UIKit
import CoreData
class FirstTimeViewController: UIViewController {
private var player = [Player]()
private var appDelegate = UIApplication.shared.delegate as! AppDelegate
private let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
#IBOutlet weak var nameTextField: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
// This View Controller will only be used once upon the first time the app is being used.
// MARK: Make func that prepares for segue on initial opening of app
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "toMainViewController" {
let entity = NSEntityDescription.entity(forEntityName: "Player", in: context)
let newPlayer = NSManagedObject(entity: entity!, insertInto: context)
if let newUser = self.nameTextField.text{
newPlayer.setValue(newUser, forKey: "name")
print("This is what i got: ", newPlayer)
}
appDelegate.saveContext()
}
}
#IBAction func continueButtonPressed(_ sender: UIStoryboardSegue) {
UserDefaults.standard.set(true, forKey: "firstTimer")
performSegue(withIdentifier: "toMainViewController", sender: self)
}
And for the Main View Controller:
import UIKit
import Foundation
import CoreData
class MainViewController: UIViewController {
//set up model object, buttons, and labels
let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
private var appDelegate = UIApplication.shared.delegate as! AppDelegate
lazy var player = [Player]()
#IBOutlet weak var playerName: UILabel!
#IBOutlet weak var currentLevel: UILabel!
#IBOutlet weak var xpCounter: UILabel!
#IBOutlet weak var playerProfileImage: UIImageView!
override func viewDidLoad() {
super.viewDidLoad()
let request = NSFetchRequest<NSFetchRequestResult>(entityName: "Player")
// request.predicate = NSPredicate(format: "name = %#", "noon")
request.returnsObjectsAsFaults = false
do {
let result = try context.fetch(request)
for data in result as! [NSManagedObject] {
print(data.value(forKey: "name") as! String)
self.playerName.text = data.value(forKey: "name") as? String
}
} catch {
print("Failed")
}
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
// loadView()
}
#IBAction func menuButtonPressed(_ sender: Any) {
}

data not showing up in firebase database

im attempting to add user data via a create account view controller which contains all UITextFields (password, confirm password, first name, last name, phone number). when the create account button is tapped, the users email shows up in the authentication section on the firebase website but the user information from the first name, last name and phone number text fields are not passed into the database. I'm new to iOS development and have never used firebase so im unsure what the issue is. the app runs without crashing.
below is my Create Account view controller
thanks in advance
import UIKit
import FirebaseAuth
import QuartzCore
import FirebaseDatabase
import Firebase
class CreateAccount: UIViewController {
var refUsers: DatabaseReference!
#IBOutlet weak var emailTextField: UITextField!
#IBOutlet weak var passwordTextField: UITextField!
#IBOutlet weak var confirmPasswordTextField: UITextField!
#IBOutlet weak var firstNameTextField: UITextField!
#IBOutlet weak var lastNameTextField: UITextField!
#IBOutlet weak var phoneNumberTextField: UITextField!
#IBOutlet weak var alreadyHaveAccountLabel: UILabel!
#IBAction func loginButtonTapped(_ sender: Any) {
performSegue(withIdentifier: "showLoginScreen", sender: self)
}
override func viewDidLoad() {
super.viewDidLoad()
self.refUsers = Database.database().reference().child("Users");
// Do any additional setup after loading the view.
}
override func viewDidAppear(_ animated: Bool) {
if Auth.auth().currentUser != nil {
print("success")
self.presentMainScreen()
}
}
#IBAction func createAccountTapped(_ sender: Any) {
if let email = emailTextField.text, let password = passwordTextField.text {
Auth.auth().createUser(withEmail: email, password: password, completion:{ user, error in
if let firebaseError = error {
print(firebaseError.localizedDescription)
return
} else {
self.addUser()
print("this is the first name:", self.firstNameTextField.text!)
print("this is the last name:", self.lastNameTextField.text!)
print("this is the phone number" , self.phoneNumberTextField.text!)
print("success")
self.presentMainScreen()
}
})
}
}
func addUser(){
let key = refUsers.childByAutoId().key
let user = ["id":key,
"FirstName":firstNameTextField.text! as String,
"LastName":lastNameTextField.text! as String,
"PhoneNumber":phoneNumberTextField.text! as String
]
refUsers.child(key).setValue(user)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
/*
// MARK: - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
// Get the new view controller using segue.destinationViewController.
// Pass the selected object to the new view controller.
}
*/
func presentMainScreen(){
let mainstoryboard = UIStoryboard(name: "Main", bundle: nil)
let mainTabController = mainstoryboard.instantiateViewController(withIdentifier: "MainTabController") as! MainTabController
mainTabController.selectedViewController = mainTabController.viewControllers?[0]
self.present(mainTabController, animated: true, completion: nil)
//let storyboard:UIStoryboard = UIStoryboard(name:"Main", bundle:nil)
//let loggedInVC:LoggedInVC = storyboard.instantiateViewController(withIdentifier: "LoggedInVC") as! LoggedInVC
//self.present(loggedInVC, animated: true, completion: nil)
}
}
Try this:
Instead of set value use update value
let childUpdates = ["/user/\(key)": user]
refUser.updateChildValues(childUpdates)
Hope this helps :)

iOS Swift - Properties not updating after preparing for segue

I am trying to pass a news ID of type string to the second VC and load the object based on it from Realm. When I debugged, I found that the prepare for segue is correctly setting the detailNewsVC.newsID to the primary key of my news item but the second VC is not receiving it. Any help on this?
Checks I have made:
Made sure that the detail VC identifier is correct
detailNewsVC.newsID in VC 1 is correctly setting the news ID .. This is to make sure that realm is correctly sending the newsID and it is working fine.
Changed the viewDidLoad in VC 2 to viewWillLoad..Just to make sure that second vc is not loaded before for any reason but no luck on that.
Restarted xcode
Replaced newsID in VC 2 with an actual news primary key and it's correctly pulling the related news. I think the culprit is that the VC2 property: newsID is not updating when prepare for segue is called.
First VC code for prep for segue:
extension HomeVC: UICollectionViewDelegate {
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == SegueIdentifier.gotodetail.rawValue, let sendNewsID = sender as? String {
let navVC = segue.destination as? UINavigationController
let detailNewsVC = navVC?.viewControllers.first as! DetailNewsVC
detailNewsVC.newsID = sendNewsID
print("Detail News ID = \(detailNewsVC.newsID)")
}
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
let newsID = newsArray[indexPath.row].newsId
performSegue(withIdentifier: SegueIdentifier.gotodetail.rawValue, sender: newsID)
}
}
Second VC Code:
class DetailNewsVC: UIViewController {
#IBOutlet private weak var scrollView: UIScrollView!
#IBOutlet private weak var newsTitle: UILabel!
#IBOutlet private weak var newsImage: UIImageView!
#IBOutlet private weak var newsDescription: UILabel!
var newsID = ""
override func viewDidLoad() {
super.viewDidLoad()
let realm = try! Realm()
print("News ID: \(newsID)")
guard let news = realm.object(ofType: News.self, forPrimaryKey: newsID as AnyObject) else {
print("Cannot load news")
return
}
print(news)
newsTitle.text = news.newsTitle
if let url = URL(string: news.urlToImage), let data = try? Data.init(contentsOf: url) {
newsImage.image = UIImage(data: data)
}
newsDescription.text = news.newsDescription
}
}
Move your prepare function out of the extension and put it in HomeVC. According to Apple's Swift Guide extensions cannot override existing functionality.
Extensions can add new functionality to a type, but they cannot override existing functionality.
Apple Developer Guide
It's hard to tell in which order UIKit calls the UIViewController methods, but it might be possible that viewDidLoad is getting called before you get the chance to set the value of newsID.
The following might be overkill, but it'll guarantee the views will be updated during viewDidLoad, or otherwise if newsID is set after the fact:
class DetailNewsVC: UIViewController {
#IBOutlet private weak var scrollView: UIScrollView!
#IBOutlet private weak var newsTitle: UILabel!
#IBOutlet private weak var newsImage: UIImageView!
#IBOutlet private weak var newsDescription: UILabel!
public var newsID = "" {
didSet {
updateUIForNews()
}
}
override func viewDidLoad() {
super.viewDidLoad()
updateUIForNews()
}
private func updateUIForNews() {
guard !newsID.isEmpty else {
return
}
let realm = try! Realm()
print("News ID: \(newsID)")
guard let news = realm.object(ofType: News.self, forPrimaryKey: newsID as AnyObject) else {
print("Cannot load news")
return
}
print(news)
newsTitle.text = news.newsTitle
if let url = URL(string: news.urlToImage), let data = try? Data.init(contentsOf: url) {
newsImage.image = UIImage(data: data)
}
newsDescription.text = news.newsDescription
}
}

Unresolved identifier using segue when passing data

In my app I am using segue to pass data between two viewcontrollers and that should be easy enough, but for som reason I can`t see there I keep getting "Unresolved Identifier"
Her are some of the code that has to do with that function.
from ViewController 1
import UIKit
import CoreData
class ViewController: UIViewController, UITextFieldDelegate
{
#IBOutlet var panelWidthTextField: UITextField!
#IBOutlet var panelHightTextField: UITextField!
#IBOutlet var panelsWideTextField: UITextField!
#IBOutlet var panelsHightTextField: UITextField!
#IBOutlet var panelPitchTextField: UITextField!
#IBOutlet var calculateButton: UIButton!
#IBOutlet var resultWithLabel: UILabel!
#IBOutlet var resultHightLabel: UILabel!
#IBOutlet var fillAllFieldsLabel: UILabel!
var pawidth:String!
var pahight:String!
var papitch:String!
override func viewDidLoad()
{
super.viewDidLoad()
panelWidthTextField.text = pawidth
panelHightTextField.text = pahight
panelPitchTextField.text = pap itch
From Second ViewController
import UIKit
import CoreData
class DataBase: UIViewController, UITextFieldDelegate
{
#IBOutlet var makerTextField: UITextField!
#IBOutlet var modelTextField: UITextField!
#IBOutlet var stPanelWidthTextField: UITextField!
#IBOutlet var stPanelHightTextField: UITextField!
#IBOutlet var stPitchTextField: UITextField!
let moc = (UIApplication.sharedApplication().delegate as! AppDelegate).managedObjectContext
// Removes keyboard when touch outside edit field.
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?)
{
view.endEditing(true)
super.touchesBegan(touches, withEvent: event)
}
#IBAction func saveButton(sender: UIButton)
{
let ed = NSEntityDescription.entityForName("Ledinfo", inManagedObjectContext: moc)
let model = Ledinfo(entity:ed!, insertIntoManagedObjectContext:moc)
model.manufactor = makerTextField.text
model.model = modelTextField.text
model.panelwidth = stPanelWidthTextField.text
model.panelhight = stPanelHightTextField.text
model.pitch = stPitchTextField.text
do {
try moc.save()
makerTextField.text = ""
modelTextField.text = ""
stPanelWidthTextField.text = ""
stPanelHightTextField.text = ""
stPitchTextField.text = ""
Alert.show("Succsess", message: "Your Record Is Saved", vc: self)
}
catch _ as NSError
{
Alert.show("Failed", message: "Something Went Wrong", vc: self)
}
}
#IBAction func searchButton(sender: UIButton)
{
let ed = NSEntityDescription.entityForName("Ledinfo", inManagedObjectContext: moc)
let req = NSFetchRequest()
req.entity = ed
let cond = NSPredicate(format: "manufactor = %#", makerTextField.text!)
req.predicate = cond
do {
let result = try moc.executeFetchRequest(req)
if result.count > 0
{
let model = result[0] as! Ledinfo
makerTextField.text = model.manufactor
modelTextField.text = model.model
stPanelWidthTextField.text = model.panelwidth
stPanelHightTextField.text = model.panelhight
stPitchTextField.text = model.pitch
} else
{
Alert.show("Failed", message: "No Record Is Found", vc: self)
}
} catch _ as NSError!
{
Alert.show("Failed", message: "No Record Is Found" , vc: self)
}
}
#IBAction func transfereButton(sender: UIButton) {
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject!) {
if (segue.identifier == "transfereButton") {
let svc = segue.destinationViewController as! ViewController
svc.pawidth = stPanelWidthTextField.text
svc.pahight = stPanelHightTextField.text
svc.papitch = stPitchTextField.text
}
}
}
It can not find panelWidthTextField.text, panelHightTextField.text and panelPitchTextField.text as identifier.
I have check spelling and just can`t seem to be able to find what is missing.
Any help is appreciated
"Segue" means, that in "prepareForSegue" method you set the property of ViewController to some data in your DataBase controller. In your example, this can be done like this:
svc.pawidth = someDataFromDataBaseWhichYouWantToPassToSecondVC
svc.pahight = someDataFromDataBaseWhichYouWantToPassToSecondVC
svc.papitch = someDataFromDataBaseWhichYouWantToPassToSecondVC
And then, you can manipulate this data from your ViewController class.
You mistake that you are not passing the data from one VC to another, instead of that you are trying to set the property of 1stVC to another property of 1stVC, and there is no segue needed.
This has nothing to do with segues. do you have 3 text fields in your DataBase class with names panelWidthTextField, panelHightTextField and panelPithcTextField? It's complaining about not being able to find those variables.
You should call the performSegueWithIdentifier("transfereButton", sender: nil) inside your transfereButton IBOutlet action to actually make the prepareForSegue to run.

No text shown at NSUserDefaults

I have two view controllers and I want to store the "name" entered in the second and to be shown in the first one. I already made it work that a value is stored, and now I want to store the name entered by the user.
So here's the code of the view controller where the name should be shown:
import UIKit
var name = [String]()
class profile: UIViewController {
//Name
#IBOutlet weak var nameTextField: UILabel!
var vornameLabel = String()
override func viewDidLoad() {
super.viewDidLoad()
//Name
nameTextField.text = "\(name)"
//Vorname speichern
NSUserDefaults.standardUserDefaults().setObject(name, forKey: "vorname")
name = NSUserDefaults.standardUserDefaults().objectForKey("vorname") as! [String]
}
And this is the code of second view controller where the "name" is entered:
import UIKit
class profileSettings: UIViewController {
#IBOutlet weak var vornameLabel: UITextField!
#IBOutlet weak var nachnameLabel: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
#IBAction func addInformation(sender: AnyObject) {
vornameLabel.text = "\(name)"
NSUserDefaults.standardUserDefaults().setObject(name, forKey: "vorname")
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
//in Profil
var destProfile:profile = segue.destinationViewController as! profile
destProfile.vornameLabel = vornameLabel.text
destProfile.nachnameLabel = nachnameLabel.text
}
}
1) If the user is entering their name and that is going into vornameLabel successfully then in addInformation() you are overwriting what ever the user entered into vornameLable with "(name)" so you have now lost what the user entered.
2) name is not being set to anything (unless you have that in another part of your code that you have not shown)
3) So 1 and 2 together means vornameLable contains nothing.
4) Even if vornameLable did contain something, then in viewDidLoad() you are calling setObject which will overwrite any value that was stored to NSUserDefaults with whatever is in name.
I think you need to show more code, this can't be all of it.If it is then it not doing anything.
Updated after receiving info the posted code is all there is:
a) name doesn't contain anything, therefore you are not saving anything to defaults. Change it to var name = "My name".
b) Change vornameLabel.text = "(name)" tp vornameLabel.text = name
c) change NSUserDefaults.standardUserDefaults().setObject(name, forKey: "vorname") to NSUserDefaults.standardUserDefaults().setObject(vornameLable.text, forKey: "vorname")
d) remove NSUserDefaults.standardUserDefaults().setObject(name, forKey: "vorname") in viewDidLoad
Yeah, set your values in viewWillAppear:
override func viewWillAppear(animated: Bool)
{
super.viewWillAppear(animated)
name = NSUserDefaults.standardUserDefaults().objectForKey("vorname") as! [String]
nameTextField.text = "\(name)"
}

Resources