flight-school / anycodable Goto Github PK
View Code? Open in Web Editor NEWType-erased wrappers for Encodable, Decodable, and Codable values
Home Page: https://flight.school/books/codable
License: MIT License
Type-erased wrappers for Encodable, Decodable, and Codable values
Home Page: https://flight.school/books/codable
License: MIT License
It looks like AnyCodable version 0.3.0 is not available via CocoaPods.
[!] CocoaPods could not find compatible versions for pod "AnyCodable-FlightSchool":
In Podfile:
AnyCodable-FlightSchool (= 0.3.0)
None of your spec sources contain a spec satisfying the dependency: `AnyCodable-FlightSchool (= 0.3.0)`.
You have either:
* out-of-date source repos which you can update with `pod repo update` or with `pod install --repo-update`.
* mistyped the name or version.
* not added the source repo that hosts the Podspec to your Podfile.
Perhaps this is because the CI build failed? https://github.com/Flight-School/AnyCodable/runs/887025181
Hi,
I would like to use this library as a dependency of my own pod, but I can't, since the .podspec say it is "static". Is there a way to solve this ?
Thanx
-Sylvain
Hey!
This framework looks great! I'd love to pull it into my project, but currently I use Cocoapods. Is that on your roadmap because I'd love to pull it in through that.
Thanks,
Adi
cc: @mattt
Hi, can you pls add the privacy manifest file to Packages.swift as required by Apple for 3rd party SDKs? https://developer.apple.com/support/third-party-SDK-requirements/
According to this requirement, all 3rd party SDKs need to have the privacy manifest file, otherwise apps that include them will be rejected for app submission starting May 1st, 2024.
Thanks.
Would you mind supporting Carthage as well?
This mapping is resulting in the string "null" to be shown in our app as if it is a legal value, and forcing us to do a regex to replace ""null"" with "null" in the resulting JSON before sending it on to our app.
Please add a tag- atlas 0.1.0. So that we can use with SPM
@mattt Welcome back the OSS world and congrats on your book(s). Looking great so far.
I used this approach earlier today to add Codable
support to a LinkedList
with arbitrary values.
Your implementation works great for known Swift types but I'm wondering if its possible to encode/decode any value
that conforms to Codable
?
I gave it a shot and can get it to compile by adding:
public func encode(to encoder: Encoder) throws {
// ...
case let value as Codable:
try container.encode(AnyEncodable(value))
//...
}
Which compiles but when I try to encode (haven't tackled decoding yet) I get a runtime crash because AnyEncodable
ends up being called recursively.
Any ideas would be appreciated :)
Hi @mattt,
I was exploring your project and I have a short question.
Am I assuming incorrectly that the assertion bellow should hold?
let t0: AnyEncodable = ["x": 1]
let t1: AnyEncodable = ["x": 1]
assert(t0 == t1, "These should be equal")
I've read the conformance of AnyEncodable to Equatable and it's not clear to me if my expectations are wrong or there's something missing.
Thanks,
Stefan
Hi,
I have a problem with assigning data to the dictionary that should be encodable. The Data struct inherit from Codable protocol and contains four different variable types.
I am trying to convert this struct to dictionary that will represent some other model. Please find a dummy code below:
struct Data: Codable {
let string: String
let int: Int
let double: Double
let bool: Bool
}
let data: Data
var body: [String : AnyEncodable]? {
[
"string": data.string,
"int": data.int,
"double": data.double,
"bool": data.bool
]
}
When the project is compiling I am getting four errors:
Cannot convert value of type 'String' to expected dictionary value type 'AnyEncodable'
Cannot convert value of type 'Int' to expected dictionary value type 'AnyEncodable'
Cannot convert value of type 'Double' to expected dictionary value type 'AnyEncodable'
Cannot convert value of type 'Bool' to expected dictionary value type 'AnyEncodable'
Is there any simple way to fix it and left the code clean?
I've checked some structures presented by Foundation framework, and tested them.
There are JSON coders and _PropertyList coders in Foundation framework, so I tested them on JSONEncoder and PropertyListEncoder using this simple script.
And results are below:
AnyEncodable<Array<Int>>
Array
AnyEncodable<Calendar>
Calendar
AnyEncodable<CharacterSet>
CharacterSet
AnyEncodable<Data>
Data
AnyEncodable<Date>
Date
AnyEncodable<DateInterval>
DateInterval
AnyEncodable<NSDecimal>
NSDecimal
AnyEncodable<Dictionary<String, Int>>
Dictionary<String, Int>
AnyEncodable<IndexPath>
IndexPath
AnyEncodable<IndexSet>
IndexSet
AnyEncodable<Locale>
Locale
AnyEncodable<Set<Int>>
Set<Int>
AnyEncodable<String>
String
AnyEncodable<TimeZone>
TimeZone
AnyEncodable<URL>
URL
AnyEncodable<UUID>
UUID
According to results, AnyCodable doesn't cover some major types, and it doesn't support PropertyList coders completely.
Dictionary is [String: AnyCodable], JSONSerialization.isValidJSONObject(dict) is false
how to resolve [String: AnyCodable] to JSONString?
This package is not compatible to Swift 4.0 despite there is Package@swift-4.swift due to reasons below:
#if
is in switch
blocks which only case
label valid.canImport
which is implemented since Swift 4.1.We need to decide resolve the problem for compatibility, or resign and change the lowest requirement to Swift 4.1.
I'm using this library in a Framework i'm developing. When exporting my framework as an XCFramework and attempting to use in another project i'm getting this error
Initializer 'init(extendedGraphemeClusterLiteral:)' has different argument labels from those required by protocol 'ExpressibleByStringLiteral' ('init(stringLiteral:)')
var array = [AnyCodable]()
array.append("test")
do{
try JSONSerialization.data(withJSONObject: array, options: .prettyPrinted)
}catch{}
log:
failed: caught "NSInvalidArgumentException", "Invalid type in JSON write (_SwiftValue)"
Is there any way can support JSONSerialization?
Hi, love the work. I wonder why its not init<T: Codable>(_ value: T?)
. Could this catch more errors at compile time?
Installed using Cocoapods and latest version is 0.2.1
I may be missing something fundamental here, but I'm having a difficult time making this library interoperate well with Objective C
Our API handler is in Swift but the object parser is in Objective C and difficult to refactor into Swift for now.
The API handler looks something like this:
public typealias JSONCodable = [String: AnyCodable]
struct MyObjectsResponse: Codable {
let myObjects: [JSONCodable]
enum CodingKeys: String, CodingKey {
case myObjects
}
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
self.myObjects = try container.decode([JSONCodable].self, forKey: .myObjects)
}
}
Now in the objective-c object parser, we have something like this, where data
is a single element from the myObjects
array from the MyObjectsResponse
above, being passed in from swift:
- (instancetype)initWithData:(NSDictionary *)data
{
self = [super init];
if (self) {
self.myItemId = data[@"id"];
NSString *myEnumString = data[@"my_enum"];
if ([myEnumString isEqualToString:@"foo"]) {
self.myEnum = MyEnumFoo;
}
if ([myEnumString isEqualToString:@"bar"]) {
self.myEnum = MyEnumBar;
}
}
return self;
}
This fails with the following exception:
-[__SwiftValue isEqualToString:]: unrecognized selector sent to instance 0x600001965600
In the debugger at the exception breakpoint:
(lldb) po data
{
id = "AnyCodable(\"abc123\")";
"my_enum" = "AnyCodable(\"bar\")";
}
How can I get AnyCodable
to interoperate seamlessly with Objective C types and methods like NSString
and isEqualToString:
?
cc @mattt
Simple question:
@mattt , why something like that cannot be embed on Swift itself? It's super handy.
I bought your book anyway! Thanks for your amazing contributions :)
{
"aps": {
"alert": {
"title": "Test Title",
"subtitle": "Test Subtitle",
"body": "Test body content"
},
"badge": 1,
"sound": "default",
"category": "CUSTOM_UNNotificationCategory",
"interruption-level": "active",
"relevance-score": 0.0
}
}
Decoded this successfully using
JSONDecoder().decode(AnyCodable.self, from: payloadData)
Causing error while
JSONEncoder().encode(_payloadEncodable)
Stacktrace:
* thread #20, queue = 'com.apple.root.default-qos.cooperative', stop reason = EXC_BREAKPOINT (code=1, subcode=0x18a773698)
frame #0: 0x000000018a773698 Foundation`Foundation.__JSONEncoder.encode<τ_0_0 where τ_0_0: Swift.Encodable>(τ_0_0) throws -> () + 292
frame #1: 0x000000018a773ae8 Foundation`protocol witness for Swift.SingleValueEncodingContainer.encode<τ_0_0 where τ_1_0: Swift.Encodable>(τ_1_0) throws -> () in conformance Foundation.__JSONEncoder : Swift.SingleValueEncodingContainer in Foundation + 24
frame #2: 0x0000000198f26588 libswiftCore.dylib`dispatch thunk of Swift.SingleValueEncodingContainer.encode<τ_0_0 where τ_1_0: Swift.Encodable>(τ_1_0) throws -> () + 32
* frame #3: 0x000000010594d3e4 NotifyHub`AnyCodable.encode(encoder=Swift.Encoder @ 0x000000016b261e58, self=Codability.AnyCodable @ 0x000000016b261ae0) at AnyCodable.swift:87:27
frame #4: 0x000000010594de30 NotifyHub`protocol witness for Encodable.encode(to:) in conformance AnyCodable at <compiler-generated>:0
frame #5: 0x0000000198f2489c libswiftCore.dylib`dispatch thunk of Swift.Encodable.encode(to: Swift.Encoder) throws -> () + 32
frame #6: 0x0000000104eaed18
Could you support to set AnyCodable Data into the NSKeyedArchiver?
let complexObject: [AnyCodable] = [["key": "value"], "string2", 1234, nil]
try! NSKeyedArchiver.archivedData(withRootObject: complexObject, requiringSecureCoding: false)
let data = try! NSKeyedUnarchiver.unarchiveTopLevelObjectWithData(complexObject)
.
.
But It didn't work..
At the bottom of this ticket
I’ve successfully exported any cod able along with 6-7 other frameworks but then hit a snag with this library. Are you aware that this actually works with say Bazel uses x frameworks?
UPDATE
https://stackoverflow.com/questions/34159442/x-is-not-a-member-type-of-y
_When using an xcframework that depends on another framework, the X is not a member of type Y will also happen for the Framework it depends on when writing an extensions that wraps, for example, delegate methods
Example: Framework Foo depends on Bar and need to conform to DataDelegate.
class Foo {
...
}
extension Foo : Bar.DataDelegate {
...
}
Everything during compiling will go as planned and the xcframework will be generated. Once you add it to your App along with the dependancy framework Bar and try to build it you will get DataDelegate is not a member of type Bar._
I have a use case where there can be multiple datasources accessed through a strategy pattern. Those strategies return similar objects (json from the network).
Internally they handle the data differently and can't share the same data model, but for the functionality using those API's this doesn't really matter.
I'd like to "proxy" the data behind some protocol which is backed by the JSON data itself. Is there a good pattern for that?
I'll share an example:
protocol EventType {
associatedtype PointType: DataPointType
var timestamp: Int {get}
var value: Double {get}
var data : PointType
}
protocol DataPointType {
var field1: Int {get}
var field2: String {get}
// etc. etc.
}
.... get some data as json ....
let jsonData: AnyCodable = .... get the data from somewhere .... there are many internal types and don't want to craft custom types for each one
// jsonData structure adheres to EventType ....
/// I need a concrete dynamic object conforming to the EventType
// some sort of generic object which implements the EventType protocol
let typedData = Proxy<EventType>(jsonData) // behave like the protocol with the backing jsonData and I don't want to create. a concrete type implementing EventType
Hey @mattt ,
great library 🍺 .
I guess there might be an issue with Xcode 10.2 and Swift5.
I've added within the Package.swift in a super simple way:
// swift-tools-version:5.0
// The swift-tools-version declares the minimum version of Swift required to build this package.
import PackageDescription
let package = Package(
name: "****",
dependencies: [
.package(path: "https://github.com/Flight-School/AnyCodable.git")
]
)
When I run the swift build
command I get:
[1] 67199 illegal hardware instruction swift build
Am I doing something wrong?
Thanks 👍 🚀
This mapping is resulting in the string "null" to be shown in our app as if it is a legal value, and forcing us to do a regex to replace "\"null\"" with "null" in the resulting JSON before sending it on to our app, so in JSON you would see
"value",null,"value"
for example instead of
"value","null","value2"
Could null please be mapped to just null please?
Hi, I want to create generic/dynamic structure and convert AnyCodable to -> Login/Register/X Response Model.
I easily convert Model to AnyCodable like this -> AnyCodable( LoginResponseModel(parameter: "") )
However, if i want to convert AnyCodable to Model, i must follow this steps;
1- Converting Object To Json String
2- Converting Json String To Json Data
3- Converting Json Data To Model
Is there any easier way?
There's a bug (https://bugs.swift.org/browse/SR-14048) in the Xcode build system that can be triggered in rare circumstances if a SwiftPM dependency does not specify its minimum required platform versions. Is that something we could add to the next version? I would open a PR bug I'm not sure which versions of iOS, etc should be supported.
I am getting following error while using library:
Undefined symbols for architecture arm64: "protocol witness table for MyTestFramework.AnyCodable : MyTestFramework._AnyEncodable in MyTestFramework", referenced from: function signature specialization <Arg[0] = Dead> of TestAnyEncodable.ViewController.test() -> () in ViewController.o "(extension in MyTestFramework):MyTestFramework._AnyEncodable.init(floatLiteral: Swift.Double) -> A", referenced from: function signature specialization <Arg[0] = Dead> of TestAnyEncodable.ViewController.test() -> () in ViewController.o "(extension in MyTestFramework):MyTestFramework._AnyEncodable.init(stringLiteral: Swift.String) -> A", referenced from: function signature specialization <Arg[0] = Dead> of TestAnyEncodable.ViewController.test() -> () in ViewController.o "(extension in MyTestFramework):MyTestFramework._AnyEncodable.init(booleanLiteral: Swift.Bool) -> A", referenced from: function signature specialization <Arg[0] = Dead> of TestAnyEncodable.ViewController.test() -> () in ViewController.o "(extension in MyTestFramework):MyTestFramework._AnyEncodable.init(integerLiteral: Swift.Int) -> A", referenced from: function signature specialization <Arg[0] = Dead> of TestAnyEncodable.ViewController.test() -> () in ViewController.o "(extension in MyTestFramework):MyTestFramework._AnyEncodable.init(nilLiteral: ()) -> A", referenced from: function signature specialization <Arg[0] = Dead> of TestAnyEncodable.ViewController.test() -> () in ViewController.o ld: symbol(s) not found for architecture arm64 clang: error: linker command failed with exit code 1 (use -v to see invocation)
Issue is reproducible
You can download the Sample framework and test app where the issue is reproducible from here
I get this error while compiling with Xcode 12.0:
/Pods/AnyCodable-FlightSchool/Sources/AnyCodable/AnyDecodable.swift:66:1: error: extension of internal protocol cannot be declared public
public extension _AnyDecodable {
^~~~~~~
and suggested Xcode fix:
"Remove public"
The error seems to go away if I deintegrate the pods and install them again, but somehow resurfaces again after switching to a different build configuration
Any ideas?
According to Itai Ferber on the Swift forums the implementation used in AnyEncoder
is incorrect because it can't access custom encoding strategies of the type-erased type:
See https://forums.swift.org/t/how-to-encode-objects-of-unknown-type/12253/6
Any ideas? I mean this would only be a problem for custom types right?
I wonder whether there's a way to auto-unpack a [String: AnyDecodable]
in a compiler-assisted way, i.e. if you know that you're dealing with a value in the directory that's, say, an array of int, can't we automatically get this?
I am using Vapor, though I don't believe that matters. I'm trying to pass in an object something that conforms to AnyEncodable
See code:
let dic: [String: AnyEncodable] = [
"number": 1,
"string": "2020-10-01",
"isBool": true,
"post": Post(payload: "")
]
try req.content.encode(dic, as: .urlEncodedForm)
And my post object
struct Post {
let payload: String
}
How do I make Post
conform to AnyEncodable
, so I can pass in an object as a value in my dictionary like such?
Additionally, I've tried:
KLPayload(
token: "",
time: 0,
customer_properties: [
"email": checkout.email
]
)
struct KLPayload: Encodable {
let token: String
let time: Int
let customer_properties: [String: AnyEncodable]
}
And I get Cannot convert value of type 'String' to expected dictionary value type 'AnyEncodable'
currently i have some data. This data is [String: AnyCodable], i just want to get this data's hashvalue. Because the value in this data is dynamic. It can be Number/String/Dictionary/Array/Other Object. How should I do??
//???
extension AnyCodable: Hashable {
}
For frameworks that have BUILD_LIBRARY_FOR_DISTRIBUTION=YES
we see the following warning when pulling in through SPM.
@mattt would you be open to setting this to YES
?
I got an error while trying to submit to the app store with the AnyCodable framework included in my build. I got the error:
ERROR ITMS-90056: "This bundle Payload/MyApp.app/Frameworks/AnyCodable.framework is invalid. The Info.plist file is missing the required key: CFBundleVersion. Please find more information about CFBundleVersion at https://developer.apple.com/documentation/bundleresources/information_property_list/cfbundleversion"
In the AnyCodable_Info.plist I see the following:
CFBundleVersion
$(CURRENT_PROJECT_VERSION)
However, I don't see CURRENT_PROJECT_VERSION defined anywhere in the project.
print(AnyCodable.init(["1"]) == AnyCodable.init(["1"])) // print false
print(AnyCodable.init(["1:2"]) == AnyCodable.init(["1:2"])) // print false
I am using AnyCodable-FlightSchool 0.6.0
Hi,
I have this struct
struct Items : Codable {
let id : Double?
let custom_attributes : [Custom_attributes]?
}
struct Custom_attributes : Codable {
let attribute_code : String?
let value : AnyCodable
}
Now
let model = self.items?. custom_attributes[indexPath.row]
Query: How to read value of mode.value in which datatype is dynamic
I can only read model.attribute_code but how I can read mode.value in which datatype is dynamic
I was upgrading to 0.2.0 and found that the deployment is failing on Linux due to CFNumberType.
I tried adding CoreFoundation import but it still fails with the reason nsnumber cannot be converted to cfnumber.
/tmp/app/.build/checkouts/AnyCodable/Sources/AnyCodable/AnyEncodable.swift:98:16: error: use of unresolved identifier 'CFNumberGetType'
switch CFNumberGetType(nsnumber) {
^~~~~~~~~~~~~~~
Failed to compile droplet: Failed to compile droplet: exit status 1
Hi! I'll try to encode NSNumber with value 1673520803 but in result I see -6493. It seams there is a bug when encoding NSNumber in
case "i": try container.encode(nsnumber.int16Value)
According documentation objCType "I" is An int
https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/ObjCRuntimeGuide/Articles/ocrtTypeEncodings.html
I think in this case should use
case "i": try container.encode(nsnumber.intValue)
See the results of #60.
I'm trying to write a AutoCoding module. But I'm stuck with coding swift-enum.
I can't init the enum from decoder without knowing its exact type...
[!] Authentication token is invalid or unverified. Either verify it with the email that was sent or register a new session.
https://github.com/Flight-School/AnyCodable/actions/runs/1961929014
Hello!
I've noticed that in 0.6.3, the encoding of boolean types has changed in certain circumstances. I've narrowed down the code causing me issues to this:
var options: AnyCodable {
return [
"key": true,
]
}
In < 0.6.3, this would result in the JSON data {"key": true}
. In 0.6.3, it produces {"key": 1}
.
I'm trying to pass an array into a function that accepts a parameter of type AnyCodable
. To do this I need to convert its type to AnyCodable
. The only option to do this is AnyCodable.init(arrayLiteral elements: Any...)
but passing the array into that function of course treats it as an array with one element of type array ([[1,2,3]]
instead of [1,2,3]
).
This is a Swift snafu, supporting variadic parameters without supporting spreading has always been awkward, but the commonly accepted solution is to provide two versions of the function with a variadic parameter so consumers of the API can use it no matter what form their data is in. See: https://forums.swift.org/t/explicit-array-splat-for-variadic-functions/11326 for the generally accepted implementation. Basically the variadic function just collects the elements into an array and passes them into the array version of the function, where the actual function implementation is. The current AnyCodable implementation offers only the variadic version of the function.
The possible downside to adding this is that given the necessary vagueness of types in this library, it is possible someone would want the [[1,2,3]]
behavior, and adding this would make that more difficult, so it may need to be done differently than the standard format.
If anyone knows of a way to turn an array into an AnyCodable other than the code change I've proposed, I'd be happy to hear it.
Please see sample code and its output:
let encoder = JSONEncoder()
let sample = People(name: "neeraj", age: 1)
let data = try! encoder.encode(sample)
let dictionary = try! JSONSerialization.jsonObject(with: data, options: []) as? [String: Any]
let str1 = String.init(data: data, encoding: .utf8)
print(str1!) // print: {"name":"neeraj","age":1}
let d1 = ["data":AnyCodable(dictionary)]
let data1 = try! encoder.encode(d1)
let str2 = String.init(data: data1, encoding: .utf8)
print(str2!) // print: {"data":{"name":"neeraj","age":true}}
struct People:Codable{
var name:String?
var age:Int?
}
{"name":"qwertyui","age":1} {"data":{"name":"qwertyui","age":true}}
We can see age value (1) is converted into bool value (true).
When dictionary contains an NSNumber as 0 or 1, encodable method is mapping to true or false because 0 or 1 is also a boolean for swift.
I think this bug was introduced in #69 because NSNumber condition was removed from the first switch statement.
Example:
var dictionary = [
"int": NSNumber(0)
]
AnyEncodable is returning ["int": false].
This problem only happens from version 0.6.5.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.