I'm learning Swift and I'm making a tic-tac-toe game now. Here is the image of the game and everything works fine so far.image of tic-tac-toe. However, I was wondering if there is a way to refactor the code or not.
I added a plate image to each button (so you can see 3 X 3 buttons), so when a user taps the button, the plate image becomes either an apple image or a pineapple image.
In the code below, I made IBAction for each button (i.e. func plate1Pressed()), but every IBAction execute the same function, which is changePlateImage(plate: sender). So far, I only have 9 buttons in total, so I can just make IBAction 9 times and put changePlateImage(plate: sender) in them, however, I was thinking if I had to make more square games like Reversi, I had to make 8 X 8 IBActions, which is kind of terrifying...
So is there any way to refactor my code? instead of adding IBActions 9 times and put the same function in them?
import UIKit
class GameScreenViewController: UIViewController {
var isPlayer1 = true
override func viewDidLoad() {
super.viewDidLoad()
}
// when player 1 taped a button, change isPlayer1 to flase
func displayHandPointer () {
// some codes here...
}
func chnagePlayerTurn () {
// some codes here...
}
func changePlateImage (plate: UIButton) {
let fruitImage = isPlayer1 ? K.Image.apple : K.Image.pineapple
plate.setImage(UIImage(named: fruitImage), for: .normal)
chnagePlayerTurn()
displayHandPointer()
}
//MARK: - IBA actions for board game
#IBAction func plate1Pressed(_ sender: UIButton) {
changePlateImage(plate: sender)
}
#IBAction func plate2Pressed(_ sender: UIButton) {
changePlateImage(plate: sender)
}
#IBAction func plate3Pressed(_ sender: UIButton) {
changePlateImage(plate: sender)
}
#IBAction func plate4Pressed(_ sender: UIButton) {
changePlateImage(plate: sender)
}
#IBAction func plate5Pressed(_ sender: UIButton) {
changePlateImage(plate: sender)
}
#IBAction func plate6Pressed(_ sender: UIButton) {
changePlateImage(plate: sender)
}
#IBAction func plate7Pressed(_ sender: UIButton) {
changePlateImage(plate: sender)
}
#IBAction func plate8Pressed(_ sender: UIButton) {
changePlateImage(plate: sender)
}
#IBAction func plate9Pressed(_ sender: UIButton) {
changePlateImage(plate: sender)
}
// and codes go on...
}
You don't need to create 9 IBAction to do that. sender is passed in as a parameter when it's tapped, and it differs each time when different plate is tapped.
So only one IBAction is needed to call changePlateImage.
Do the following:
Connect plate1 to plate9 to platesPressed IBAction func
#IBAction func platesPressed(_ sender: UIButton) {
changePlateImage(plate: sender)
}
func changePlateImage (plate: UIButton) {
// keep the same code
}
You can use the same IBAction for all UIButtons and then use tags to know which buttons you are pressing.
#IBAction func platePressed(_ sender: Any) {
let button = sender as! UIButton
if button.tag == 1 {
// do something
}
}
View tags can be set inside the interface builder
Related
Why when I try to print button title i used print(sender.currentTitel) and isn't working.
And this in below it is work:
print((sender as AnyObject).currentTitle!!)
I assume you are in a IBAction function like this:
#IBAction func buttonTapped(_ sender: Any) {
// print here
}
This is due to the Any reference you declare when you create the IBAction. Two solution.
You can modify your IBAction like this:
#IBAction func buttonTapped(_ sender: UIButton) {
// print(sender.titleLabel?.text)
}
or test the sender conformance:
#IBAction func buttonTapped(_ sender: Any) {
if let button = sender as? UIButton {
// print(button.titleLabel?.text)
}
}
Solution 1 is better if your IBAction is only triggered by button(s)
Solution 2 may be an approach if your IBAction is used by multiple senders
Cheers
I want to be able to call function start within function use without hitting the action button for start. I know simple thing to do is just put print("a") in use. But I am using this as a simple example because I have a more complex problem in mind.
#IBAction func start(_ sender: Any) {
print("a")}
fun use() {
}
viewdidload() {
use()
}
Consider refactoring your functions. Instead of putting the button action code directly inside of the #IBAction function, put it in a separate function. This way, you can call this code from multiple places.
Here is one solution:
#IBAction func start(_ sender: Any) {
startAction()
}
func startAction() {
print("a")
}
func use() {
startAction()
// anything else
}
override func viewDidLoad() {
use()
}
Create an IBOutlet for your button:
#IBOutlet weak var button: UIButton!
Then simply, use this code to trigger its action:
button.sendActions(for: .touchUpInside)
Ok so I am trying to make it when the user flips the cheat mode switch it will disable the answerButton. I did try to set the button to disable near the bottom however it does not appear to do anything. I added the print("") to see if it would print in the console however nothing was printed. I a unsure what is wrong here.
I have pasted my code below.
import Foundation
import UIKit
class SettingsController: UITableViewController {
#IBOutlet weak var cheatSwitch: UISwitch!
override func viewDidLoad() {
super.viewDidLoad()
cheatSwitch.isOn = UserDefaults.standard.bool(forKey: "switchState")
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#IBAction func saveSettings(_ sender: UISwitch) {
UserDefaults.standard.set(cheatSwitch.isOn, forKey: "switchState")
UserDefaults.standard.synchronize()
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
let mainView : ViewController = segue.destination as! ViewController
if cheatSwitch.isOn == true {
print("turn off button")
mainView.btnAnswer.isEnabled = false;
}
else {
print("turn on button")
mainView.btnAnswer.isEnabled = true;
}
}
}
You are saving the value UISwitch's state in UserDefaults so you can use its value in ViewController's method viewDidApper.
override func viewDidAppear(_ animated: Bool) {
self.btnAnswer.isEnabled = !UserDefaults.standard.bool(forKey: "switchState")
}
Note: There is no need to add prepareForSegue in your SettingsController because it will never called when you press back button of NavigationController so consider to remove it.
I have one uiview , Button .At initial my view will be hidden So when my button click I need to show my uiview and when I click same button I need to hide same view.
How to do that in swift 2.0.Now what I did is when I click first time - its showing.
#IBAction func PressRefine(sender: AnyObject) {
menuView.hidden = false
}
But again when I press it should hide.
How to do that???
Try an if statement.
#IBAction func PressRefine(sender: AnyObject) {
if menuView.hidden {
menuView.hidden = false
} else {
menuView.hidden = true
}
}
or as #TedHuinink suggested, with less code.
#IBAction func PressRefine(sender: AnyObject) {
menuView.hidden = !menuView.hidden
}
first make view outlet
#IBOutlet weak var newpptview: UIView!
#IBAction func newpresentation(_ sender: Any) {
if newpptview.isHidden{
newpptview.isHidden = false
} else{
newpptview.isHidden = true
}
}
its better that to all
OR
#IBAction func newpresentation(_ sender: Any) {
newpptview.isHidden = !newpptview.isHidden
}
swift 3 and 4
I am creating an iOS application in which I want to perform an assignment action in button press before running the method prepareForSegue.
I created all controls using Main Story board.
The order of execution for some buttons is
button press action -> prepareForSegue
but for some buttons it is
prepareForSegue-> button press action
How to change the order for second set of buttons?
Here is the code I am using:
import UIKit
class SummaryViewController: UIViewController {
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.
}
var button_prsd = "none"
#IBAction func people_insights(sender: AnyObject) {
button_prsd = "people_insights"
}
#IBAction func industry_research(sender: AnyObject) {
button_prsd = "industry_research"
}
#IBAction func holidays_events(sender: AnyObject) {
button_prsd = "holidays_events"
}
#IBAction func monthly_spotlights(sender: AnyObject) {
button_prsd = "monthly_spotlights"
}
#IBAction func blog(sender: AnyObject) {
button_prsd = "blog"
}
#IBAction func about_us(sender: AnyObject) {
button_prsd = "about_us"
print("button press about us executed")
}
#IBAction func settings(sender: AnyObject) {
button_prsd="settings"
print("button press settings executed")
}
#IBAction func quiz(sender: AnyObject) {
button_prsd="quiz"
print("button press quiz executed")
}
// MARK: - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
// Get the new view controller using segue.destinationViewController.
// Pass the selected object to the new view controller.
let next_view = segue.destinationViewController
if(next_view is DetailViewController)
{
let det_view = next_view as! DetailViewController
det_view.link = button_prsd
print("segue executed")
} else if(next_view is DetailTableViewController)
{
let det_view = next_view as! DetailTableViewController
print("segue executed")
}
}
}
I figured out the problem, when give then code in this way, the execution is just alphabetical order, all the other methods were getting executed before prepareForSegue because the methods come above in alphabetical order
When I renamed the quiz and settings methods as a_quiz and a_settings, it worked