This question already has answers here:
How to choose a random enumeration value
(9 answers)
Closed 4 years ago.
enum TrackingEvent: String {
case notificationScreenLoaded = "Notification Screen"
case homeScreenLoaded = "Home Screen"
case homeScreenViewBill = "Home Screen View Bill Button"
case homeScreenPayBill = "Home Screen Pay Bill Button"
case homeScreenViewLastPayment = "Home Screen Last Payment Section"
case chartToggleUsage = "Charts Toggle"
case chartExplanation = "Charts Explanation Screen"
}
for this example, how do I get a random string? So far what I search in StackOverflow examples the enum are all UInt32 return type
Put all into an array and emit a random index item,
extension TrackingEvent {
static func random() -> TrackingEvent {
let all: [TrackingEvent] = [.notificationScreenLoaded,
.homeScreenLoaded,
.homeScreenViewBill,
.homeScreenPayBill,
.homeScreenViewLastPayment,
.chartToggleUsage,
.chartExplanation]
let randomIndex = Int(arc4random()) % all.count
return all[randomIndex]
}
}
You need to create a function to get random UInt32 with upper bound equal to the number of cases in the enum TrackingEvent and return the case based on a random number.
enum TrackingEvent: String {
case notificationScreenLoaded = "Notification Screen"
case homeScreenLoaded = "Home Screen"
case homeScreenViewBill = "Home Screen View Bill Button"
case homeScreenPayBill = "Home Screen Pay Bill Button"
case homeScreenViewLastPayment = "Home Screen Last Payment Section"
case chartToggleUsage = "Charts Toggle"
case chartExplanation = "Charts Explanation Screen"
static func random() -> TrackingEvent {
let rand = arc4random_uniform(7)
switch rand {
case 1:
return .homeScreenLoaded
case 2:
return .homeScreenViewBill
case 3:
return .homeScreenPayBill
case 4:
return .homeScreenViewLastPayment
case 5:
return .chartToggleUsage
case 6:
return .chartExplanation
default:
return .notificationScreenLoaded
}
}
}
You can use it like
let random = TrackingEvent.random()
Related
I'm implementing an NSPopUpButton (for a macOS app using Swift), as in the picture:
And, I have the following code, which actually works:
enum Importance: Int8 {
case EXTREMELY_IMPORTANT = 5
case VERY_IMPORTANT = 4
case IMPORTANT = 3
case NORMAL = 2
case NOT_IMPORTANT = 1
case JUST_FOR_RECORD = 0
case ERROR = -1
}
let english_extremely_important = "Extremely Important"
let english_very_important = "Very Important"
let english_important = "Important"
let english_normal = "Normal"
let english_not_important = "Not Important"
let english_just_for_record = "Just for Record"
var importanceEnglishItems: [String] = {
return [
english_extremely_important,
english_very_important,
english_important,
english_normal,
english_not_important,
english_just_for_record
]
}()
func getImportance(importanceEnglish: String) -> Int8 {
switch importanceEnglish {
case english_extremely_important:
return Importance.EXTREMELY_IMPORTANT.rawValue
case english_very_important:
return Importance.VERY_IMPORTANT.rawValue
case english_important:
return Importance.IMPORTANT.rawValue
case english_normal:
return Importance.NORMAL.rawValue
case english_not_important:
return Importance.NOT_IMPORTANT.rawValue
case english_just_for_record:
return Importance.JUST_FOR_RECORD.rawValue
default:
return Importance.ERROR.rawValue
}
}
Whenever the user selects the item in the popup menu, this code executes:
#IBAction func handleImportancePopUpButtonSelectionChanged(_ importancePopUpButton: NSPopUpButton) {
let importanceIndex = getImportance(importanceEnglish: importancePopUpButton.titleOfSelectedItem!)
print("importanceIndex: \(importanceIndex)")
}
It works, BUT... I believe this implementation isn't that elegant. What is the better way to do this?
I have these requirements in mind:
The corresponding values of the enums list "enum Importance: Int8" are fixed. For example, EXTREMELY_IMPORTANT must be 5, as it is already coded on the server-side. Therefore, based on user's selection, the corresponding enum values must be sent to be server. (EXTREMELY_IMPORTANT == 5, etc.)
Further to the above point, the selection's index of the NSPopUpButton cannot be used for sending to the server. For example, "Extremely Important" would be 0 since it is the first one on the top of the list.
The NSPopUpButton is using "titleOfSelectedItem" and then call getImportance(importanceEnglish: String) method, which is inefficient, and should be better off using "indexOfSelectedItem" instead. That means, it would be more efficient to use the selection index of "Extremely Important" (which is 0) to retrieve the value of 5 for sending to the server.
Better yet, if everything can support support localization (more languages: Japanese, etc.) using standard practice.
How can I make my Swift code more beautiful?
I would change the encapsulation a little bit to make it more readable; such solution would be a better way to start with in my view, (e.g. adding localisation or extending it by new values, etc...).
this idea is obviously not the only way – there are many other alterations/solutions could be as good as this (or maybe even better).
Swift 4.2
enum Importance: Int, CaseIterable {
case extremelyImportant = 5
case veryImportant = 4
case important = 3
case normal = 2
case notImportant = 1
case justForRecord = 0
var friendlyName: String? {
switch self {
case .extremelyImportant: return "Extremely Important"
case .veryImportant: return "Very Important"
case .important: return "Important"
case .notImportant: return "Not Important"
case .justForRecord: return "Just for Record"
default: return nil
}
}
init?(withName name: String) {
guard let importance = Importance.allCases.first(where: {
guard let friendlyName = $0.friendlyName else { return false }
return friendlyName == name
}) else { return nil }
self = importance
}
static var allCasesNames: [String] {
return Importance.allCases.compactMap { $0.friendlyName }
}
}
You can create NSMenuItem with a Title and importance as tag and add it NSPopUpButton.menu.items.
override func viewDidLoad() {
super.viewDidLoad()
popUpButton.menu?.items = self.importanceEnglishItems
}
class func MenuItem(title: String, tag: Int) -> NSMenuItem {
let item = NSMenuItem(title: title, action: nil, keyEquivalent: "")
item.tag = tag
return item
}
var importanceEnglishItems: [NSMenuItem] = {
return [
MenuItem(title: "Extremely Important", tag: 5),
MenuItem(title: "Very Important", tag: 4),
MenuItem(title: "Important", tag: 3),
MenuItem(title: "Normal", tag: 2),
MenuItem(title: "Not Important", tag: 1),
MenuItem(title: "Just for Record", tag: 0)
]
}()
#IBAction func handleSelection(_ sender: NSPopUpButton) {
guard let item = sender.selectedItem else { return }
print("importanceIndex: \(item.tag)")
}
Given this code:
class Item{}
func foo(item:Item){}
enum SelectionType{
case single(resultsHandler:(Item)->Void)
case multi(resultsHandler:([Item])->Void)
}
var selectionType:SelectionType = .single(resultsHandler:foo)
// This line won't compile
let title = (selectionType == .single)
? "Choose an item"
: "Choose items"
How can you update the part that won't compile?
A ternary operator cannot work for enums with associated values, because the classic equality operator does not work with them. You have to use pattern matching, or if case syntax:
let title: String
if case .single = selectionType {
title = "Choose an item"
} else {
title = "Choose items"
}
I don't know if there is a direct way to address what you are looking for.
My understanding:
Enums are not equatable by default, you have to implement Equatable
For enums with associated values, even if you implemented it, I don't think it is possible to achieve what you had asked.
Computed variable (Workaround 1):
enum SelectionType{
case single(resultsHandler:(Item)->Void)
case multi(resultsHandler:([Item])->Void)
var title : String {
let text : String
switch self {
case .single(_):
text = "Choose an item"
case .multi(_):
text = "Choose items"
}
return text
}
}
var title = selectionType.title
Use if case (Workaround 2):
if case .single(_) = selectionType {
print("Choose an item")
}
else {
print("Choose items")
}
I'm trying to detect the type of number a user enters into a textField. For example
if the user enters 1000 The program should return 1Kcs
if the user enters 12,000, The program should return 12Kcs
if the user enters 12,000,000 The program should return 12MCS
How do I go about this in swift?
Thousands - Kcs
Hundreds - Mcs
This should to the job
extension Int {
var unitFormatted: String {
let positive = self < 0 ? -self : self
switch positive {
case 1_000_000..<Int.max: return "\(self / 1_000_000)MCS"
case 1_000..<1_000_000: return "\(self / 1_000)Kcs"
default: return "\(self)"
}
}
}
Examples
0.unitFormatted // "0"
1.unitFormatted // "1"
1000.unitFormatted // "1Kcs"
12000.unitFormatted // "12Kcs"
12000000.unitFormatted // "12MCS"
Some variation of this to fit your needs should be fine:
var num = 12000000
switch num {
case 1000...999999:
print(String(num/1000) + "Kcs")
case 1000000...999999999:
print(String(num/1000000) + "Mcs")
default:
print(num)
}
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 {
}
}
Given the following enum:
enum GameLevel {
case Level(Int)
case TutorialLevel, BossLevel
}
How to generate a random variable of type GameLevel in Swift?
I updated your enum as per Apple standards (Capital letter to start a Type, and no abbreviations.
enum GameLevel {
case Level(Int)
case TutorialLevel, BossLevel
}
First, how to create a constant or variable with a value for level.
let level = GameLevel.Level(1)
Next, for a random value to level use arc4random_uniform:
let maxGameLevel: UInt32 = 10
let randomGameLevel: Int = Int(arc4random_uniform(maxGameLevel))
let level = GameLevel.Level(randomGameLevel)
Of course, this can be put into a function:
func RandomGameLevel() -> GameLevel {
let maxGameLevel: UInt32 = 10
return .Level(Int(arc4random_uniform(maxGameLevel)))
}
let level = RandomGameLevel()
Finally, here is how you would use it in a case statement:
switch level {
case .Level(let levelValue):
println("Level \(levelValue)")
case .TutorialLevel:
println("Tutorial Level")
case .BossLevel:
println("Boss Level")
}
Update
OK, it's not too hard to include the other values. I'll also put all of this into GameLevel to package it up better.
enum GameLevel {
case Level(Int)
case TutorialLevel, BossLevel
static func Random() -> GameLevel {
let maxGameLevel: UInt32 = 10 /* levels will be 0 through 9 */
let otherGameLevels: UInt32 = 2 /* TutorialLevel and BossLevel */
let levelValue = Int(arc4random_uniform(maxGameLevel + otherGameLevels))
switch levelValue {
case 10: return .TutorialLevel
case 11: return .BossLevel
default: return .Level(levelValue)
}
}
}
Then
let level = GameLevel.Random()
Not the cleanest, but it's a start.
enum GameLevel: CaseIterable {
case Level(Int)
case TutorialLevel, BossLevel
}
let level:GameLevel = GameLevel.allCases.randomElement()!
Why would you need it that way? :(
Assign numbers to your start and final levels and implement a function, which will return random in that range as Lvl(int)