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

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.

Related

#IBAction fails to work in Swift, though I can connect it in Interface Builder, and it works in Objective-C

In all cases, I can wire user-interface buttons to actions with Interface Builder. But the buttons work for Objective-C but not for Swift.
Objective-C example (it works):
- (IBAction)TogglePlaying:(id)sender {
(details snipped for brevity)
}
Swift example (it doesn't work, though it's wired to its button):
#IBAction func Go(_ sender: Any) {
print("Going")
OutputText!.stringValue = InputText!.stringValue
}
I have no idea of what the difference might be, because everything I've found on using IBAction in Swift indicates that I've written it correctly. Also, in Interface Builder, I've set File's Owner's Custom Class correctly.
Update:
Using
ios - Find what Action is called by a Button in interface builder in debug mode - Stack Overflow
Find what Action is called by a Button in interface builder in debug mode
I used "Debug View Hierarchy", right-clicked on "NSButton - Go!" in the widget-hierarchy view, and selected "Print Description of NSButton - Go!"
I got
Printing description of $13:
<NSButton: 0x7fac1b116250>
I then did:
po [0x7fac1b116250 allTargets]
error: Execution was interrupted, reason: Attempted to dereference an invalid ObjC Object or send it an unrecognized selector.
The process has been returned to the state before expression evaluation.
Update:
I tried
po [0x7faf38011790 target]
(new address of that button) and I got
nil
Update:
The complete code of TLWindow, in Swift:
import Cocoa
class TLWindow: NSWindowController {
#IBOutlet weak var InputText: NSTextField!
#IBOutlet weak var OutputText: NSTextField!
override var windowNibName: NSNib.Name? {
return NSNib.Name("TLWindow")
}
#IBAction func Go(_ sender: Any?) {
print("Going")
OutputText!.stringValue = InputText!.stringValue
}
}
I don't know how to show that the xib is wired up correctly without doing a lot of screenshots. But it is, with the "Go!" button connected to "Go:" in "File's Owner". Also, "File's Owner" is set to "TLWindow", this class.
You are creating an instance of TLWindow in newDocument(), but then you're letting it go out-of-scope...
Try this:
#NSApplicationMain
class AppDelegate: NSObject, NSApplicationDelegate {
// add a property to "hang onto" the instance
var myTLWindow: TLWindow!
func applicationDidFinishLaunching(_ aNotification: Notification) {
// Insert code here to initialize your application
newDocument(self)
}
// Create an app window
#IBAction func newDocument(_ sender: Any?) {
let wc = TLWindow()
// add this line
myTLWindow = wc
wc.showWindow(self)
}
}

Swift getting Nil when attempting to get value

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

How to create UIButton action in custom class in Swift

I want to create a class to add UIButton action, and then viewcontroller can call this class to create action.
But the error message told me "unrecognized selector sent to instance "
How can I fix them?
class MYController: UIViewController{
#IBOutlet weak var pptMode: UIButton!
#IBOutlet weak var videoMode: UIButton!
#IBOutlet weak var meetingMode: UIButton!
#IBOutlet weak var videoMeeting: UIButton!
override func viewDidLoad() {
super.viewDidLoad()
ModeChange().modeChangeUtil(self,pptMode:pptMode, videoMode: videoMode, meetingMode: meetingMode, videoMeeting: videoMeeting)
}
}
class ModeChange {
func modeChangeUtil(vc:UIViewController,pptMode:UIButton,videoMode:UIButton,meetingMode:UIButton,videoMeeting:UIButton){
pptMode.addTarget(vc, action: "modeTouched:", forControlEvents:UIControlEvents.TouchUpInside)
pptMode.tag = modeButtonTag.ppt.rawValue
videoMode.addTarget(vc, action: "modeTouched:", forControlEvents:UIControlEvents.TouchUpInside)
videoMode.tag = modeButtonTag.video.rawValue
meetingMode.addTarget(vc, action: "modeTouched:", forControlEvents:UIControlEvents.TouchUpInside)
meetingMode.tag = modeButtonTag.meeting.rawValue
videoMeeting.addTarget(vc, action:"modeTouched:", forControlEvents:UIControlEvents.TouchUpInside)
videoMeeting.tag = modeButtonTag.videoMeeting.rawValue
}
enum modeButtonTag: Int {
case ppt
case video
case meeting
case videoMeeting
}
func modeTouched(sender:UIButton){
let modeCmd:ModeCommand = ModeCommand(device: Mode(onoffUrl: OfficeConstants.MeetingRoom3A.MODE))
switch sender.tag {
case modeButtonTag.ppt.rawValue:
modeCmd.modeStatus = .PPT
case modeButtonTag.video.rawValue:
modeCmd.modeStatus = .Video
case modeButtonTag.meeting.rawValue:
modeCmd.modeStatus = .Meeting
case modeButtonTag.videoMeeting.rawValue:
modeCmd.modeStatus = .VideoMeeting
default: break
//do nothing
}
modeCmd.execute()
}
}
You passed an incorrect parameter!
The addTarget method takes 3 parameters:
target is the instance to which the selector will be sent.
action is a selector
forControlEvents is the event that you want to handle
After explaining these, can you figure out which parameter is wrong in your code?
It's the target!
Since the selector will be sent to the target, the target must have a method called modeTouched:.
In your method call, you passed in vc as the target. This means that the selector modeTouched: must be sent to vc. However, you did not define a modeTouched: method in vc! That's why the error occurred.
I guess you want to send the selector to the modeTouched: method in the ModeChange class. Thus, the target should be self:
pptMode.addTarget(self, action: #selector(modeTouched:), forControlEvents:UIControlEvents.TouchUpInside)
That should fix it!

Swift Promises - Reload Data method is not binding the data

I'm using promises to retrieve information some methods via JSON. I'm filling the information with the function:
I'm trying to set those records in my TableView with:
#IBOutlet weak var usersTableView: UITableView!
var dataSource: [UserResponse]? {
didSet {
self.usersTableView.reloadData()
}
}
override func viewDidLoad() {
super.viewDidLoad()
loadFriends()
// Do any additional setup after loading the view.
}
func loadFriends() {
//UserService.getFriends()
let (request, promise) = UserService.getFriends()
promise.then { user in
self.dataSource = user
}.catch{
error in
SCLAlertView().showError("Error", subTitle: error.localizedDescription)
}
}
But is returning the error:
fatal error: unexpectedly found nil while unwrapping an Optional value
How I can fix this error?
Your usersTableView is an implicitly unwrapped optional (UITableView!). When you call the dataSource setter, the didSet property observer tries to call reloadData() on usersTableView, but it is nil, so you get a crash - you cannot call methods on nil.
It looks like you haven't connected the outlet to your usersTableView property in your storyboard. Alternatively, you're setting it to nil somewhere else in your code. This could be happening automatically if usersTableView isn't part of your view hierarchy when the view controller is loaded, since it is a weak variable, but I expect you have added it as a subview in the storyboard?

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