In my program 2 functions (IBAction player.Move(UIButton) and autoMove()) are supposed to be called by turns till all of the fields (UIButtons) has been clicked. For this I've created a function play(). However, I don't know how can I put the IBAction playerMove inside of play() function, because I need no parameter here.
I've found some answers and tried self.playerMove(nil) and self.playerMove(self) but it doesn't work.
import UIKit
class ViewController: UIViewController {
#IBOutlet var cardsArray: Array<UIButton> = []
var randomCard = 0
override func viewDidLoad() {
super.viewDidLoad()
self.play()
// Do any additional setup after loading the view, typically from a nib.
}
func play () {
self.autoMove()
self.playerMove(self) // <----- here is my problem
}
#IBAction func playerMove(sender: UIButton) {
switch (sender) {
case self.cardsArray[0]:
self.cardPressedAll(0)
case self.cardsArray[1]:
self.cardPressedAll(1)
case self.cardsArray[2]:
self.cardPressedAll(2)
case self.cardsArray[3]:
self.cardPressedAll(3)
default: break
}
}
func cardPressedAll (cardNumber: Int) {
self.cardsArray[cardNumber].enabled = false
self.cardsArray[cardNumber].setBackgroundImage(UIImage(named: "cross"), forState: UIControlState.Normal)
self.cardsArray.removeAtIndex(cardNumber)
}
func autoMove (){
self.randomCard = Int(arc4random_uniform(UInt32(self.cardsArray.count)))
self.cardsArray[self.randomCard].enabled = false
self.cardsArray[self.randomCard].setBackgroundImage(UIImage(named: "nought"), forState: UIControlState.Normal)
self.cardsArray.removeAtIndex(self.randomCard)
}
}
Either you have to call playerMove: without a button, in which case you have to declare the sender parameter as an optional. Like:
#IBAction func playerMove(sender: UIButton?) {
UIButton means that you have to pass in a button. nil is not a button, but with UIButton?, that is to say Optional<UIButton>, nil is a valid value meaning the absence of a button.
Or you have to work out which button you want to pass to playerMove: to make it do what you want. Sit down and work out what you want to have happen, and what the code needs to do in order to make that happen.
Try
self.playerMove(UIButton())
Your func playerMove has parameters expecting sender to be of type UIButton, self or nil would be an unexpected object.
Edit:
You could us optional parameters by placing ?. This would allow you to call self.playerMove(nil) if needed.
#IBAction func playerMove(sender: UIButton?) {
if sender != nil {
//handle when button is passed
} else {
//handle when nil is passed
}
}
doSomeTask(UIButton()) in swift 5.0 and onward worked for me
Related
I'm trying to create an array composed of multiple tools.
The array changes depending on which tools are carried.
Expecting a long list of tools I would like to avoid having to write an action for each single element to add or remove from the array. ( I managed this part as you'll see below)
Instead I'd like to use the name of the toggle switch and apply the same action to all the toggles on the screen.
I came up with this inelegant method:
import UIKit
class mainVC: UIViewController {
var myEquippement: [String] = []
override func viewDidLoad() {
super.viewDidLoad()
}
#IBAction func shovelSwitch(_ sender: UISwitch) {
if sender.isOn{
myEquippement.append("Shovel")
}
else {
let subjectIndex = myEquippement.firstIndex(of: "Shovel")
myEquippement.remove(at: subjectIndex!)
}
}
#IBAction func hammerSwitch(_ sender: UISwitch) {
if sender.isOn{
myEquippement.append("Hammer")
}
else {
let subjectIndex = myEquippement.firstIndex(of: "Hammer")
myEquippement.remove(at: subjectIndex!)
}
}
#IBAction func screwdriverSwitch(_ sender: UISwitch) {
if sender.isOn{
myEquippement.append("Screwdriver")
}
else {
let subjectIndex = myEquippement.firstIndex(of: "Screwdriver")
myEquippement.remove(at: subjectIndex!)
}
}
#IBAction func sawSwitch(_ sender: UISwitch) {
if sender.isOn{
myEquippement.append("Saw")
}
else {
let subjectIndex = myEquippement.firstIndex(of: "Saw")
myEquippement.remove(at: subjectIndex!)
}
}
}
could you point me please to a better way of doing it.
I thought of using something like this:
#IBAction func toggleSwitched(_ sender: UISwitch) {
if sender.isOn{
myEquippement.append(sender.title!)
}
else {
let subjectIndex = myEquippement.firstIndex(of: sender.title!)
myEquippement.remove(at: subjectIndex!)
}
}
but sender.title always returns a nil value, the force unwrapping crashes the app.
Thanks in advance for your help.
One solution would be to have a master array of tool names. When creating a switch, assign its tag property to the corresponding index within that array.
Then in your single switch handler you can use the sender's tag to get the name of the tool from the master list of tool names. That will give you the title for the switch. Then your logic for adding/removing the title from myEquipment can be used.
I'm following this tutorial to send data back using Closures.
https://betterprogramming.pub/5-ways-to-pass-data-between-view-controllers-18acb467f5ec
in this tutorial point no 4 that is "Closures". I have two VC's one for selecting pet (FormsVC) and one for displaying selected pet (ProfileVC).
below is a code for ProfileVC:
// ProfileVC
// MARK: - Set Fav Pet Name
func setPetName(pet: String) {
lblFavouritePet.text = pet
}
// MARK: - Button Select Your Fav Pet Event
#IBAction func btnSelectYourFavPet_Event(_ sender: UIButton) {
let vc = FormsVC()
self.present(vc, animated: true)
}
below is a code for FormsVC:
// FormsVC
// MARK: - Variable Declaration
var favoritePet = String()
// MARK: - viewDidLoad Method
override func viewDidLoad() {
super.viewDidLoad()
setUpFormsVC()
}
// MARK: - Set Up FormsVC
func setUpFormsVC() {
btnDog.titleLabel?.text = "Dog"
btnCat.titleLabel?.text = "Cat"
btnRabbit.titleLabel?.text = "Rabbit"
btnBird.titleLabel?.text = "Bird"
}
// MARK: - Button Selected Pet Event
#IBAction func selectedPetEvent(_ sender: UIButton) {
favoritePet = sender.titleLabel?.text ?? "Dog"
}
// MARK: - Selected Pet Name
func getFavoritePet() -> String {
return favoritePet
}
// MARK: - Button OK Event
#IBAction func btnOk_Event(_ sender: UIButton) {
let vc = ProfileVC()
self.dismiss(animated: true, completion: {
vc.setPetName(pet: self.getFavoritePet())
})
// problem occurs when I dismiss FormsVC after selecting pet, the label displaying selected pet name (lblFavouritePet) throwing error of "Unexpectedly found nil while implicitly unwrapping an Optional value"
}
}
Problem occurs when I dismiss FormsVC after selecting pet, the label displaying selected pet name (lblFavouritePet) throwing error of "Unexpectedly found nil while implicitly unwrapping an Optional value". I have no idea why it is found nil because I have assigned favoritePet's value of selected pet. Sorry for this dumb question, Could anyone help me ?
As #matt mentioned, you should take the presenting view controller, not create the new instance. It's stated in the tutorial you use:
if let vc = presentingViewController as? Profile...
Your app crashes, because you use storyboards, and lblFavoritePet is an #IBOutlet implicitly unwrapped optional, hence, you should initialize it from the storyboard. But you initialize it without using the storyboard, and the property remains nil.
So, don't make a new instance, use the code that is stated in the tutorial.
And follow the naming conventions.
First of all, you have to declarer the closer where you want to pass data.
// FormsVC
// MARK: - Variable Declaration
let completion: ((String)->Void)? = nil
// MARK: - Button OK Event
#IBAction func btnOk_Event(_ sender: UIButton) {
completion?(self.getFavoritePet())
self.dismiss(animated: true)
}
The second part is you have to write the code to receive the data
// ProfileVC
// MARK: - Button Select Your Fav Pet Event
#IBAction func btnSelectYourFavPet_Event(_ sender: UIButton) {
let vc = FormsVC()
vc.completion = { petName in
self.setPetName(pet: petName)
}
self.present(vc, animated: true)
}
i just want to know the method to handle multiple click event on single button.(e.g FACEBOOK like button if i tapped multiple time then it may work perfect)
below code give you some idea and if there is any appropriate solution then give me as soon as possible.
class LikeViewController: UIViewController {
//MARK:- Outlets
#IBOutlet weak var btnLike: UIButton!
#IBOutlet weak var lblDescription: UILabel!
//MARK:- Variables
var objModelWatchList:WatchListModel?
var objUser = WatchListModel()
//MARK:- Lifecycle methods
override func viewDidLoad() {
super.viewDidLoad()
getWatchList()
}
//MARK:- Functions
//Function for prepare UI
func prepareUI() {
btnLike.isSelected = isLike()
}
//Function for prepare data from api
func getWatchList() {
objUser.videoId = 216
objUser.type = "VIDEO"
APIService.sharedInstance.getWatchList(parameters: objUser.toDictionary() as [String : AnyObject], success: { (dataSuccess) -> (Void) in
self.objModelWatchList = dataSuccess
DispatchQueue.main.async {
self.prepareUI()
self.lblDescription.text = self.objModelWatchList?.message
}
}) { (resultFailure) -> (Void) in
print(resultFailure)
}
}
//Function to varify the status of like
func isLike() -> Bool {
return objModelWatchList!.status == 1 ? true : false
}
//MARK:- Actions
#IBAction func btnLikeClicked(_ sender: UIButton) {
sender.isSelected = !sender.isSelected
self.getWatchList()
}
}
Thank You.
You have to disable your button when API call and when u will get right response after the processing on that response you have to enable it.
Its works for me. I have a same issue.
if you refer to manage several events taps...I recommend that use tapGestureRecognizer or variants, these can manage events that you comment for example...:
Single tap,double tap or more taps to trigger function event
Hold tap [UILongPressGestureRecognizer]
if you refer to same button called severals function in diferents situations i recommend the use un tag button for example:
function examplefunctionA(){
//Another Proccess
//Another Proccess
self.button.tag = 2
}
function examplefunctionB(){
//Another Proccess
//Another Proccess
self.button.tag = 1
}
func buttonclicked(sender: UIButton) {
if sender.tag == 1 {
examplefunctionA()
}else if sender.tag == 2 {
examplefunctionB()
}
}
I have a function that runs when a button is pressed.
Inside that function is another function.
I would like to pass the pressed button into the inner function so that I can change the text of the button depending on stuff in that inner function.
#IBAction func newItem(sender: AnyObject) {
let urlFetch:String = urlField.text!
self.service.createNewItem(urlFetch, I_WANT_BUTTON_HERE)
}
How do I pass the button into the function?
If it helps this is the function that I am passing it to:
func createNewItem(item_url: String, plus_button: UIButton) {
let dataDictionary = ["url" : item_url]
self.post("item/create", data: dataDictionary).responseJSON { (response) -> Void in
plus_button.titleLabel!.text = "success"
}
}
Later I will add an if statement that changes the text depending on what the response is.
The object passed into newItem method is actually the button you tapped so you can securely convert the type of parameter sender into UIButton like below:
#IBAction func newItem(sender: UIButton) {
...
self.service.createNewItem(urlFetch, sender)
}
There is also one thing though. Setting the text of titleLabel is not the right way of updating the title of button. You should be using setTitle:forState instead:
func createNewItem(item_url: String, plus_button: UIButton) {
...
plus_button.setTitle("success", forState: .Normal)
}
Instead of sending AnyObject as parameter in the newItem function, pass a UIButton.
#IBAction func newItem(sender: UIButton) {
let urlFetch:String = urlField.text!
self.service.createNewItem(urlFetch, sender)
}
I got two functions running called updatePrice and updateTime, and I want to stop them when I click an UIButton.
func updateTime() {...}
func updatePrice() {...}
// ..
#IBAction func Button(sender: UIButton) {
// What should I write here?
}
Do something like NSOperations do: make a boolean and periodically check it in those functions. Something like:
var stopFuncs = false
and later in functions at sensitive moments insert that:
if stopFuncs { return }
and add this to button code:
stopFuncs = true