I'm working on an open source project while learning swift at the same time, the github repository is available at https://github.com/istx25/schedules. I'm trying to add an identifier to the case that will run a function everytime the button is pressed in a UIActionSheet. The code for the action sheet is as follows:
#IBAction func rightButton(sender : AnyObject) {
var sheet: UIActionSheet = UIActionSheet()
let title: String = "Please choose a block rotation"
sheet.title = title
sheet.delegate = self
sheet.addButtonWithTitle("Cancel")
sheet.addButtonWithTitle("Day Four")
sheet.addButtonWithTitle("Day Three")
sheet.addButtonWithTitle("Day Two")
sheet.addButtonWithTitle("Day One")
sheet.cancelButtonIndex = 0
sheet.showInView(self.view)
}
and I've started the switch to defer which button is which as:
func actionSheet(actionSheet: UIActionSheet, clickedButtonAtIndex buttonIndex: Int) {
switch buttonIndex {
case 0:
print("Go Back")
case 1:
print("Day Four")
// Day Four Function
case 2:
print("Day Three")
// Day Three Function
case 3:
print("Day Two")
// Day Two Function
case 4:
print("Day One")
// Day One Function
default:
print("Something's broken")
}
}
I'm wanting each case to be pushed to it's own func method and I'm not sure exactly how I would approach this, so please if anybody could help that would be great. If this question is hard to understand please tell me; so I can get better at asking for help on Stackoverflow! Thanks in advance.
If you're targeting iOS 8 then you shouldn't be using UIActionSheets as they are deprecated. Use UIAlertController with a preferredStyle of UIAlertControllerStyleActionSheet and add actions to it with the addAction() method.
I'm not familiar with Swift (yet), but the usual setup is not with switch/case. Instead each button is associated with an action. That might be a callback. Here, UIControl.sendAction and related code looks like the place to start.
You could create a separate func, and pass in buttonIndex. There you could either do if's or the same switch.
func actionSheet(actionSheet: UIActionSheet, clickedButtonAtIndex buttonIndex: Int) {
switch buttonIndex {
case 0:
print("Go Back")
theFuction(buttonIndex)
case 1:
print("Day Four")
// Day Four Function
theFuction(buttonIndex)
case 2:
print("Day Three")
// Day Three Function
theFuction(buttonIndex)
case 3:
print("Day Two")
// Day Two Function
theFuction(buttonIndex)
case 4:
print("Day One")
// Day One Function
theFuction(buttonIndex)
default:
print("Something's broken")
}
}
func theFuction (btnIndex: Int) {
if btnIndex == 0 {
} else if btnIndex == 1 {
} else if btnIndex == 2 {
} else if btnIndex == 3 {
} else if btnIndex == 4 {
}
}
Related
This is what I've tried and can't figure out where the error is coming from. Is there something missing? Syntax error? I tried doing similar with if-else in the function and also getting errors.
var steps = 0
func incrementSteps() -> Int {
steps += 1
print(steps)
return steps
}
incrementSteps()
let goal = 10000
func progressUpdate() -> Int {
let updated = progressUpdate()/goal
switch updated {
case (0.0..<0.1):
print("Great start")
case (0.11..<0.5):
print("Almost halfway")
case (0.51..<0.9):
print("Almost complete")
default:
print("Beat goal")
}
}
progressUpdate()
You need to specify updated as Double. And cast it back to Int when returning(if you require Int for your requirement).
Note: Also, you need to modify calling the progressUpdate function within progressUpdate definition which causes a recursion. If you want to do so you might want to give condition to break the loop.
func progressUpdate() -> Int {
let updated = Double(steps/goal)
switch updated {
case (0.0..<0.1):
print("Great start")
case (0.11..<0.5):
print("Almost halfway")
case (0.51..<0.9):
print("Almost complete")
default:
print("Beat goal")
}
return Int(updated)
}
This question already has answers here:
Swift switch pattern matching with arrays
(3 answers)
Closed 6 years ago.
I want to put my array of values as a case for my switch statement
I have an array of values say
let intValues = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20 .... 100]
and I want to use a switch statement to be used as a comparison tool like so.
let inputValue = 30 // or some other int value
switch inputValue {
case 101:
// do something lol
/* =============================== */
case intValues: //
// do something more:
/* =============================== */
case 13131:
// do another thing
default:
// do default
}
I know I can do this easily by either doing this case 1, 2, 3, 4, 5, and so on or by using an if statement like so:
if intValues.contains(inputValue) {
// do something more:
} else if inputValue == 101 {
// do something lol
} else if inputValue == 13131 {
// do another thing
} else {
// do default
}
or by doing somethig like
if intValues.contains(inputValue) {
// do something more:
} else {
switch inputValue {
case 101:
// do something lol
case 13131:
// do another thing
default:
// do default
}
}
and vice versa
But is it possible though? to do it with just a switch statement?
You can use case let with where for that.
let intValues = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20]
let inputValue = 30 // or some other int value
switch inputValue {
case let x where intValues.contains(x):
// do something more:
case 101:
// do something lol
case 13131:
// do another thing
default:
// do default
}
You can do this with range operator.
let inputValue = 30
switch value {
case 1...100:
print("between hundred")
case 101:
print("it's 101")
default:
print("outer value")
}
You should just use a countable closed range in your switch cases:
let inputValue = 30
switch inputValue {
case 1...10:
print(1...10)
case 11...20:
print(11...20)
case 21...100:
print(21...100) // "21...100\n"
default:
print("default")
}
I'm rewriting a code from java to swift and need to break a multi-layered switches right way. In Java it looks like :
block0 : switch (topSwithch) {
case one: {
switch (innerSwitch) {
case insideCase: {
if (something){
break block0;
}
// etc
So, I'm breaking one switch from another. How do I do it in swift ?
This is what it'd look like in Swift. I did this in a playground with hardcoded values for the variables:
let topSwitch = 1
let innerSwitch = 4
let one = 1
let insideCase = 4
let something = true
block0 : switch (topSwitch) { //first switch labeled "block0", switching on topSwitch
case one: //topSwitch is 1, one is 1
switch (innerSwitch) { // switching on innerSwitch
case insideCase: // both are 1
if (something){ // if true
break block0; // break from "block0"
}
default: break // else
}
default: break // else
}
So what I'm trying to do is call a function, that will run only 1 function out of 4 possible functions, so it randomly decides which one to do.
In this case those 4 functions that I'm trying to have randomly be chosen are moveUp() moveDown() moveRight() and moveLeft().
This is what I've got right now and its not really working out well. I haven't found anything to help.
func moveComputerPlayer() {
//This is where I have no idea what to do.
"randomly choose to run: moveRight(), moveLeft(), moveUp(), moveDown()
}
Thanks.
Create an array of possible functions/methods.
Select a random element.
Call the chosen function.
Remember, functions are types in Swift.
func moveUp() {}
func moveDown() {}
func moveLeft() {}
func moveRight() {}
func moveComputerPlayer() {
let moves = [
moveUp,
moveDown,
moveLeft,
moveRight,
]
let randomIndex = Int(arc4random_uniform(UInt32(moves.count)))
let selectedMove = moves[randomIndex]
selectedMove()
}
Take a look here:
https://stackoverflow.com/a/24098445/4906484
And then:
let diceRoll = Int(arc4random_uniform(4) + 1)
switch (diceRoll) {
case 1:
moveRight()
case 2:
moveLeft()
case 3:
moveUp()
case 4:
moveDown()
default:
print("Something was wrong:" + diceRoll)
}
Use arc4random() or arc4random_uniform() to generate a random number. Use e.g. switch case statement to associate number with one of the functions.
In your case:
func moveComputerPlayer() {
let rd = Int(arc4random_uniform(4) + 1)
switch rd {
case 1:
moveRight()
case 2:
moveLeft()
case 3:
moveUp()
case 4:
moveDown()
default:
print(rd)
}
}
After reading How to test equality of Swift enums with associated values, I implemented the following enum:
enum CardRank {
case Number(Int)
case Jack
case Queen
case King
case Ace
}
func ==(a: CardRank, b: CardRank) -> Bool {
switch (a, b) {
case (.Number(let a), .Number(let b)) where a == b: return true
case (.Jack, .Jack): return true
case (.Queen, .Queen): return true
case (.King, .King): return true
case (.Ace, .Ace): return true
default: return false
}
}
The following code works:
let card: CardRank = CardRank.Jack
if card == CardRank.Jack {
print("You played a jack!")
} else if card == CardRank.Number(2) {
print("A two cannot be played at this time.")
}
However, this doesn't compile:
let number = CardRank.Number(5)
if number == CardRank.Number {
print("You must play a face card!")
}
... and it gives the following error message:
Binary operator '==' cannot be applied to operands of type 'CardRank' and '(Int) -> CardRank'
I'm assuming this is because it's expecting a full type and CardRank.Number does not specify an entire type, whereas CardRank.Number(2) did. However, in this case, I want it to match any number; not just a specific one.
Obviously I can use a switch statement, but the whole point of implementing the == operator was to avoid this verbose solution:
switch number {
case .Number:
print("You must play a face card!")
default:
break
}
Is there any way to compare an enum with associated values while ignoring its associated value?
Note: I realize that I could change the case in the == method to case (.Number, .Number): return true, but, although it would return true correctly, my comparison would still look like its being compared to a specific number (number == CardRank.Number(2); where 2 is a dummy value) rather than any number (number == CardRank.Number).
Edit: As Etan points out, you can omit the (_) wildcard match to use this more cleanly:
let number = CardRank.Number(5)
if case .Number = number {
// Is a number
} else {
// Something else
}
Unfortunately, I don't believe that there's an easier way than your switch approach in Swift 1.2.
In Swift 2, however, you can use the new if-case pattern match:
let number = CardRank.Number(5)
if case .Number(_) = number {
// Is a number
} else {
// Something else
}
If you're looking to avoid verbosity, you might consider adding an isNumber computed property to your enum that implements your switch statement.
Unfortunately in Swift 1.x there isn't another way so you have to use switch which isn't as elegant as Swift 2's version where you can use if case:
if case .Number = number {
//ignore the value
}
if case .Number(let x) = number {
//without ignoring
}
In Swift 4.2 Equatable will be synthesized if all your associated values conform to Equatable. All you need to do is add Equatable.
enum CardRank: Equatable {
case Number(Int)
case Jack
case Queen
case King
case Ace
}
https://developer.apple.com/documentation/swift/equatable?changes=_3
What I usually do to compare if two enum cases "match" no matter their associated value is:
I have a protocol Matchable:
protocol Matchable {
static func ~= (lhs: Self, rhs: Self) -> Bool
}
Then I make enums conform to it:
extension CardRank: Matchable {
static func ~= (lhs: Self, rhs: Self) -> Bool {
switch (lhs, rhs) {
case
(.number, .number),
(.jack, .jack),
(.queen, .queen),
(.king, .king),
(.ace, .ace):
return true
default:
return false
}
}
}
let card1: CardRank = .number(1)
let card2: CardRank = .number(2)
let card3: CardRank = .jack
print(card1 ~= card2) // true
print(card1 ~= card3) // false
Here's a simpler approach:
enum CardRank {
case Two
case Three
case Four
case Five
case Six
case Seven
case Eight
case Nine
case Ten
case Jack
case Queen
case King
case Ace
var isFaceCard: Bool {
return (self == Jack) || (self == Queen) || (self == King)
}
}
There's no need to overload the == operator, and checking for card type does not require confusing syntax:
let card = CardRank.Jack
if card == CardRank.Jack {
print("You played a jack")
} else if !card.isFaceCard {
print("You must play a face card!")
}
I didn't want to conform Equatable (it didn't help me either) and I wanted to filter for other cases than a specific one, so instead of simply writing card != .Number I had to write the following. (I adjusted my code to this question.)
enum CardRank {
...
var isNumber: Bool {
if case .Number = self { return true }
return false
}
}
So I can write not a number in a complex condition:
if something && !card.isNumber { ... }
I wish I could just write card != .Number, but the compiler was always complaining with Type of expression is ambiguous without more context. Maybe in an upcoming swift version!
You don't need func == or Equatable. Just use an enumeration case pattern.
let rank = CardRank.Ace
if case .Ace = rank { print("Snoopy") }
extension CardRank {
func isSameCaseAs(_ other: CardRank) -> Bool {
switch (self, other) {
case (.Number, .Number),
(.Jack, .Jack),
(.Queen, .Queen),
(.King, .King),
(.Ace, .Ace):
return true
default:
return false
}
}
}
let number = CardRank.Number(1)
let otherNumber = CardRank.Number(2)
number.isSameCaseAs(otherNumber) // true
Just create an extension and ignore the associated types.
From Swift 5.3, you can use the Comparable Enums feature:
enum CardRank: Comparable {
case Number(Int)
case Jack
case Queen
case King
case Ace
}
let cards: [CardRank] = [
.Queen, .Number(8), .Ace, .Number(3), .King
]
print(cards.sorted())
// [.Number(3), .Number(8), .Queen, .King, .Ace]