Swift getting Nil when attempting to get value - swift

Im not sure why i am getting this nil error on optional when attempting to print. Can somebody provide any input? It doesn't make sense that I am able to output the value from the aplicationContext, however when I attempt to get value from applicationContext["hearRate"] i get nil.
func session(_ session: WCSession, didReceiveApplicationContext applicationContext: [String : Any]) {
print("didReceiveApplicationContext\n\t\(applicationContext)")
let hrValue = applicationContext["heartRate"] as? String
print(applicationContext["hearRate"])
print(hrValue)
//heartRate.text = hrValue
}
console - output
2021-03-10 18:41:04.623716-0700 Trainer+[1824:759737] Metal API Validation Enabled
session active state
didReceiveApplicationContext
["heartRate": 00BPM]
nil
Optional("00BPM")
Fatal error: Unexpectedly found nil while implicitly unwrapping an Optional value: file Trainer_/ViewController.swift, line 57
2021-03-10 18:41:04.999001-0700 Trainer+[1824:759754] Fatal error: Unexpectedly found nil while implicitly unwrapping an Optional value: file Trainer_/ViewController.swift, line 57
Update - Ignore typo, found issue with IBOutlet
func session(_ session: WCSession, didReceiveApplicationContext applicationContext: [String : Any]) {
print("didReceiveApplicationContext\n\t\(applicationContext)")
let hrValue = applicationContext["heartRate"] as? String
print(applicationContext["heartRate"])
print(hrValue)
//heartRate.text = hrValue
heartRate.text = "test"
}
2021-03-11 12:45:05.482464-0700 Trainer+[1873:817768] Metal API Validation Enabled
session active state
didReceiveApplicationContext
["heartRate": 91BPM]
Optional(91BPM)
Optional("91BPM")
Fatal error: Unexpectedly found nil while implicitly unwrapping an Optional value: file Trainer_/ViewController.swift, line 58
2021-03-11 12:45:05.887523-0700 Trainer+[1873:817966] Fatal error: Unexpectedly found nil while implicitly unwrapping an Optional value: file Trainer_/ViewController.swift, line 58
the func session(didReceiveApplicationContext), from watchconnectivity is working as intended. I believe that my problem comes from me moving the heartRate label to a 'view container'. I added the watchconnectivity at the same time that I moved the label and assumed that it would work.
This may require a different question, not sure, how can i pass data along multiple view controllers that are visible at the same time. Since I am creating the session on the ViewController, I don't yet know how to pass the data to other view controllers without passing a full 'self' reference of the ViewController, to the DetailViewController. Coming from Java and PHP, i feel like this is not good coding practice.
I am thinking about extensions/delegates, and prototypes. I understand them to a slight degree, but I am currently working on an app and my main goal is to have a working prototype. I'll come back and refactor the code fix and fix any gaping vulnerabilities. If any body with experience can provide me with any reliable resources. Tired of hitting the next page of google as i cant find the answers that I am looking for lol.
Update #3
class ViewController: UIViewController, WCSessionDelegate {
#IBOutlet weak var cont: DetailViewController!
override func viewDidLoad() {
super.viewDidLoad()
if WCSession.isSupported() {
connectivitySession = WCSession.default
connectivitySession?.delegate = self
connectivitySession?.activate()
}
}
func session(_ session: WCSession, didReceiveApplicationContext applicationContext: [String : Any]) {
print("didReceiveApplicationContext\n\t\(applicationContext)")
let hrValue = applicationContext["heartRate"] as? String
print(applicationContext["heartRate"])
print("container\n\t\(cont.heart.text)")
cont.heart.text = "test"
}
******
}
// class assigned to 'view container' in ViewController in SB
class DetailViewController: UIView {
#IBOutlet weak var heart: UILabel!
// #IBOutlet weak var hearRate: UILabel!
#IBOutlet weak var sessionTimer: UILabel!
#IBOutlet weak var currentActivity: UILabel!
#IBOutlet weak var startButton: UIButton!
#IBOutlet weak var activityTimer: UILabel!
}
Output
2021-03-11 15:22:15.294727-0700 Trainer+[1938:854826] Metal API Validation Enabled
2021-03-11 15:22:15.628977-0700 Trainer+[1938:854826] *** Terminating app due to uncaught exception 'NSUnknownKeyException', reason: '[<Trainer_.ViewController 0x102e04ec0> setValue:forUndefinedKey:]: this class is not key value coding-compliant for the key menuContainer.'
*** First throw call stack:
(0x1986ad9d8 0x1aca33b54 0x1985be6e4 0x19986aca8 0x19a84f6a4 0x19ab5f254 0x198598298 0x19ab5b218 0x19a856d88 0x19a857114 0x19a8577e8 0x19af56448 0x19af55c5c 0x19af56af0 0x19af67730 0x19b17aba0 0x19a434be4 0x19af19ca0 0x19af1a044 0x19aa59ab8 0x1a79d7704 0x1a79ff130 0x1a79e4e60 0x1a79fee44 0x101291528 0x1012949f0 0x1a7a23e60 0x1a7a23b28 0x1a7a23ffc 0x19862dbf0 0x19862daf0 0x19862ce9c 0x1986273e0 0x198626ba0 0x1af38f598 0x19af182f4 0x19af1d874 0x1abda7b54 0x100f75a08 0x100f75980 0x100f75a4c 0x198305568)
libc++abi.dylib: terminating with uncaught exception of type NSException
*** Terminating app due to uncaught exception 'NSUnknownKeyException', reason: '[<Trainer_.ViewController 0x102e04ec0> setValue:forUndefinedKey:]: this class is not key value coding-compliant for the key menuContainer.'
terminating with uncaught exception of type NSException
(lldb)

answered my own question, by chaning from uiviewcontroller to name of custom class.
This is for a basic watch connection session for iphone that uses multiple view controllers on same screen.
Delegates, extensions, etc, is not required. Will need to setup your segue, secondary controller, and connections.
class ViewController: UIViewController, WCSessionDelegate {
var variable: Any? // Your variable type
var sessionVariable: WCSession?
var secondVC: SecondViewController!
override func viewDidLoad() {
super.viewDidLoad()
// start session
if WCSession.isSupported() {
sessionVariable = WCSession.default
sessionVariable?.delegate = self
sessionVariable?.activate()
}
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
// using segue.identifier, save live ViewController to your variable
if segue.identifier == "Storyboard Segue Identifier" {
if let destinationVC = segue.destination as? SecondViewController {
secondVC = destinationVC
}
}
}
func session(_ session: WCSession, activationDidCompleteWith activationState: WCSessionActivationState, error: Error?) {
print("session active state")
}
//using dispatchqueue, to update label on main thread, use self.secondVC.variable to update.
func session(_ session: WCSession, didReceiveApplicationContext applicationContext: [String : Any]) {
let contextValue = applicationContext["context"] as? String
DispatchQueue.main.async {
self.secondVC.variable.text = contextValue
}
}
}
class HealthViewController: UIViewController {
#IBOutlet weak var varialble: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
}
}

Related

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)
}

How to retrieve the value of switch and pass into Object?

I am trying to get the value of a switch and pass it to an object in a view controller.
Below is the code of my view controller. I have created a label, switch outlet, and switch action.
#IBOutlet weak var firstTimeConducting: UILabel!
#IBOutlet weak var firstTime_Conduct: UISwitch!
#IBAction func firstTimeConductSwitchTap(_ sender: Any) {
firstTimeConductTapped()
}
override func viewDidLoad() {
super.viewDidLoad()
firstTimeConductTapped()
}
func firstTimeConductTapped() {
if firstTime_Conduct.isOn {
value = "Yes"
} else {
value = "No"
}
}
I have debugged it and it enters and gets the value as "yes" when I click on the switch from off to on state in simulator.
Then after returning to function firstTimeConductSwitchTap(), it crashes saying the following error
"Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[app.RequestFormViewController first_TimeConduct:]: unrecognized selector sent to instance 0x7fb900421fc0'
I am just retrieving the value of "value" variable and passing it to object to display.
Can you suggest whether I am following the correct procedure and why I get this error?
The error is pretty clear:
In Interface Builder there is a dead connection to a selector first_TimeConduct. Most likely you renamed the action method.
Search for first_TimeConduct with ⇧⌘F and delete the connection.

Read value from BLE device on 2 UIViewControllers

Currently my MainViewController can connect to my Bluetooth module and read the data coming from it.
Now, I'm trying to read the data from another View Controller.
My Bluetooth Manager is a singleton so that it doesn't get instantiated multiple times. To read and process the data in the appropriate ViewController, I was thinking of using optional delegates. It's working fine when I get to receivedMVC(data: String) but crashes when getting to receivedUVC(data: String)
I get the following error:
[BLE_Tests.MainViewController receivedUVCWithData:]: unrecognized
selector sent to instance 0x100d0a9d0 2017-06-22 16:25:58.634682-0700
BLE_Tests[9544:2692419] * Terminating app due to uncaught exception
'NSInvalidArgumentException', reason: '-[BLE_Tests.MainViewController
**receivedUVCWithData:]: unrecognized selector sent to instance
0x100d0a9d0'
If I add the receivedUVC(data: String) to my MainViewController, it doesn't crash but doesn't call the receivedUVC from the correct ViewController.
How do I point to the correct selector?
Thank you.
MainViewController.swift
class MainViewController: UIViewController, UITableViewDataSource, UITableViewDelegate, BluetoothDelegate {
#IBOutlet weak var peripheralListTableView: UITableView!
#IBOutlet weak var updateButton: UIButton!
let bluetoothManager = BluetoothManager.getInstance()
override func viewDidLoad() {
super.viewDidLoad()
peripheralListTableView.delegate = self
peripheralListTableView.dataSource = self
bluetoothManager.delegate = self
bluetoothManager.discover()
}
func reloadPeripheralList() {
peripheralListTableView.reloadData()
}
func receivedMVC(data: String) {
print("Hello? \(data)")
}
//MARK: - UITableViewDataSource
}
UpdateViewController.swift
class UpdateViewController: UIViewController, BluetoothDelegate {
let bluetoothManager = BluetoothManager.getInstance()
func receivedUVC(data: String) {
print("Allo: \(data)")
}
}
BluetoothManager.swift
func peripheral(_ peripheral: CBPeripheral, didUpdateValueFor characteristic: CBCharacteristic, error: Error?) {
let stringValue = String(data: characteristic.value!, encoding: String.Encoding.utf8)!
print("Received packet: \(stringValue)")
delegate?.receivedMVC!(data: stringValue) // Delegate method in MainViewController
delegate?.receivedUVC!(data: stringValue) // Delegate method in UpdateViewController
}
[BLE_Tests.MainViewController **receivedUVCWithData:]
This tells you that the MainViewController method receivedUVCWithData: was called, but that class do not implement it. And thats the reason why it's called:
delegate?.receivedUVC!(data: stringValue)
This call will check if the delegate exists and if so it send a message to receivedUVC that must(!) exist. So it will not crash if you call this:
delegate?.receivedUVC?(data: stringValue)
But then I ask myself why you define two different methods in your protocol? Define one mandatory (not optional) method in your protocol, implement it in both UIViewControllers and call this method in BluetoothManager.swift. Then the last set delegate get the data. If both ViewControllers exists at the same time your BluetoothManager needs a delegate1 and a delegate2 and a call to the method on both delegates.

Swift: How can I catch a modification of a switch from dynamic cell

I need to catch the modification of a switch in a dynamic cell.
The app has dynamic cells to list all BLE devices which where found.
The BLE device should be able to turn on/off via switch.
Now is the problem, I can't catch the switch via Outlet or Action.
How is it possible to catch a change from a dynamic cell.
UI for the problem looks like that:
UI with dynamic cell
I found the point where I can catch the tap but there I can't use my methods because in a class type UITableViewCell CoreBluetooth is not supported and I can't fill out the attribute for the CoreBluetooth methods.
import UIKit
class remoteCellTableViewCell: UITableViewCell{
//MARK: Properties
#IBOutlet weak var remoteCellLabel: UILabel!
#IBOutlet weak var remoteCellImageView: UIImageView!
#IBOutlet weak var remoteCellSwitch: UISwitch!
#IBOutlet weak var remoteCellPower: UIProgressView!
override func awakeFromNib() {
super.awakeFromNib()
}
//HERE I CAN CATCH THE SWITCH TAP BUT I CAN'T USE CoreBluetooh IN THIS CLASS
#IBAction func onOff(sender: AnyObject) {
//OBJECT FROM THE CLASS FOR CONNECT AND SEND TO THE PERIPHERAL
var connection: ViewController = ViewController()
connection.viewDidLoad()
//CANT FILLOUT THE ATTRIBUTES BECAUSE OF MISSING COREBLUETOOTH SUPPORT
//-->
connection.centralManagerDidUpdateState(<#T##central: CBCentralManager##CBCentralManager#>)
connection.centralManager(<#T##central: CBCentralManager##CBCentralManager#>, didDiscoverPeripheral: <#T##CBPeripheral#>, advertisementData: <#T##[String : AnyObject]#>, RSSI: <#T##NSNumber#>)
connection.centralManager(<#T##central: CBCentralManager##CBCentralManager#>, didConnectPeripheral: <#T##CBPeripheral#>)
connection.centralManager(<#T##central: CBCentralManager##CBCentralManager#>, didDiscoverPeripheral: <#T##CBPeripheral#>, advertisementData: <#T##[String : AnyObject]#>, RSSI: <#T##NSNumber#>)
connection.centralManager(<#T##central: CBCentralManager##CBCentralManager#>, didConnectPeripheral: <#T##CBPeripheral#>)
connection.peripheral(<#T##peripheral: CBPeripheral##CBPeripheral#>, didDiscoverServices: <#T##NSError?#>)
connection.peripheral(<#T##peripheral: CBPeripheral##CBPeripheral#>, didDiscoverCharacteristicsForService: <#T##CBService#>, error: <#T##NSError?#>)
connection.peripheral(<#T##peripheral: CBPeripheral##CBPeripheral#>, didUpdateValueForCharacteristic: <#T##CBCharacteristic#>, error: <#T##NSError?#>)
connection.peripheral(<#T##peripheral: CBPeripheral##CBPeripheral#>, didWriteValueForDescriptor: <#T##CBDescriptor#>, error: <#T##NSError?#>)
//->
}
override func setSelected(selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
}
Use Tags to get the switch state. here is the code that i used to get the button click action. Like this
In your cellForRowAtIndexPath assign tag to the button.
cell.absentButton.tag = indexPath.row
In your button action get the row of the button
if let button = sender as? UIButton {
if button.selected {
// set selected
let row = sender.tag
}
}
From this you can get which switch is changed.

terminating with uncaught exception of type NSException in Swift

I am pretty new to swift and was just playing around with the following tutorial to learn Core Data Basics.
CoreData Tutorial
I've tried to narrow down where the exception is being thrown using breaks. I believe it is when I am trying to pass data through a view controller.
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "Update" {
// var selectedItem: NSManagedObject = myList[self.tableView.indexp] as NSManagedObject
let IVC: CreateRiderViewController = (segue.destinationViewController as? CreateRiderViewController)!
var indexPath: NSIndexPath = self.tableView.indexPathForSelectedRow()!
var selectedItem: NSManagedObject = myList[indexPath.row] as! NSManagedObject
IVC.firstName = (selectedItem.valueForKey("firstName") as?String)!
IVC.lastName = (selectedItem.valueForKey("lastName") as! String?)!
IVC.phoneNumber = (selectedItem.valueForKey("phoneNumber") as! String?)!
IVC.eMail = (selectedItem.valueForKey("eMail") as! String?)!
IVC.exitingItem = selectedItem
}
}
The view controller I'm attempting to pass this data too looks like this.
class CreateRiderViewController: UIViewController {
#IBOutlet weak var firstNameField: UITextField!
#IBOutlet weak var lastNameField: UITextField!
#IBOutlet weak var phoneNumberField: UITextField!
#IBOutlet weak var eMailField: UITextField!
var exitingItem: NSManagedObject!
var firstName: String = ""
var lastName: String = " "
var phoneNumber: String = " "
var eMail: String = " "
override func viewDidLoad() {
super.viewDidLoad()
if (exitingItem != nil) {
firstNameField.text = firstName
lastNameField.text = lastName
phoneNumberField.text = phoneNumber
eMailField.text = eMail
}
// Do any additional setup after loading the view.
}
It should set the text fields text to the row selected from my first view controller. However when i select a row the program seems to crash at the point it is transitioning view controllers.
The error I am getting is
2015-06-09 15:53:51.193 ARRR[37189:4601772] -[UITextInputTraits length]: unrecognized selector sent to instance 0x7fc129f60800
2015-06-09 15:53:51.198 ARRR[37189:4601772] *** Terminating app due to uncaught exception 'NSInvalidArgumentException',
reason: '-[UITextInputTraits length]: unrecognized selector sent to instance 0x7fc129f60800'
I believe I am unwrapping something at the wrong time but can not figure it out.
I'm also trying to become better at sharing information to get help trouble shooting and would appreciate feedback on how I can explain my problems more clearly and know if I'm including the right pieces of code / error messages to find the problem.
Check that your UITextField is connected to your ViewController.
ctrl-click on all UITextFields in the storyboard and check for broken links (you might have created an outlet in the code but changed its name). Also check that all outlets in the ViewController are connected (a circle appears to the left of the initialisation line, if it's filled it's connected, if it's an empty circle there's a broken link)
Screenshot