Search code examples
swiftmacoscocoaswift4.2nspopupbutton

Swift NSPopUpButton enum


I'm implementing an NSPopUpButton (for a macOS app using Swift), as in the picture:

enter image description here

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?


Solution

  • 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 }
        }
    }