Different definition for sender - swift

So I used sender a lot in swift but it confuses what exactly it does.
#IBAction func btnPressed(_sender: AnyObject){
performSegue(withIdentifier: "newScreen", sender: code)
}
Someone explain the difference between the two senders pls. It kind of confuses me because it has the same name but different functions.

The parameter of an IBAction tells you who caused the action. In your case, when you push the button that triggered this IBAction to be invoked, sender will be set to that button.
The word sender is nothing more than a name. It's a typical convention.
In your case, it's better to use a more strongly typed argument, with a more descriptive name, such as:
#IBAction func btnPressed(_ button: NSButton) { // or UIButton for iOS
performSegue(withIdentifier: "newScreen", sender: code)
}

Related

Passthrough _ sender UIViewController action method

How can I pass through the sender of an action outlet like this:
#IBAction func doPlay(_ sender: Any) {
someMethod(???)
}
What means the underscore?
just write
someMethod(sender)
The underscore just means that the argument "sender" doesn't need a label.

How do I close the first window when the next one opens?

Xcode 9.2, macOS 10.12.6, Swift 4. I don't really know what I'm doing, so please explain what to do in detail.
I am trying to make it so that the first window is closed when the second one is opened. The buttonCONTINUE makes the second window open, via show segue.
I followed the Control+Click and drag as explained here, and tried to make the CONTINUE button close the first window when closed in two different ways; with self.view.window?.close() and with setting the key equivalent to CMD+W.
I've tried the solution suggested here, but that did not solve my problem.
Edit:
I have two windows, one each goes to the other one. Here is the code:
override func prepare(for segue: NSStoryboardSegue, sender: Any?) {
super.prepare(for: segue, sender: sender)
if segue.identifier!.rawValue == "SegueToWIR" {
view.window?.close()
}
//neither if or else if make this work
if segue.identifier!.rawValue == "SegueToWarning" {
view.window?.close()
}
}
The second if statement doesn't cause an error, but doesn't do anything.
Unlike UIKit's UIControl, AppKit only permits a single target-action per NSControl instance. You are attempting to use two:
The show segue.
The action method connection you created using the control + click & drag method.
The segue takes precedence. You can verify this by setting a breakpoint at CONTINUE(_:). You'll find that the action method never gets called!
So scrap the action method &, alternatively, use:
📌 Note: The below implementation is valid for Swift 4.2+.
override func prepare(for segue: NSStoryboardSegue, sender: Any?) {
super.prepare(for: segue, sender: sender)
// Note: For Swift 4, replace `segue.identifier` with `segue.identifier?.rawValue`.
if segue.identifier == "my-segue-identifier" {
view.window?.close()
}
}

Perform UnwindSegue correctly

I am trying to create an Unwind segue that brings from the DetailViewcontroller to the SecondViewcontroller.
I have created an IBAction like this one that can be intercepted by Segues :
#IBAction func segueToSecondVC(sender: UIStoryboardSegue) {
print("segue intercepted by IBAction segueToSecondVC")
}
An placed it in the receiver ViewController (secondViewController).
Then I moved to the Detailviewcontroller and clicked to the third figure on the top of the viewcontroller (exit),clicked to the segueToSecondVC IBAction that appeared in the list of events and dragged it into the button "TURN BACK"(placed in the Detailviewcontroller) in order to associate the button to the event.
In this way the button should be connected with the event and should turn back to the secondVC with an automatic Hidden Segue.
But it doesn't work, the simulator crash and I am redirected to xCode editor with an error in the Appdelegate that says "Thread 1: signal SIGABRT"
I don't know why it doesn't work, anyone could help me?
you can use Unwind like this:
#IBAction func prepareForUnwind(segue: UIStoryboardSegue){}
#IBAction func closePressed(_ sender: Any) {
performSegue(withIdentifier: "unwindToAnotherVC", sender: nil)
}
good rule, is to add all your segues names to constants file:
Create swift file
import Foundation
// Segues
let TO_LOGIN = "toLogin"
let TO_CREATE_ACCOUNT = "toCreateAccount"
let UNWIND = "unwindToChannel"
and then use UNWIND in
#IBAction func closePressed(_ sender: Any) {
performSegue(withIdentifier: UNWIND, sender: nil)
}

Triggering function with parameters upon UIButton press

I'm trying to call a function with parameters on a button press, from what I understand #selector just checks that a function is there and then runs it. I've seen other answers where the button can be sent to the function but sadly I don't think that will solve my problem.
If I run this code (func is any function and a: 14 is just an example of a parameter being given):
myButton.addTarget(self, action: #selector(func(a: 14)), for: .touchUpInside)
I get an error saying 'Argument of #selector does not refer to an #objc method, property, or initializer
A workaround that I've been using:
myButton.addTarget(target: self, action: #selector(myFunc), for: .touchUpInside)
func myFunc() {
someOtherFunc(args)
}
The problem with this is that unless the argument that was going to be passed is global or class wide and known, you wont be able to use it.
Main Question:
Is there a way to have it run a function with parameters when a button is clicked without setting a class wide variable and assessing that instead of using a parameter?
My Solution:
Simplified, and buttons aren't setup and such...
var personName:String!
func scrollViewClicked(name:String) {
personName = name
myButton.addTarget(target: self, action: #selector(myFunc), for: .touchUpInside)
}
func myFunc() {
do something with personName
}
So pretty much I have a way of 'solving' the problem but it feels like a bit of a hack/improper way. Just trying to figure out if there is a 'real' way to do this or if it isn't meant to happen.
No, there's no way to have a UIButton run a function with arbitrary parameters.
But there is a way to have it run with some parameters, which may be useful to you.
The documentation for addTarget says that it takes a selector, which is essentially just a reference to a method. If you pass it a method with the right set of arguments, it will call it and pass whatever it's designed to pass. If you send a method with other arguments, you'll get an "unrecognized selector" error.
UIControl's addTarget understands three kinds of selectors:
func myFunc()
func myFunc(sender: UIButton)
func myFunc(sender: UIButton, forEvent event: UIEvent)
So you can set it to run a function with parameters, but the only parameters it knows how to send are the button that was pressed and the event it generated.
This is still potentially useful though, if you can use information about the button and/or the event to determine your action. For example you can set up your handler:
func myFunc(sender: UIButton, forEvent event: UIEvent) {
switch(sender) {
case myButton:
print("myButton was pressed")
default:
print("Something else was pressed.")
}
}
Depending on your use case, you could make use of the button's storyboard restoration ID, its title or other identifier, or you could even subclass UIButton and give it an instance variable to hold your parameter, like this:
class MyButtonClass: UIButton {
var argument:String = ""
}
Then when you're setting up your button you specify the argument:
myButton.argument = "Some argument"
And you can access it from your handler like this:
func myFunc(sender: UIButton, forEvent event: UIEvent) {
if let button = sender as? MyButtonClass {
print(button.argument)
}
}
It's still not as neat as just specifying your parameter in the selector, but as far as I know that's not possible.

Give Values to Buttons - Swift

I was wondering if someone can help me with this. Right now when I click on the button 0 it will automatically take me to the 2nd screen for testing purposes. Now I want to give value to the numbers accordingly and when the number clicked is equals to the number on my label than it will show the 2nd screen. If not, the Question mark label will blink or change color. Thanks
Place this variable above viewDidLoad():
var chosenNumber: Int?
Attach your buttons to an IBAction like this one and in the storyboard make each of their tags equal to their face value.
#IBAction func aNumberButtonWasPressed(_ sender: UIButton) {
chosenNumber = sender.tag
performSegue(withIdentifier: "theSegueIdentifier", sender: nil)
}
Pass the number to the following view controller like so and then use that number to populate the label accordingly.
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
super.prepare(for: segue, sender: sender)
if let vc = segue.destination as? TheViewControllerYouAreGoingTo {
vc.theVariableYouWantToSaveYourNumberTo
}
}
If you want to know how to do something differently, just ask.
If you want to really learn swift well, I highly recommend taking this Paul Hegarty Course for FREE. Paul Hegarty Course
The first two lessons specifically will teach you everything you could want to know about proper swift syntax and building a calculator early on. It might seem slightly advanced, but that is why I have watched the course 3 times now. Every 3-6 months since I started learning Swift this has helped refine my skills.
EDIT
let thisString = label.text
let thisInt = Int(thisString)
thisInt will be an optional, so at some point you will need to unwrap it. You can use it however you want to and set it to another label like so:
anotherLabel.text = "\(thisInt)"