Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

RFC: Swift Codable Attribute Support #375

Open
atomicbird opened this issue Aug 11, 2018 · 6 comments
Open

RFC: Swift Codable Attribute Support #375

atomicbird opened this issue Aug 11, 2018 · 6 comments

Comments

@atomicbird
Copy link
Collaborator

atomicbird commented Aug 11, 2018

Feature Request

I think it would be extremely useful if Swift developers could use Codable attributes in Core Data.

Core Data has long supported transformable properties, which work transparently with any type that conforms to NSCoding. Supporting Codable is conceptually the same thing: values are stored in a binary form and converted to/from a deserialized value as needed. Core Data doesn't have support for this (see rdar://37708071 if you can), but in the meantime we can do something about it.

Note that this issue is only about Codable for attributes. Implementing Codable for managed object subclasses is a very different question, addressed in #377

The Plan

I'm working on the following scheme and would appreciate any feedback people might have.

  1. Declare an attribute as "binary".

  2. In the attribute's userInfo, include a new key to be named attributeCodableTypeName. The value is any Swift type name where the type conforms to Codable.

  3. mogenerator generates custom accessor code for the property that converts to/from the Codable type. The code can use any valid binary encoding so long as it's the same going in and coming out. I'm testing this with JSONEncoder/JSONDecoder but the property list versions would work too.

For example, given the following Swift type:

public enum EventType: UInt16, Codable {
    case party
    case concert
    case birthday
    case presentation
}

One could add a binary attribute type to an entity, and include attributeCodableTypeName = EventType in user info. The generated code for this property would be:

public var type: EventType? {
	get {
		let key = Event.Attributes.type
		willAccessValue(forKey: key)
		defer { didAccessValue(forKey: key) }

		guard let primitiveValue = primitiveValue(forKey: key) as? Data else {
			return nil
		}

		return try? JSONDecoder().decode(EventType.self, from: primitiveValue)
	}
	set {
		let key = Event.Attributes.type
		willChangeValue(forKey: key)
		defer { didChangeValue(forKey: key) }

		let primitiveValue = try? JSONEncoder().encode(newValue)
		setPrimitiveValue(primitiveValue, forKey: key)
	}
}

[Note that in this example, Event.Attributes is defined as a struct as in the current swift42 branch, thanks to PR #368.]

With this change, values of EventType can be assigned to the type attribute in the same manner as tranformables are now.

Limitation

This might be too similar to transformables, in that it would be generally impossible to use values of these attributes in predicates. Usually that's not an issue, but with Codables it might be more problematic. In this example, for instance, there's no support for fetching all objects with a given EventType value.

I'd really like to get Codable support in, though, so any comments pro or con are appreciated.

@rentzsch
Copy link
Owner

I can't speak to the Swift devil-in-the-details, but this addition would fit in very well with mogenerator's general thrust of generating obvious code for obvious situations to lubricate Core Data's gears.

@radianttap
Copy link
Contributor

On vacation atm, so not sure am I missing something obvious...

  1. Why the property must be binary..?

  2. Approach with Codable looks like proper solution for what I tried to do with CoreDataRepresentable which works with any attribute type

@atomicbird
Copy link
Collaborator Author

Hi @radianttap. It's binary because that's how the built-in coders work and because binary is a type that Core Data understands. JSONEncoder/JSONDecoder and PropertyListEncoder/PropertyListDecoder each convert to/from binary data. It's a good choice to handle any possible Codable, since they can be more complex than the simple enumeration I used as an example. This also parallels how transformables work, which is the behavior I'm aiming for.

@atomicbird
Copy link
Collaborator Author

Commit 28c0a72 includes an implementation of this.

@atomicbird atomicbird changed the title RFC: Swift Codable Support RFC: Swift Codable Attribute Support Sep 15, 2018
@radianttap
Copy link
Contributor

Like I said previously, I use CoreDataRepresentable protocol to map custom enums and structs into Core Data supported types. That works rather well in the last year or so.

I never used 'binary' type for the attribute thus when you said it can't be used in predicates it rang a pretty big bell. I went through the largest project I'm maintaining to see just how much I use these attributes in predicates. Ends up – a lot. Most use cases for custom types is to map enums which represent attributes used for filtering. Thus I have a lot of predicates using exactly those types

NSPredicate(format: "%K == %d", Attributes.sportCode, sportCode.coredataValue)

Hence is not an option for me to lose this.

(I'll need to go over other proposed changes in 376, 377)

@atomicbird
Copy link
Collaborator Author

Hey @radianttap, I'm giving CoreDataRepresentable a try and it looks really good, but I think maybe we're mixing up two different but related things. For this issue I'm aiming for a general implementation of Codable. I included an example of an enum because it's a simple, easy to understand example. It may have been a bad choice though, because this issue isn't intended to be specific to enum. It seems like CoreDataRepresntable would be a good idea for better support of enums, but the more general case of Codable properties includes things that may not conform to RawRepresentable and are not enums at all. I think the best approach is probably to use the code in 28c0a72 for this issue but then also look at using CoreDataRepresentable for enum-specific improvements. Does that make sense?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants