practicing Core Data in Swift save method creates new entry everytime - swift

I've been trying to figure out how Core Data works with using Swift. I don't think I'm grasping the proper concept of the whole thing. I get that I need to be interacting with Context to store data to PersistentContainer, but it seems everytime I press on save button, the data is stored as brand new. I want it to be able to update the existing row. Below is my code. Any help will be greatly appreciated. Thank you.
import UIKit
import CoreData
class ViewController: UIViewController {
var editNotes: Note?
let dataFilePath = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)
#IBOutlet weak var textView: UITextView!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
#IBAction func saveButton(_ sender: UIButton) {
print (dataFilePath)
print (sender.tag)
var new: Note?
if let note = editNotes {
new = note
} else {
new = Note(context: context)
}
new?.body = textView.text
new?.date = NSDate() as Date
do {
ad.saveContext()
self.dismiss(animated: true, completion: nil)
} catch {
print(“cannot save”)
}
}
}

Related

Why would NSWindowController return nil-value window property?

I'm using modal sheets (slide down from top) to get user input. I currently have 2 that I think are identical except for the UI, each a NIB + NSWindowController-subclass pair. One works as expected, binding input to an array controller and table view. When trying to use the other, the window property of the NSWindowController is nil.
This code works:
#IBAction func addItemButtonClicked(_ button: NSButton) {
let window = document?.windowForSheet
let windowController = NewItemSheetController()
windowController.typeChoices = newItemSheetTypeChoices
windowController.windowTitle = newItemSheetTitle
print(#function, windowController.window) // output below
window?.beginSheet(windowController.window!, completionHandler: { response in
// The sheet has finished. Did user click OK?
if response == NSApplication.ModalResponse.OK {
let structure = (self.newItemSheetController?.structure)!
self.document?.dataSource.structures.append(structure)
}
// All done with window controller.
self.newItemSheetController = nil
})
newItemSheetController = windowController
}
The output of the print statement: "addItemButtonClicked(_:) Optional()"
This code doesn't:
#IBAction func addItemButtonClicked(_ button: NSButton) {
let window = document?.windowForSheet
let windowController = NewRecurrenceItemSheetController()
windowController.windowTitle = newItemSheetTitle
print(#function, windowController.window)
window?.beginSheet(windowController.window!, completionHandler: { response in
// The sheet has finished. Did user click OK?
if response == NSApplication.ModalResponse.OK {
let recurrence = (self.newItemSheetController?.recurrence)!
self.document?.dataSource.recurrences.append(recurrence)
}
// All done with window controller.
self.newItemSheetController = nil
})
newItemSheetController = windowController
}
The output of the print statement: "addItemButtonClicked(_:) nil"
Classes NewItemSheetController and NewRecurrenceItemSheetController are subclasses of NSWindowController and differ only with NSNib.Name and properties related to differing UI. As far as I can see, the XIBs and Buttons are "wired" similarly. The XIBs use corresponding File's Owner. Window objects have default class.
#objcMembers
class NewItemSheetController: NSWindowController {
/// other properties here
dynamic var windowTitle: String = "Add New Item"
override var windowNibName: NSNib.Name? {
return NSNib.Name(stringLiteral: "NewItemSheetController")
}
override func windowDidLoad() {
super.windowDidLoad()
titleLabel.stringValue = windowTitle
}
// MARK: - Outlets
#IBOutlet weak var titleLabel: NSTextField!
#IBOutlet weak var typeChooser: NSPopUpButton!
// MARK: - Actions
#IBAction func okayButtonClicked(_ sender: NSButton) {
window?.endEditing(for: nil)
dismiss(with: NSApplication.ModalResponse.OK)
}
#IBAction func cancelButtonClicked(_ sender: NSButton) {
dismiss(with: NSApplication.ModalResponse.cancel)
}
func dismiss(with response: NSApplication.ModalResponse) {
window?.sheetParent?.endSheet(window!, returnCode: response)
}
}
Why does one return instantiate a windowController object with a nil-valued window property?
In Interface Builder, the XIB Window needed to be attached to File's Owner with a Window outlet and delegate. Thanks #Willeke.

Giving Usernames to users with Firebase & Swift

I am a new to programming, and right now I want to give my users a username and then store it in the firebase real time database. However, every time I run my code it comes up with:
Thread 1: signal SIGABRT
I have checked all of my #IB buttons etc for clashes but there is nothing that I can find. I think I have written code that may be out dated so I am hoping someone can shed some light on my situation and help out!
I think there error is coming from here:
import UIKit
import Firebase
class HandlerViewController: UIViewController {
#IBOutlet weak var username: UITextField!
var user : AnyObject?
var ref = DatabaseReference()
override func viewDidLoad() {
super.viewDidLoad()
self.user = Auth.auth().currentUser
ref = Database.database().reference()
// Do any additional setup after loading the view.
}
#IBAction func joinHaps(_ sender: Any) {
ref.child("Usernames").childByAutoId().setValue(username)
self.performSegue(withIdentifier:"HomeScreenOne", sender: nil)
}
}
In your crash log saying 'InvalidFirebaseData', reason: '(setValue:) Cannot store object of type UITextField at,
In this line your getting error, because setValue can't accept UITextField as input.
Change your code to :
#IBAction func joinHaps(_ sender: Any) {
//username is UITextfield, you can fetch text from it using .text
ref.child("Usernames").childByAutoId().setValue(username.text ?? "")
self.performSegue(withIdentifier:"HomeScreenOne", sender: nil)
}

Basic Sinch Sample in Swift - but no Sound

first of all thank you for reading my lines.
For an idea I'm currently trying to dive into the Swift world (I only have very basic programming knowledge - no Objective C knowledge
).
I tried to set up the following lines to create a very basic app-to-app sample in Sinch. After my code I let you know what the issues are.
import UIKit
import Sinch
var appKey = "APP_KEY_FROM_MY_ACCOUNT"
var hostname = "clientapi.sinch.com"
var secret = "SECRET_FROM_MY_ACCOUNT"
class CViewController: UIViewController, SINCallClientDelegate, SINCallDelegate, SINClientDelegate {
var client: SINClient?
var call: SINCall?
var audio: SINAudioController?
//Text field in the main storyboard
#IBOutlet weak var userNameSepp: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
self.initSinchClient()
}
//initialize and start the client as a fixed "userA"
func initSinchClient() {
client = Sinch.client(withApplicationKey: appKey, applicationSecret: secret, environmentHost: hostname, userId: "userB")
client?.call().delegate = self
client?.delegate = self
client?.startListeningOnActiveConnection()
client?.setSupportCalling(true)
client?.start()
}
//Did the Client start?
func clientDidStart(_ client: SINClient!) {
print("Hello")
}
//Did the Client fail?
func clientDidFail(_ client: SINClient!, error: Error!) {
print("Good Bye")
}
//Call Button in the main.storyboard ... if call==nil do the call ... else hangup and set call to nil
//the background color changes are my "debugging" :D
#IBAction func callSepp(_ sender: Any) {
if call == nil{
call = client?.call()?.callUser(withId: userNameSepp.text)
//for testing I change to callPhoneNumber("+46000000000").
// the phone call progresses (but I hear nothing),
// the phonecall gets established (but I hear nothing)
// and the phonecall gets ended (but of course I hear nothing)
self.view.backgroundColor = UIColor.red
call?.delegate = self
audio = client?.audioController()
}
else{
call?.hangup()
self.view.backgroundColor = UIColor.blue
call = nil
}
}
func callDidProgress(_ call: SINCall?) {
self.view.backgroundColor = UIColor.green
client?.audioController().startPlayingSoundFile("/LONG_PATH/ringback.wav", loop: true)
print("Call in Progress")
}
//I know that this works but I don't hear anything
func callDidEstablish(_ call: SINCall!) {
client?.audioController().stopPlayingSoundFile()
print("Call did Establish")
}
func callDidEnd(_ call: SINCall!) {
print("Call did end")
}
// this works fine
#IBAction func hangUpSepp(_ sender: Any) {
call?.hangup()
self.view.backgroundColor = UIColor.red
call = nil
}
// i work in a "sub view controller" - so i navigate here back to the main view controller
#IBAction func goBackMain(_ sender: Any) {
call?.hangup()
dismiss(animated: true, completion: nil)
client?.stopListeningOnActiveConnection()
client?.terminateGracefully()
client = nil
}
}
So I can call my private phone number or if I change to callUser I can call another app but I don't hear anything. What do I miss? It must have to do with the SINAudioController and the client's method audioController() but I don't know what I'm doing wrong. Thank you for your help.

Maintaining Button State when App is Re-opened with Swift/Xcode

I am new to Swift and Xcode, but I have been reading on here and watching videos on YouTube to guide me along with starting my app. I can't seem to get my button to save its state once the app is closed and re-opened. I used UserDefault To Save Button State as an example, but following it still did not get the button state saved.
I set the state with the Interface Builder and so far have the below code:
#IBAction func ownedButton(_ sender UIButton) {
sender.isSelected = !sender.isSelected
UserDefaults.standard.set(sender.isSelected, forKey: "isSaved")
UserDefaults.standard.synchronize()
}
Clicking the button will keep it selected until clicked again, so it is partially working. It looks like I need some code to in the viewDidLoad section, but I haven't been able to figure out what it should be.
Thank you for any help!
A habit from my Objective-C days is to write a wrapper around the properties in UserDefaults. This way, everything is compile-time checked and the use of strings as keys is minimized:
// Properties.swift
import Foundation
fileprivate var standardDefaults = UserDefaults.standard
class Properties {
static func registerDefaults() {
standardDefaults.register(defaults: [
kIsButton1Selected: false,
kIsButton2Selected: true
])
}
fileprivate static let kIsButton1Selected = "isButton1Selected"
static var isButton1Selected: Bool {
get { return standardDefaults.value(forKey: kIsButton1Selected) as! Bool }
set { standardDefaults.set(newValue, forKey: kIsButton1Selected) }
}
fileprivate static let kIsButton2Selected = "isButton2Selected"
static var isButton2Selected: Bool {
get { return standardDefaults.value(forKey: kIsButton2Selected) as! Bool }
set { standardDefaults.set(newValue, forKey: kIsButton2Selected) }
}
}
Then in your View Controller:
override func viewDidLoad() {
// Always call registerDefaults before you use UserDefaults
// for the first time in your app
Properties.registerDefaults()
button1.isSelected = Properties.isButton1Selected
button2.isSelected = Properties.isButton2Selected
}
#IBAction func ownedButton(_ sender: UIButton) {
sender.isSelected = !sender.isSelected
switch sender {
case button1:
Properties.isButton1Selected = sender.isSelected
case button2:
Properties.isButton2Selected = sender.isSelected
default:
break
}
}
You can replace the switch with key-value observing but remember to remove the KVO on deinit.

App crashes when trying to append data to a child value

I'm following the instructions as shown in firebase but I'm still getting crashes even after making sure that the text entry is type String.
Here's the error:
Terminating app due to uncaught exception 'InvalidPathValidation', reason: '(child:) Must be a non-empty string and not contain '.' '#' '$' '[' or ']''
and here's the code:
import UIKit
import Firebase
import FirebaseDatabase
import FirebaseAuth
class BioEditViewController: UIViewController {
#IBOutlet weak var bioTextView: UITextView!
let databaseRef = FIRDatabase.database().reference()
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
override func viewWillAppear(animated: Bool) {
let userID = FIRAuth.auth()?.currentUser?.uid
databaseRef.child("users").child(userID!).observeSingleEventOfType(.Value, withBlock: { (snapshot) in
// Get user level
let userBio = snapshot.value!["userBio"] as! String
self.bioTextView.text = userBio
})
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#IBAction func doneSave(sender: UIButton) {
let textView = bioTextView.text
self.dismissViewControllerAnimated(false, completion: nil)
databaseRef.child("users/(user.uid)/userBio").setValue(textView)
}
}
I'm just trying to update a specific child: userBio and not affect the entire object.
Warning
Avoid instantiating your database reference to a variable out of scope. Reason why :- Outside your scope, when you instantiate a class to a variable you don't know wether or not your FIRApp has already been configured or not, or in general if that class has even been initialised as of yet or not. Just provide a reference(!) to the variable and instantiate later in a scope.
Change:-
let databaseRef = FIRDatabase.database().reference()
to
let databaseRef = FIRDatabaseReference!
And before using it just initialise it as:-
databaseRef = FIRDatabase.database().reference()
Try :-
#IBAction func doneSave(sender: UIButton) {
let textView = bioTextView.text
self.dismissViewControllerAnimated(false, completion: nil)
databaseRef = FIRDatabase.database().reference()
databaseRef.child("users/\(FIRAuth.auth!.currentUser!.uid)/userBio").setValue(textView)
}