Why this enum is strange?

Anyone can help me, Ive just starting to study swift, and now doing the iOS App Dev Tutorial (Scrumdinger), so, in some part of the tutorial Ive created this enum, and it didn't get the colors when used the var mainColor, or didn't get the capitalized string o the value, when used the var name, just return yellow (not capitalized) for example.

How are you testing that?

print(Theme.yellow.name)

should give you "Yellow"

Colours are more tricky: while there are Color.red, Color.green, etc, AFAIK there is no way to get the standard colour by name "red", "green", etc unless you put the correspondingly named colours in the asset catalogue.

I have just checked and this is the result:

 let mainColor = Theme.teal.mainColor
 print(mainColor) // NamedColor(name: "teal", bundle: nil)
        
let name = Theme.indigo.name     
print(name) // Indigo

It seems that the name is returned capitalised as expected, but the Color call is looking for a color in your app bundle (assets). If you have not declared the colors there, you will not get it. This means that this should not be a problem of the enum, but of the way Color is initialised.

P.S.: If you paste the code and use the code formatting option, it is easier to reproduce the problem. :)

P.P.S.: Color is part of Apple's SwiftUI framework and not of Swift

Theme file that has the enum

import SwiftUI

enum Theme: String {
    case bubblegum
    case buttercup
    case indigo
    case lavender
    case magenta
    case navy
    case orange
    case oxblood
    case periwinkle
    case poppy
    case purple
    case seafoam
    case sky
    case tan
    case teal
    case yellow
    
    var accentColor: Color {
            switch self {
            case .bubblegum, .buttercup, .lavender, .orange, .periwinkle, .poppy, .seafoam, .sky, .tan, .teal, .yellow: return .black
            case .indigo, .magenta, .navy, .oxblood, .purple: return .white
            }
        }
    
    var mainColor: Color {
        Color(rawValue)
    }
    
    var name: String {
        rawValue.capitalized
    }
}

Class that actually initialize the Theme:

import Foundation

struct DailyScrum: Identifiable {
    let id: UUID
    var title: String
    var attendees: Array<Attendee>
    var lengthInMinutes: Int
    var lengthInMinutesAsDouble: Double {
        get {
            Double(lengthInMinutes)
        }
        set {
                    lengthInMinutes = Int(newValue)
        }
    }
    var theme: Theme
    
    init(id: UUID = UUID(), title: String, attendees: Array<Attendee>, lengthInMinutes: Int, theme: Theme) {
        self.id = id
        self.title = title
        self.attendees = attendees
        self.lengthInMinutes = lengthInMinutes
        self.theme = theme
    }
}

extension DailyScrum {
    struct Attendee: Identifiable {
        let id: UUID
        var name: String
        
        init(id: UUID = UUID(), name: String) {
            self.id = id
            self.name = name
        }
    }
}

extension DailyScrum {
    static let sampleData: Array<DailyScrum> = [
        DailyScrum(title: "Design",
                   attendees: [Attendee(name: "Diego"), Attendee(name: "Roberto"), Attendee(name: "Rodrigo")],
                   lengthInMinutes: 10,
                   theme: .yellow),
        DailyScrum(title: "App dev",
                   attendees: [Attendee(name: "Diego"), Attendee(name: "Roberto"), Attendee(name: "Rodrigo")],
                   lengthInMinutes: 15,
                   theme: .indigo),
        DailyScrum(title: "Start backend",
                   attendees: [Attendee(name: "Diego"), Attendee(name: "Roberto"), Attendee(name: "Rodrigo")],
                   lengthInMinutes: 30,
                   theme: .purple)
    
    ]
    
    static var emptyScrum: DailyScrum {
        DailyScrum(title: "", attendees: [], lengthInMinutes: 5, theme: .sky)
    }
}

So when im using im actually using this way:

NavigationLink(destination: DetailView(scrum: scrum)) {
                    CardView(scrum: scrum)
}
                .listRowBackground(scrum.theme.mainColor)

Ok, but have you declared your colors in the assets catalogue like this?:

Because:

Color("orange")  // looks for a color called "orange" in the assets catalogue
Color(.orange)   // gives your the color "orange" - this is a static let declared in the SwiftUI Color class....

and Color(rawValue) behaves just like Color("orange")

Oh, I haven't created this asset catalogue, will try to find out how to create

This instruction covers the topic very well:

1 Like

Thank you, I've created with the guide and worked fine:

Still a problem with capitalisation?

This is a bit odd limitation that standard colours like red, green, etc are not available via Color(systemName:). Here's a possible workaround:

import SwiftUI

#if canImport(UIKit)
import UIKit
extension Color {
    init?(systemName: String) {
        let sel = Selector(systemName)
        guard UIColor.self.responds(to: sel), 
            let result = UIColor.self.perform(sel) else {
            print("no such system, color: \(systemName)")
            return nil
        }
        let object = result as Unmanaged<AnyObject>
        let color = object.takeUnretainedValue() as! UIColor
        self.init(color)
    }
}
#endif
#if canImport(Cocoa)
import Cocoa
extension Color {
    init?(systemName: String) {
        let sel = Selector(systemName)
        guard NSColor.self.responds(to: sel), 
            let result = NSColor.self.perform(sel) else {
            print("no such system, color: \(systemName)")
            return nil
        }
        let object = result as Unmanaged<AnyObject>
        let color = object.takeUnretainedValue() as! NSColor
        self.init(color)
    }
}
#endif

Should work for both UIKit and Cocoa clients utilising Obj-c's performSelector feature. Minimally tested.

PS. forgot to mention: systemName should be in the form: "systemRedColor", "systemBlueColor" and so on.