12

I want to save a custom enum to my SwiftData model. I can get it to work that it shows and even updates the value in the UI. Though, the change of the enum var/entity isn’t persisted when relaunching the app!

Any advice what to watch out for when using custom enums?

My Model

enum Type: Int, Codable {
    case foo = 0
    case bar = 1
}

@Model
final public class Item {
    var type: Type
}

UI Code

struct DetailView: View {
    @Bindable var item: Item
    
    // MARK: -
    var body: some View {
        Picker("Type", selection: $item.type) {
            Text("Foo").tag(Type.foo)
            Text("Bar").tag(Type.bar)
        }
        .pickerStyle(.segmented)
    }
}
HangarRash
  • 7,314
  • 5
  • 5
  • 32
alexkaessner
  • 1,966
  • 1
  • 14
  • 39
  • How does `load` connect to `item`? – lorem ipsum Jun 14 '23 at 19:20
  • @loremipsum Ups sorry, updated my example code. That was a mistake by converting my actual code in a sizable example – so yes. – alexkaessner Jun 14 '23 at 20:32
  • Now are you sure this mimics your actual code? because usually when a `Picker` doesn't work it is because the types don't match exactly. I havent tested this code so I am not sure if this works or now but in theory it should. – lorem ipsum Jun 14 '23 at 20:35
  • @loremipsum Should be, I’ve just checked again … – alexkaessner Jun 14 '23 at 20:40
  • 1
    I have an enum in my model classes and when I turned on debug logging I could see that each item in the enum became a separate field in the models sql table! Very weird indeed. I noticed they mentioned enums and custom types in the introduction video to SwiftData in WWDC but as far as I have found out they haven't mentioned it in any other videos or in the documentation so perhaps this functionality isn't ready yet. – Joakim Danielson Jun 14 '23 at 20:50
  • I can confirm the same happened to me. Using enum types results in no stored data, ever. – Hugo Sousa Jun 15 '23 at 17:11
  • Okay, we are [not alone](https://developer.apple.com/forums/thread/731538)! Filed a feedback on this now (FB12362116). – alexkaessner Jun 16 '23 at 07:03
  • This issue finally fixed in iOS 17 beta 7. Now the code above works fine. [Release notes](https://developer.apple.com/documentation/ios-ipados-release-notes/ios-ipados-17-release-notes#SwiftData) – Andrei Durymanov Aug 25 '23 at 12:29
  • @AndreiDurymanov You are right, it finally is! Feel free to post this as an answer here, so I can mark it as solved. ;) – alexkaessner Aug 25 '23 at 13:00

3 Answers3

7

This solution work for me. Hopefully enums will be fixed in future versions of SwiftData.

enum SomeType: Int, Codable {
    case foo = 0
    case bar = 1
}

@Model
final public class Item {
    
    @Transient var type: SomeType {
        get { SomeType(rawValue: _type)! }
        set { _type = newValue.rawValue }
    }
    
    @Attribute var _type: SomeType.RawValue
    
} 
Community
  • 1
  • 1
  • 1
    If the name of the property has not changed then we don't need @Attribute(originalName) attribute right? We can just remove it. – azamsharp Jul 23 '23 at 17:55
  • Thanks, this worked for me too! Hopefully this will get fixed soon. – Nathaniel Martin Jul 28 '23 at 04:00
  • 1
    @azamsharp you are right. It does nothing here. I've removed it. – Andrei Durymanov Jul 31 '23 at 09:18
  • These gyrations to get this to work are pretty bonkers, but it did work for me. Er, at least it compiled. I have no idea if this is actually going to persist or not. I had to use the `[at]Attrubute var _type` portion of the solution for it to compile in Beta 6. Without it, Xcode said “No”. :D – Evan K. Stone Aug 16 '23 at 14:23
2

The issue has been fixed since iOS version 17 beta 7. Now the code below works correctly. Release notes

enum ItemType: Int, Codable {
    case foo = 0
    case bar = 1
}

@Model
final public class Item {
    
    var type: ItemType
    
    init(type: ItemType) {
        self.type = type
    }
    
}

struct DetailView: View {
    
    @Bindable var item: Item
    
    var body: some View {
        Picker("Type", selection: $item.type) {
            Text("Foo").tag(ItemType.foo)
            Text("Bar").tag(ItemType.bar)
        }
        .pickerStyle(.segmented)
    }
    
}
0

Are you witnessing the same issue with the enum placed inside of the class?

@Model
final public class Item {
    var type: ItemType

    enum ItemType: Int, Codable {
        case foo, bar
    }

    init(type: ItemType) {
        self.type = type
    }
}
  • Unfortunately not, it’s the same result … btw. also makes it impractical as the enum isn’t easily accessible outside of the class. – alexkaessner Jun 27 '23 at 08:30