How to run a button action in motionEnded? - ibaction

In a very basic shaking dice app in Swift 4, I have two functions. The first runs the random dice function. The second however needs a sender argument as it's really an IBAction so it needs to know which button is being pressed.
How do I add a fake button hit to motionEnded during the shake?
// MARK: -- Outlets and Actions
#IBOutlet weak var diceImageView1: UIImageView!
#IBOutlet weak var diceImageView2: UIImageView!
#IBAction func rollButtonPressed(_ sender: UIButton) {
updateDiceImages()
updateRollButton(sender)
}
...
override func motionEnded(_ motion: UIEventSubtype, with event: UIEvent?) {
updateDiceImages()
// how to send sender from motionEnded?
rollButtonPressed( magic sender needed )
// or another function that also needs the UIButton sender
updateRollButton( same magic sender needed )
}
}

IBActions don't have to have a sender argument, you can remove it.
#IBAction func rollButtonPressed()
Note that after modifying the function, you should rewire the action inside Interface Builder to prevent crashing.

Related

NSButton state issues

I have two ViewControllers.
On VC1 I have search criteria and on VC2 I have the search results. If you want to go from VC2 to VC1 the VC2 is dismissed.
On VC1 I have an NSButton(style Check, type Switch) which by default I want it to be in ON state. The purpose of the NSButton is to include photos in the results.
If the user unchecks the button and presses search, it will go on to VC2 showing the search results without photos.
BUT when the user goes back to VC1 for a new search that's where the unwanted behaviour occurs:
The NSButton is unchecked(i want it to be checked by default, every time the user is at the VC1. Also, the button is nil.
Why is this happening, and how can i make it the button box to be ticked everytime the VC2 is dismissed?
I tried enabling it and setting it to ONState but as its nil it would crash.
To set a state every time your controller opens use the method
-(void)viewWillAppear
To let viewControllers communicate with each other you can implement delegates. Here is a pretty good tutorial: Link
Another approach is to communicate with Notifications -> Link
Or you can set values on methods like prepareForSegue - depending on what you use to imstantinate your controllers.
I have managed to make it perform the way I want it by adding
switch.state=1
just before the segue from VC1 to VC2 is performed.
However, I don't think this is the most elegant solution as the button is still nil.
UPDATE:
I have figured out that the issue occurs as when it goes from VC1 to VC2 the VC1 becomes nil, when the VC2 is dismissed it becomes nil as well. Hence the crash. One solution is to use delegates.
VC1:
class FirstViewController: UIViewController,SecondViewControllerProtocol {
#IBOutlet var firstName: UITextField!
#IBOutlet var lastName: UITextField!
#IBOutlet var subscribeSwitch: UISwitch!
#IBAction func goToSecondVC(_ sender: Any) {
let viewController = self.storyboard?.instantiateViewController(withIdentifier: String(describing: SecondViewController.self)) as! SecondViewController
viewController.delegate = self
self.present(viewController, animated: true, completion: nil)
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func dismissViewController() {
if let viewController = self.storyboard?.instantiateViewController(withIdentifier: "SecondViewController"){
subscribeSwitch.isOn=true
}
}
}
VC2:
protocol SecondViewControllerProtocol {
func dismissViewController()
}
class SecondViewController: UIViewController {
var delegate:SecondViewControllerProtocol!
#IBAction func goBackToFirstVC(_ sender: Any) {
self.dismiss(animated: true) {
self.delegate!.dismissViewController()
}
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}

Assistant Editor shows different "ViewController.swift" file than the one that Main Editor shows?

The source code shown in the Assistant Editor for "ViewController.swift" is different than source code shown in Main Editor for "ViewController.swift".
"ViewController.swift" in Main Editor:
// ViewController.swift
// FoodTracker
import UIKit
class ViewController: UIViewController, UITextFieldDelegate {
// MARK: Properties
#IBOutlet weak var nameTextField: UITextField!
#IBOutlet weak var mealNameLabel: UILabel!
#IBOutlet weak var mainButton: UIButton!
override func viewDidLoad() {
super.viewDidLoad()
nameTextField.delegate = self
}
// MARK: UITextFieldDelegate
func textFieldShouldReturn(textField: UITextField) -> Bool {
textField.resignFirstResponder()
return true
}
func textFieldDidEndEditing(textField: UITextField) {
mealNameLabel.text = textField.text
}
// MARK: Actions
#IBAction func setDefaultLabelText(sender: UIButton) {
mealNameLabel.text = "DEFAULT text"
// mainButton.tintColor = UIColor.darkTextColor()
}
}
"ViewController.swift" in Assistant Editor:
//
// ViewController.swift
// FoodTracker
import UIKit
internal class ViewController : UIViewController, UITextFieldDelegate {
#IBOutlet weak internal var nameTextField: UITextField!
#IBOutlet weak internal var mealNameLabel: UILabel!
#IBOutlet weak var mainButton: UIButton!
override internal func viewDidLoad()
internal func textFieldShouldReturn(textField: UITextField) -> <<error type>>
internal func textFieldDidEndEditing(textField: UITextField) -> <<error type>>
#IBAction internal func setDefaultLabelText(sender: UIButton) -> <<error type>>
}
So, those are completely different different files, but have the same name. The one in the Assistant Editor is the interface while the file shown in the Main Editor is the implementation of the interface, right?
That seems a little weird, but the interface and implementing class have the same name? When I'm working in Xcode I need to be aware that sometimes two files can (often?) have the same name?
I had the same problem. I couldn't figure out why it was showing this "internal class" file.
I managed to get it to display the correct associated file. To do this, click the associated editor icon, the two circles. Then in the window that appears, click the '+'. The new window that appears should have the right code in it. Then close the old window and you should be left with the right one. The rest of the project appears to work be fixed now.
I found this in Xcode 9.2, Swift 4, but it may be in other versions.
In Xcode, with the option key down, hover your mouse over 'func' or another scope-describing keyword to reveal the scope with the blue bracket.
Then do a two finger tap on the trackpad to automatically open an Assistant Editor at the same point in the code. I'm frequently going somewhere else in my code but want to have a window open that stays where I just was. This trick does just that.
(Make sure your track pad is set so a 'Secondary click' is a tap with two fingers.)
(Swift 4.2) I just had the same problem. Whenever I was in the assistant editor, my ViewController was labeled internal and I couldn't make any edits to it. The above solutions didn't work for me, but they put me on the right trail. Apparently, I was in some kind of duplicate file and not in the ViewController I needed. Correcting the issue was simply a matter of navigating to the correct file via the controls at the top of the assistant editor.
I have seen what could be a solution at the video youtube.com/watch?v=wPAUKhlmW1M at time-position 1:31 - please correct if I'm wrong

Trigger Segue Artificially

I am trying to pass data between two viewContollers in an OS X storyboard application using Swift. When I press a button on VC1, it opens VC2, and prepareForSegue is run. However, I can't pass data back to VC1 because a. prepareForSegue isn't being run (because a window isn't being opened) and b. because even if it were, VC1 doesn't know data is being sent and I can't figure out a function (something like viewDidBecomeFocus, if such a function existed) to let it know to look. I feel like there must be a way to do this.
If you know of a way to do this in IOS but not OSX, it could still be useful.
Thanks!
Let assume that in your first ViewController you have one label and one button. When pressed, that button open popover (SecondViewController) with one textfield (and one button what says ready or close etc.), where you want take its value and assign it to your label. That is where delegates and protocols come handy.
SecondViewController:
#objc protocol TextDelegate {
func passedString(textValue: String)
}
class SecondViewController: NSViewController {
#IBOutlet weak var textField: NSTextField!
weak var delegate: TextDelegate?
override func viewDidLoad() {
super.viewDidLoad()
// Do view setup here.
}
#IBAction func closePopOver(sender: AnyObject) {
if delegate != nil {
delegate!.passedString(textField.stringValue)
}
self.dismissViewController(self)
}
}
This is ViewController:
#IBOutlet weak var myLabel: NSTextField!
override func prepareForSegue(segue: NSStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "mySegue" {
let vc = segue.destinationController as! SecondViewController
vc.delegate = self
}
}
func passedString(textValue: String) {
myLabel.stringValue = textValue
}

Setting Label text in swift

My first question here. I'm making the jump from Delphi and Pascal to Xcode and Swift and feeling totally overwhelmed by the change.
I'm simply attempting to change the text of a label when a button is clicked. Here is my code from ViewController.swift
import Cocoa
class ViewController: NSViewController {
#IBOutlet weak var Label1: NSTextField!
#IBOutlet weak var ChangeText: NSTextField!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
#IBAction func ButtonPressed(sender: AnyObject) {
Label1.stringValue = "Hello World"
}
override var representedObject: AnyObject? {
didSet {
// Update the view, if already loaded.
}
}
When I run the application as soon as I click the button the application hangs.
I've also tried exchanging stringValue with text but NSTextField does not use this. I can't seem to make the label show up as UITextField.
What am I doing wrong?

Changing image of UIButton via click - XCode 6 Swift

Im simply trying to make it so when I click on a UIButton (for which it currently shows the image of a shell), the image changes into something else (in this case, a coin).
This is what i tried so far and have not had any success. I cant find anything to do this for Swift.Thanks.
import UIKit
class ViewController: UIViewController {
#IBOutlet weak var lblOutput: UILabel!
#IBOutlet weak var lblWin: UILabel!
#IBOutlet weak var lblLost: UILabel!
#IBOutlet weak var lblWinsAmt: UILabel!
#IBOutlet weak var lblLossesAmt: UILabel!
let coin = UIImage(named: "penny_head") as UIImage;
override func viewDidLoad() {
super.viewDidLoad()
//imgShell1.hidden = true //doesnt work
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#IBAction func btnStart(sender: UIButton) {
}
#IBAction func btnShell1(sender: UIButton) {
sender.setImage(coin,forState: UIControlState.Highlighted);
}
The way you're setting up the control is incorrect. Assuming you have a button property named btnShell (and it's the button you want to setup) change your viewDidLoad() method to:
override func viewDidLoad()
{
super.viewDidLoad()
btnShell.setImage(imgShell1, forState:.Normal);
btnShell.setImage(coin, forState:.Highlighted);
}
And then remove the setImage(_:forState:) call from the action method:
#IBAction func btnShell1(sender: UIButton) {
sender.setImage(coin,forState: UIControlState.Highlighted);
}
To permanently change the button image on tap, you have to use the .Normal enum case and not .Highlighted for the control state:
sender.setImage(coin,forState: UIControlState.Normal)
Setting the image for the .Highlighted state makes the new image appear only when the button is in that state, i.e. when it is tapped.
If you are looking to change the UIButton's background image permanently you have to use Antonio's method:
sender.setImage(coin,forState: UIControlState.Normal)
This won't change the UIKit's default highlighting when you tap the button. When you don't want the button to be highlighted when you touch it or have different appearances for different states, then you might be better off using an UIImageView.
In viewDidLoad():
imgView?.image = imgOne
imgView?.userInteractionEnabled = true
imgView?.addGestureRecognizer(UITapGestureRecognizer(target: self, action: "changeImage:"))
The function that changes the image:
func changeImage(recognizer: UITapGestureRecognizer){
self.imgView?.image = imgTwo
}
You can also use isSelected.
button.setImage(image2, for: .normal)
button.setImage(image1, for: .selected)

Resources