CustomPersistable alongside RawRepresentable

As the documentation mentions I have implemented an extension CGPoint: CustomPersistable to persist CGPoint values. So far so good. Additionally I have to persist CGPoint values in SwiftUI’s @SceneStorage. For this I added another CGPoint extension which implements RawRepresentable.

extension CGPoint: RawRepresentable {
    public var rawValue: String {
        guard let data = try? JSONEncoder().encode(self),
              let string = String(data: data, encoding: .utf8)
        else {
            return "{}"
        }
        return string
    }

    public init?(rawValue: String) {
        guard let data = rawValue.data(using: .utf8),
              let result = try? JSONDecoder().decode(CGPoint.self, from: data)
        else {
            return nil
        }
        self = result
    }
}

Unfortunately these two extensions don’t want to coexist. If I implement the RawRepresentable extension I get an error for the CustomPersistable extension.

Any ideas?

Two things

When posting, please include the code textually - that way if we need to use it in an answer we won’t have to re-type it. Also, we need a clearer picture of your objects.

The PersistedType on CGSize must be a type Realm Supports - what is CGSizeObject?

Okay, it seems it’s not possible to edit/update a post, so I write it again.

This is the code in question:

public class CGPointObject: EmbeddedObject {
    @Persisted var x: Double
    @Persisted var y: Double
}

extension CGPoint: CustomPersistable {
    public typealias PersistedType = CGPointObject
    public init(persistedValue: CGPointObject) {
        self.init(x: persistedValue.x, y: persistedValue.y)
    }
    public var persistableValue: PersistedType {
        CGPointObject(value: [x, y])
    }
}

extension CGPoint: RawRepresentable {
    public var rawValue: String {
        guard let data = try? JSONEncoder().encode(self),
              let string = String(data: data, encoding: .utf8)
        else {
            return "{}"
        }
        return string
    }

    public init?(rawValue: String) {
        guard let data = rawValue.data(using: .utf8),
              let result = try? JSONDecoder().decode(CGPoint.self, from: data)
        else {
            return nil
        }
        self = result
    }
}

By adding the last extension I get the error as shown in the screenshot. CGSizeObject is the type Realm uses to persist CGSize.

You can edit your post by clicking the pencil at the bottom

Gotcha. However, if you look at your code, the CGSize object PersistedType is CGSizeObject

public typealias PersistedType = CGSizeObject

but CGSizeObject is not defined. Not saying that’s the issue, but for clarity it should be included so we know what it looks like.

Ah, now I see my mistake. It’s the wrong screenshot. It is for CGSize instead CGPoint. However, I made the same extensions for all three types CGPoint, CGSize and CGRect. It’s every time the same error for all three.

Right and the problem is still the same:

public typealias PersistedType = CGSizeObject

CGSizeObject is undefined. We don’t know what that is and there’s a possibility Realm doesn’t know what it is either as it’s not one of the supported types - unless it’s Type Projected as well - but we don’t know that.

Please include what CGSizeObject looks like so we can eliminate it as being the issue.

It’s similar to the CGPointObject of my example from above. It doesn’t matter. The error message is always the same, for all three types when I add the RawRepresentable extension.

For the sake of completeness, this is the CGSizeObject:

public class CGSizeObject: EmbeddedObject {
    @Persisted var width: Double
    @Persisted var height: Double
}

and its belonging CustomPersistable extension:

extension CGSize: CustomPersistable {
    public typealias PersistedType = CGSizeObject
    public init(persistedValue: CGSizeObject) {
        self.init(width: persistedValue.width, height: persistedValue.height)
    }
    public var persistableValue: PersistedType {
        CGSizeObject(value: [width, height])
    }
}

Ok. interesting issue. Something to note from the Type Projections docs is this

These are protocols modeled after Swift’s built-in RawRepresentable.

which led me to this Github Bug Report

Cannot use RawRepresentable/OptionSet types with CustomPersistable/FailableCustomPersistable #7612

Which seems to be a similar (exact) issue with no resolution.

1 Like

Exactly! The same problem we have.