The easy to use Swift JSON decoder

Overview

⚠️ DEPRECATED

Unbox is deprecated in favor of Swift’s built-in Codable API and the Codextended project. All current users are highly encouraged to migrate to Codable as soon as possible. Click here for more information and a migration guide.


Unbox

Unbox | Wrap

Travis status CocoaPods Carthage Twitter: @johnsundell

Unbox is an easy to use Swift JSON decoder. Don't spend hours writing JSON decoding code - just unbox it instead!

Unbox is lightweight, non-magical and doesn't require you to subclass, make your JSON conform to a specific schema or completely change the way you write model code. It can be used on any model with ease.

Basic example

Say you have your usual-suspect User model:

struct User {
    let name: String
    let age: Int
}

That can be initialized with the following JSON:

{
    "name": "John",
    "age": 27
}

To decode this JSON into a User instance, all you have to do is make User conform to Unboxable and unbox its properties:

struct User {
    let name: String
    let age: Int
}

extension User: Unboxable {
    init(unboxer: Unboxer) throws {
        self.name = try unboxer.unbox(key: "name")
        self.age = try unboxer.unbox(key: "age")
    }
}

Unbox automatically (or, actually, Swift does) figures out what types your properties are, and decodes them accordingly. Now, we can decode a User like this:

let user: User = try unbox(dictionary: dictionary)

or even:

let user: User = try unbox(data: data)

Advanced example

The first was a pretty simple example, but Unbox can decode even the most complicated JSON structures for you, with both required and optional values, all without any extra code on your part:

struct SpaceShip {
    let type: SpaceShipType
    let weight: Double
    let engine: Engine
    let passengers: [Astronaut]
    let launchLiveStreamURL: URL?
    let lastPilot: Astronaut?
    let lastLaunchDate: Date?
}

extension SpaceShip: Unboxable {
    init(unboxer: Unboxer) throws {
        self.type = try unboxer.unbox(key: "type")
        self.weight = try unboxer.unbox(key: "weight")
        self.engine = try unboxer.unbox(key: "engine")
        self.passengers = try unboxer.unbox(key: "passengers")
        self.launchLiveStreamURL = try? unboxer.unbox(key: "liveStreamURL")
        self.lastPilot = try? unboxer.unbox(key: "lastPilot")

        let dateFormatter = DateFormatter()
        dateFormatter.dateFormat = "YYYY-MM-dd"
        self.lastLaunchDate = try? unboxer.unbox(key: "lastLaunchDate", formatter: dateFormatter)
    }
}

enum SpaceShipType: Int, UnboxableEnum {
    case apollo
    case sputnik
}

struct Engine {
    let manufacturer: String
    let fuelConsumption: Float
}

extension Engine: Unboxable {
    init(unboxer: Unboxer) throws {
        self.manufacturer = try unboxer.unbox(key: "manufacturer")
        self.fuelConsumption = try unboxer.unbox(key: "fuelConsumption")
    }
}

struct Astronaut {
    let name: String
}

extension Astronaut: Unboxable {
    init(unboxer: Unboxer) throws {
        self.name = try unboxer.unbox(key: "name")
    }
}

Error handling

Decoding JSON is inherently a failable operation. The JSON might be in an unexpected format, or a required value might be missing. Thankfully, Unbox takes care of handling both missing and mismatched values gracefully, and uses Swift’s do, try, catch pattern to return errors to you.

You don’t have to deal with multiple error types and perform any checking yourself, and you always have the option to manually exit an unboxing process by throwing. All errors returned by Unbox are of the type UnboxError.

Supported types

Unbox supports decoding all standard JSON types, like:

  • Bool
  • Int, Double, Float
  • String
  • Array
  • Dictionary

It also supports all possible combinations of nested arrays & dictionaries. As you can see in the Advanced example above (where an array of the unboxable Astronaut struct is being unboxed), we can unbox even a complicated data structure with one simple call to unbox().

Finally, it also supports URL through the use of a transformer, and Date by using any DateFormatter.

Transformations

Unbox also supports transformations that let you treat any value or object as if it was a raw JSON type.

It ships with a default String -> URL transformation, which lets you unbox any URL property from a string describing an URL without writing any transformation code.

The same is also true for String -> Int, Double, Float, CGFloat transformations. If you’re unboxing a number type and a string was found, that string will automatically be converted to that number type (if possible).

To enable your own types to be unboxable using a transformation, all you have to do is make your type conform to UnboxableByTransform and implement its protocol methods.

Here’s an example that makes a native Swift UniqueIdentifier type unboxable using a transformation:

struct UniqueIdentifier: UnboxableByTransform {
    typealias UnboxRawValueType = String

    let identifierString: String

    init?(identifierString: String) {
        if let UUID = NSUUID(uuidString: identifierString) {
            self.identifierString = UUID.uuidString
        } else {
            return nil
        }
    }

    static func transform(unboxedValue: String) -> UniqueIdentifier? {
        return UniqueIdentifier(identifierString: unboxedValue)
    }
}

Formatters

If you have values that need to be formatted before use, Unbox supports using formatters to automatically format an unboxed value. Any DateFormatter can out of the box be used to format dates, but you can also add formatters for your own custom types, like this:

enum Currency {
    case usd(Int)
    case sek(Int)
    case pln(Int)
}

struct CurrencyFormatter: UnboxFormatter {
    func format(unboxedValue: String) -> Currency? {
        let components = unboxedValue.components(separatedBy: ":")

        guard components.count == 2 else {
            return nil
        }

        let identifier = components[0]

        guard let value = Int(components[1]) else {
            return nil
        }

        switch identifier {
        case "usd":
            return .usd(value)
        case "sek":
            return .sek(value)
        case "pln":
            return .pln(value)
        default:
            return nil
        }
    }
}

You can now easily unbox any Currency using a given CurrencyFormatter:

struct Product: Unboxable {
    let name: String
    let price: Currency

    init(unboxer: Unboxer) throws {
        name = try unboxer.unbox(key: "name")
        price = try unboxer.unbox(key: "price", formatter: CurrencyFormatter())
    }
}

Supports JSON with both Array and Dictionary root objects

No matter if the root object of the JSON that you want to unbox is an Array or Dictionary - you can use the same Unbox() function and Unbox will return either a single model or an array of models (based on type inference).

Built-in enum support

You can also unbox enums directly, without having to handle the case if they failed to initialize. All you have to do is make any enum type you wish to unbox conform to UnboxableEnum, like this:

enum Profession: Int, UnboxableEnum {
    case developer
    case astronaut
}

Now Profession can be unboxed directly in any model

struct Passenger: Unboxable {
    let profession: Profession

    init(unboxer: Unboxer) throws {
        self.profession = try unboxer.unbox(key: "profession")
    }
}

Contextual objects

Sometimes you need to use data other than what's contained in a dictionary during the decoding process. For this, Unbox has support for strongly typed contextual objects that can be made available in the unboxing initializer.

To use contextual objects, make your type conform to UnboxableWithContext, which can then be unboxed using unbox(dictionary:context) where context is of the type of your choice.

Key path support

You can also use key paths (for both dictionary keys and array indexes) to unbox values from nested JSON structures. Let's expand our User model:

{
    "name": "John",
    "age": 27,
    "activities": {
        "running": {
            "distance": 300
        }
    },
    "devices": [
        "Macbook Pro",
        "iPhone",
        "iPad"
    ]
}
struct User {
    let name: String
    let age: Int
    let runningDistance: Int
    let primaryDeviceName: String
}

extension User: Unboxable {
    init(unboxer: Unboxer) throws {
        self.name = try unboxer.unbox(key: "name")
        self.age = try unboxer.unbox(key: "age")
        self.runningDistance = try unboxer.unbox(keyPath: "activities.running.distance")
        self.primaryDeviceName = try unboxer.unbox(keyPath: "devices.0")
    }
}

You can also use key paths to directly unbox nested JSON structures. This is useful when you only need to extract a specific object (or objects) out of the JSON body.

{
    "company": {
        "name": "Spotify",
    },
    "jobOpenings": [
        {
            "title": "Swift Developer",
            "salary": 120000
        },
        {
            "title": "UI Designer",
            "salary": 100000
        },
    ]
}
struct JobOpening {
    let title: String
    let salary: Int
}

extension JobOpening: Unboxable {
    init(unboxer: Unboxer) throws {
        self.title = try unboxer.unbox(key: "title")
        self.salary = try unboxer.unbox(key: "salary")
    }
}

struct Company {
    let name: String
}

extension Company: Unboxable {
    init(unboxer: Unboxer) throws {
        self.name = try unboxer.unbox(key: "name")
    }
}
let company: Company = try unbox(dictionary: json, atKey: "company")
let jobOpenings: [JobOpening] = try unbox(dictionary: json, atKey: "jobOpenings")
let featuredOpening: JobOpening = try unbox(dictionary: json, atKeyPath: "jobOpenings.0")

Custom unboxing

Sometimes you need more fine grained control over the decoding process, and even though Unbox was designed for simplicity, it also features a powerful custom unboxing API that enables you to take control of how an object gets unboxed. This comes very much in handy when using Unbox together with Core Data, when using dependency injection, or when aggregating data from multiple sources. Here's an example:

let dependency = DependencyManager.loadDependency()

let model: Model = try Unboxer.performCustomUnboxing(dictionary: dictionary, closure: { unboxer in
    var model = Model(dependency: dependency)
    model.name = try? unboxer.unbox(key: "name")
    model.count = try? unboxer.unbox(key: "count")

    return model
})

Installation

CocoaPods:

Add the line pod "Unbox" to your Podfile

Carthage:

Add the line github "johnsundell/unbox" to your Cartfile

Manual:

Clone the repo and drag the file Unbox.swift into your Xcode project.

Swift Package Manager:

Add the line .Package(url: "https://github.com/johnsundell/unbox.git", from: "3.0.0") to your Package.swift

Platform support

Unbox supports all current Apple platforms with the following minimum versions:

  • iOS 8
  • OS X 10.11
  • watchOS 2
  • tvOS 9

Debugging tips

In case your unboxing code isn’t working like you expect it to, here are some tips on how to debug it:

Compile time error: Ambiguous reference to member 'unbox'

Swift cannot find the appropriate overload of the unbox method to call. Make sure you have conformed to any required protocol (such as Unboxable, UnboxableEnum, etc). Note that you can only conform to one Unbox protocol for each type (that is, a type cannot be both an UnboxableEnum and UnboxableByTransform). Also remember that you can only reference concrete types (not Protocol types) in order for Swift to be able to select what overload to use.

unbox() throws

Use the do, try, catch pattern to catch and handle the error:

do {
    let model: Model = try unbox(data: data)
} catch {
    print("An error occurred: \(error)")
}

If you need any help in resolving any problems that you might encounter while using Unbox, feel free to open an Issue.

Community Extensions

Hope you enjoy unboxing your JSON!

For more updates on Unbox, and my other open source projects, follow me on Twitter: @johnsundell

Also make sure to check out Wrap that let’s you easily encode JSON.

Comments
  • Skip invalid data instead of exiting completely.

    Skip invalid data instead of exiting completely.

    Whether using Unbox or UnboxOrThrow, the current implementation nil's the object or returns an empty collection completely if there is a single property on a single object that is invalid. This is necessary when perfect data is needed.

    However, this pull request adds an option to skip invalid data and move on to the next property or object. This way, the consuming developer can prefer to deal with default values instead of an empty collection or nil object.

    Use as:

    let items: [Post] = UnboxOrSkip(data)
    

    Also part of discussion #39.

    opened by basememara 23
  • Skip invalid data instead of exiting completely v2

    Skip invalid data instead of exiting completely v2

    Hello guys!

    I was about to make a pull request exactly the same as #41, so I read the discussion and modified the existing code of @basememara, but following other approach to arrive to the same goal. (I am kind of newbie to this PR staff, I think this is the proper way of modifying an existing PR, otherwise tell me please how to proceed)

    The main change of this PR is done in https://github.com/JohnSundell/Unbox/pull/46/commits/fb9539b096a5f8521ddd2542d4766da2aa4189f4, the other changes are to separate public API from logic, update tests and more.

    Check it please.

    opened by acecilia 16
  • [WIP] Add unboxing to Unboxer

    [WIP] Add unboxing to Unboxer

    This PR adds two unbox overloads that allows to unbox a (optional) dictionary to an Unboxer. It can be seen as an alternative to #92 and a solution to #73, #54.

    Usage example:

    struct Model: Unboxable {
      let requiredInt: Int
      let optionalInt: Int?
    
      init(unboxer: Unboxer) {
        let subUnboxer: Unboxer = unboxer.unbox("required")
        self.requiredInt = subUnboxer.unbox("requiredInt")
    
        let optionalUnboxer: Unboxer? = unboxer.unbox("optional")
        self.optionalInt = optionalUnboxer?.unbox("requiredInt")
      }
    }
    
    let dictionary: UnboxableDictionary = [
      "required": [
        "requiredInt" : "7"
      ],
      "optional": [
        "requiredInt" : "14"
      ]
    ]
    
    let unboxed: Model = try! Unbox(dictionary)
    

    In case the unboxing fails, the error is propagated to the "root" Unboxer with the full key path.

    @JohnSundell, @clayellis Let me know what you think about this approach. If you like it, I'll put together some tests and add documentation to the README.

    opened by nubbel 10
  • Add support for unboxing objects conforming to UnboxableWithContext from a provided key.

    Add support for unboxing objects conforming to UnboxableWithContext from a provided key.

    Add support for unboxing objects conforming to UnboxableWithContext from a provided key. Fixed #128

    This PR would need to go into 1.9 if you want to do a 1.9.1 release. I totally understand if you don't want to do any more pre 2.0 releases, but as we need this, I'm happy to contribute it back if anyone else is interested.

    As there is no branch for 1.9 I couldn't find a way to get Github to direct this to the right commit. If you decide you want to merge this, can you create a branch, ping me and I'll update the PR.

    opened by iainsmith 9
  • Accept other options for Booleans values

    Accept other options for Booleans values

    Hello, We noticed (incorrect but common) boolean values in JSON responses were failing. With these changes this JSON would be accepted: { "testBool": "True", "testBool2": "False", "testBool3": "T", "testBool4": "F", "testBool5": "NO", "testBool6": "YES" }

    opened by frranck 7
  • Make initializer for `UnboxError` public

    Make initializer for `UnboxError` public

    This PR makes the initializer for UnboxError public so that consumers can create their own custom UnboxError if desired.

    This is a quick fix solution to #136, which I imagine will actually suffice for many/most consumers.

    opened by JRG-Developer 6
  • Replaced allow invalid elements to threshold acceptance.

    Replaced allow invalid elements to threshold acceptance.

    Hey @JohnSundell and @acecilia, I hope you guys don't hate me for this :). The recently implemented allowInvalidElements works well. However, it works more like skipInvalidElements. When retrieving an array, if a single property fails then the whole element is skipped and the array continues.

    I am proposing an extra option beyond this, if a single property fails then it should skip that property and allow the element to be added with a nil or empty property.

    To this end, there should be a threshold introduced:

    public enum UnboxThreshold {
        case ThrowError
        case SkipInvalid
        case AllowInvalid
    }
    

    The default is ThrowError. The SkipInvalid skips elements that fail on any property unboxing. The AllowInvalid skips the property of the element but continues to add the rest of the properties for the element.

    You would use it like this:

    let items: [Model] = try? Unbox(data)
    let items: [Model] = try? Unbox(data, threshold: .ThrowError)
    let items: [Model] = try? Unbox(data, threshold: .SkipInvalid)
    let items: [Model] = try? Unbox(data, threshold: .AllowInvalid)
    

    A use case is retrieving blog posts from a WordPress JSON endpoint. If it does not contain a featured image with different sizes, those nodes would be absent in the JSON. In the app though, I'd replace those with placeholder images instead of leaving those posts out of the app completely.

    opened by basememara 6
  • Support nested collections of any type

    Support nested collections of any type

    This change makes Unbox support nested collections (arrays & dictionaries) of any type, rather than being constrained to raw values and transformed types. While this theoretically enables decoding code to be written using invalid JSON types - the extra level of flexibility is worth it.

    Fixes https://github.com/JohnSundell/Unbox/issues/34

    opened by JohnSundell 6
  • Conform Decimal to UnboxableByTransform

    Conform Decimal to UnboxableByTransform

    I'm using Unbox with API heavily loaded with prices represented like price="0.42". Float is not the best choice for such things whereas Decimal is a good fit. I think it can be part of the lib because such case is pretty usual.

    opened by delebedev 5
  • Add ISO8601DateFormatter to date formatters

    Add ISO8601DateFormatter to date formatters

    Proposal: Use it by default when no formatter is specified ?

    Fallback needed ?

    class ISO8601DateFormatter: DateFormatter {
    
        override init() {
            super.init()
    
            self.locale     = Locale(identifier: "en_US_POSIX")
            self.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"
            self.timeZone   = TimeZone(secondsFromGMT: 0)
        }
    
        required init?(coder aDecoder: NSCoder) {
            super.init(coder:aDecoder)
        }
    }
    
    opened by bre7 5
  • Feature: Unbox an Array with a formatter and optionally allowing invalid values

    Feature: Unbox an Array with a formatter and optionally allowing invalid values

    We needed to unbox an array of Strings with a specific date format into an array of NSDates, so we added this functionality to unbox.

    Would appreciate it if you could make a release with this in asap :smiley:

    opened by mikezs 5
  • Implement better path and type reporting in error messages

    Implement better path and type reporting in error messages

    Resolves #165

    This PR improves the error messaging in Unbox to show the full path through the JSON being parsed so that it's obvious where the error is happening.

    This implementation differs slightly from the one proposed in that issue, in that it uses plain dot syntax for array indices instead of subscripting (thing.2.property instead of thing[2].property). It shouldn't be hard to change this if subscripting is desired, but I used dot syntax to stay in sync with unbox's keypath syntax for querying into arrays, which looks like it uses dot syntax.

    I've also added type information to some of the errors, so that if there's a type unboxing error, you can know exactly what types are being used and add the appropriate protocol conformances to make them work if the JSON data is correct.

    Tests have also been added for all the cases I could think of that exercise these new error enhancements.

    I hope this helps! Let me know if there's any issues. I'd love to get this integrated quickly :)

    opened by klundberg 0
  • Add built-in support for Int16 and UInt16

    Add built-in support for Int16 and UInt16

    I needed support for Int16 and noticed you already had built-in support for 32 and 64 bit ints so I thought a couple of extensions for 16 bit ints would fit right in!

    opened by simme 1
  • Add support for enums expressible by string or integer

    Add support for enums expressible by string or integer

    Unbox lacks support for enums that have custom RawRepresentable that is expressible by literals.

    I needed that in my library EnumList, but maybe we could integrate it to Unbox library?

    opened by polac24 0
  • Fix unboxing of key path with same last two components

    Fix unboxing of key path with same last two components

    Hi, I've recently updated Unbox after migrating a project to Swift 3. There's a regression with JSON where last two components of key path are same.

    {
    	"message": {
    		"message": "value"
    	}
    }
    

    I ran performance tests after making changes and performance is pretty much the same.

    opened by mr-v 0
  • Log warnings when invalid elements are found in a collection

    Log warnings when invalid elements are found in a collection

    Hey! We wanted to share a little feature we included in our project that you guys might also like.

    Motivation

    We have a feature in our app that is a list of trips. Some users were reporting that some trips were missing from it. We started researching and found out that the problem was in unboxing an entity of that list.

    When unboxing of an entity fails, we always log an error into our non-fatal log and send it to our API. In this case, we didn't have any error about this.

    Upon further research, we found that the issue was that the array was using allowInvalidElements property so that one item doesn't break the unbox of that collection. In this case, one trip was broken and thus it was not listed.

    We use allowInvalidElements in multiple places in our app. We want to ensure that whenever an element in a list fails, we're informed about it and that's why we implemented this feature.

    How it works

    There's a global logger for all warnings in Unboxer.warningLogger. Devs who are using Unbox in their project can optionally set a logger in this property to start listening to these notifications.

    Internally we added a few calls to this static property from inside the collection mapping methods.

    Further improvement

    We identified other types of warnings that we are interested in logging. Imagine you have the following model:

    struct User: Unboxable {
        let name: String
        let profession: Profession? 
    }
    
    struct Profession: Unboxable {
       let name: String
    }
    

    Now, imagine the API sends you the following:

    { 
    "name": "Nicolas",
    "profession": "Engineer"
    }
    

    When unboxing that JSON, you'll get the following:

    let data = /*json data*/
    let user: User = try unbox(data: data)
    print(user.name) // "Nicolas"
    print(user.profession) // nil
    

    So in this example the API is sending a profession attribute but we're not correctly parsing it. As it is an optional value, unbox process succeeds correctly but something is wrong.

    This could be also logged as a warning to indicate that the key was present but unboxing failed.

    opened by jakunico 1
Releases(4.0.0)
  • 4.0.0(Apr 3, 2019)

    This version moves Unbox to Xcode 10.2 and Swift 5, and with that comes some API changes that will require manual fixes for users adopting this new version.

    Since Swift now automatically flattens optionals returned from throwing functions called with try?, Unbox now uses throwing APIs for all unboxing methods. That means that while in previous versions, you’d unbox an optional property like this:

    struct User: Unboxable {
        var name: String?
        
        init(unboxer: Unboxer) throws {
            name = unboxer.unbox(key: "name")
        }
    }
    

    You’ll now have to prefix such calls with try?:

    struct User: Unboxable {
        var name: String?
        
        init(unboxer: Unboxer) throws {
            name = try? unboxer.unbox(key: "name")
        }
    }
    

    While I realize that the above change brings a slight regression in terms of Unbox’s ease-of-use, it’s necessary in order to make Unbox support the latest Swift tools within a reasonable scope, and also moves Unbox's API to be more inline with modern Swift conventions for throwing methods.

    View build details and download artifacts on buddybuild: Unbox (iOS, Unbox-iOS)

    Source code(tar.gz)
    Source code(zip)
  • 3.1.0(Feb 9, 2019)

  • 3.0.0(Apr 30, 2018)

  • 2.5.0(Jun 5, 2017)

    This version of Unbox adds support for Xcode 9 and Swift 3.2, as well as re-organizes the project to be easier to browse, with separate files for each part of the API. It also enables the tests to be run using the Swift Package Manager.

    Source code(tar.gz)
    Source code(zip)
  • 2.4.0(Feb 17, 2017)

    • You can now unbox a dictionary of models directly using the top-level unbox() function. Works with both Data and UnboxableDictionary. Implemented by @mislavjavor.
    • Decimal is now a first-class number type, and gets automatically converted from other number types and strings. Implemented by @bencallis.
    • You can now unbox Set directly from an array, without any custom transformation code. Implemented by @hartbit.
    Source code(tar.gz)
    Source code(zip)
  • 2.3.1(Feb 1, 2017)

  • 2.3.0(Nov 30, 2016)

    • UnboxPathError is now public, meaning that the detailed error reporting introduced in 2.2 has now been combined with the granularity of earlier versions. UnboxError is again an enum to enable developers to switch on the different cases.
    • Xcode settings have now been updated for 8.1. No more ⚠️.
    • Unbox now has a shiny new logo (kind of shiny anyway, I'm not a designer 😁).
    • When unboxing Data to an array, you can now start unboxing at a certain key path.
    • Unbox can again be used by dragging Unbox.swift directly into a project, instead of using it as a library.
    Source code(tar.gz)
    Source code(zip)
  • 2.2.1(Nov 4, 2016)

  • 2.2.0(Oct 23, 2016)

    This version is focused on increasing Unbox's speed - it's now up to 50% faster compared to the previous version! It also contains error reporting improvements.

    Perfrormance

    • Unboxing collections is now up to 25% faster, because of decreased iteration complexity.
    • Unboxing with key paths is now up to 50% faster, since associated enum values is no longer used.

    The next releases of Unbox will continue to make performance improvements in order to make decoding your JSON even more... eh... swift 😉

    Error reporting

    Unbox now produces a coherent, easy to read error type. UnboxError has been made into a struct instead of an enum, and when printed - it produces easily debuggable information.

    For example, here's how an invalid array element would be reported in Unbox 2.1 or earlier:

    [UnboxError] Invalid value ([1, "Bad value", 3]) for key "array"
    

    And here's how Unbox 2.2 reports the same error:

    [UnboxError] An error occured while unboxing path "model.array": Invalid array element ("Bad value") at index 1. 
    

    This also means you only have to catch one error type (UnboxError) instead of performing complex pattern matching.

    Source code(tar.gz)
    Source code(zip)
  • 2.1.1(Oct 22, 2016)

  • 2.1(Oct 9, 2016)

    • You can now manually create Unboxer instances with either an UnboxableDictionary or Data. This gives you more flexibility and control over the unboxing process (compared to calling unbox(), which makes Unbox create an Unboxer for you).
    • Unbox now correctly handles Int32, Int64, UInt32 and UInt64, even on 32 bit systems.
    Source code(tar.gz)
    Source code(zip)
  • 2.0(Oct 3, 2016)

    Unbox 2.0 brings a new, streamlined API and reworked internals for maximum flexibility & performance.

    ⚠️ This release includes breaking changes for users of Unbox 1.9 or earlier. Please read these notes carefully and upgrade with caution. It's also only compatible with Swift 3 (for Swift 2 compatibility, use the swift2 branch.

    All APIs have been reworked to follow the Swift 3 API naming guidelines

    • Unbox(_) is now unbox(dictionary:), unbox(data:) and unbox(dictionaries:).
    • UnboxableWithContext.ContextType is now UnboxContext.
    • UnboxableByTransform.UnboxRawValueType is now UnboxRawValue.
    • Wherever key paths were supported with the isKeyPath: argument, that has now been replaced with key: and keyPath: overloads. For example unboxer.unbox("company.title", isKeyPath: true) is now unboxer.unbox(keyPath: "company.title").
    • The UnboxError enum now uses non-captailized first letters for its cases.
    • UnboxableKey.transformUnboxedKey() is now transform(unboxedKey:).
    • UnboxableByTransform.transformUnboxedValue() is now transform(unboxedValue:).
    • UnboxFormatter.formatUnboxedValue() is now format(unboxedValue:).
    • Unboxer.performCustomUnboxingWithDictionary() is now performCustomUnboxing(dictionary:)
    • Unboxer.performCustomUnboxingWithArray() is now performCustomUnboxing(array:)
    • Unboxer.performCustomUnboxingWithData() is now performCustomUnboxing(data:)

    Swift native error handling model

    Unboxable and UnboxableWithContext types can now throw from their initializer. This enables you to easily manually exit from an initializer, without having to use any specific APIs on Unboxer.

    This new capability is also used when performing unboxing of values. Now, all required properties are unboxed using try, meaning that as soon as an error as been encountered, the initializer will be exited. This gives us a huge performance boost when dealing with malformed data, or when allowing invalid elements.

    It also means that the unboxFallbackValue() function has been removed, and is no longer required to be implemented by types.

    Finally, since now only one error can be thrown from an unboxing process (since we exit early) - UnboxError and UnboxValueError have been merged, and there's no longer a hasFailed property on Unboxer.

    Any combination of arrays & dictionaries are now directly unboxable

    Previously, Unbox only supported combinations of types and collections that were defined as overloads on Unboxer. Now, thanks to a reworked value resolving system, any combination of types and collections are supported. You can now directly unbox even the most complex data structures with one simple call to unbox().

    Removals

    Some APIs that have been kept around for legacy reasons have been removed in this release.

    • You can no longer send a context when starting the unboxing process for Unboxable types. Instead, use UnboxableWithContext, which gives you strong typing for your contextual object.
    • UnboxableWithFormatter has been removed, since it wasn't needed. Formatting is still 100% supported, through the use of the UnboxFormatter API.
    Source code(tar.gz)
    Source code(zip)
  • 1.9(Jul 26, 2016)

    • You can now Unbox an array of UnboxableByTransform types (thanks @maxsz!)
    • You can now start Unboxing at a certain key/keyPath instead of having to create an intermediate struct (thanks @clayellis!)
    • You can now send a context when unboxing a nested Unboxable type.
    • An array of strings can now be directly unboxed to an array of another raw type (thanks @clayellis!)
    Source code(tar.gz)
    Source code(zip)
  • 1.8(Jul 1, 2016)

    This release contains great new features implemented by the ever growing Unbox community!

    • The custom unboxing API for arrays now supports allowing invalid elements (like the other array-based APIs). Thanks to @PSchu!
    • Nested dictionary support has been heavily improved (they can, for instance, now contain nested arrays in turn, making you able to unbox a deep structure in one go). Thanks @johannth!
    • You can now directly unbox an array with values that will be formatted using a formatter (and optionally allowing invalid elements too!). Thanks to @mikezs!
    Source code(tar.gz)
    Source code(zip)
  • 1.7(Jun 4, 2016)

    Unbox is 1 year old today, let's celebrate with a release 🎉

    • Unbox can now automatically convert most numbers to their expected type. The following types are supported: Ints, Bool, UInt, Int32, Int64, Double, Float.
    • The isKeyPath parameter's default value is now true, meaning that in order to use keypaths, less code needs to be written.
    Source code(tar.gz)
    Source code(zip)
  • 1.6(May 25, 2016)

    • Errors for missing and/or invalid values are now thrown as an array, so that you can see all errors that were encountered at once - reducing debugging times! Thanks @Evertt for implementing this!

    • An UnboxableByTransform's raw type can now be a collection (so you can use it to transform not only raw values, but also collections).

    • Type safety for Arrays & Dictionaries has been improved. They can now only be unboxed if they:

      A) Are explicitly typed as [AnyObject] or [String : AnyObject] B) Contain only raw values (like Int, String, etc) C) Contain nested collections

    Source code(tar.gz)
    Source code(zip)
  • 1.5.2(May 14, 2016)

    This release contains fixes from the evergrowing Unbox community! 🚀

    • Swift Package Manager (SPM) is now supported (thanks @alexaubry!)
    • OS X 10.10 is now supported, just as 10.11 (thanks @bmichotte!)
    • Custom unboxing closures can now throw (thanks @pureblood!)
    Source code(tar.gz)
    Source code(zip)
  • 1.5.1(May 5, 2016)

    • Key path based unboxing now supports retrieving an element from a nested array (thanks @BalestraPatrick for implementing this!)
    • Unbox will now automatically convert strings to numbers if you're expecting a number type and a string was found.
    Source code(tar.gz)
    Source code(zip)
  • 1.5(Apr 28, 2016)

    This release makes improvements to the main Unbox() API, as well as when working with collections.

    • Unbox() and UnboxOrThrow() have been merged into Unbox() - that is now a throwing function. The same behavior as when using UnboxOrThrow() can still be achieved using try? Unbox().
    • When unboxing an array or dictionary containing Unboxable dictionaries, an allowInvalidElements parameter has been added, to optionally (it defaults to false) skip invalid elements that couldn't be unboxed - and instead of failing the process returning a collection with all valid elements.
    • Unbox now supports collections with nested collections inside of them.
    • The project now uses single plist files for tests and for the framework.

    Thanks to @basememara, @acecilia, @Abizern for their work on this release 🎉

    Source code(tar.gz)
    Source code(zip)
  • 1.4(Mar 23, 2016)

    This release mostly includes improvements by the growing Unbox community :rocket:

    • Unbox now uses the latest Swift 2.2 syntax without warnings (thanks @Iyuna).
    • Unboxing of arrays of enum values is now supported (thanks @mikezs).
    • The Custom Unboxing API now supports arrays of dictionaries.
    • Misc small bug fixes & project settings updates.
    Source code(tar.gz)
    Source code(zip)
  • 1.3.1(Feb 7, 2016)

    This release focuses on fixing a bug caused by treating keys with dots as key paths (thanks to @sandalsoft for reporting it and to @mr-v for input on how to fix it).

    A isKeyPath parameter has been added to all Unboxer.unbox() overloads, so that using the key path support now requires the API user to explicity state that intention.

    If you were relying on the implicit treatment of strings with dots as key paths, this release will be a breaking change. The only thing you need to do though is to send isKeyPath: true when unboxing to migrate. For all other users, this is a non-breaking change as the isKeyPath parameter has a default value of false.

    Source code(tar.gz)
    Source code(zip)
  • 1.3(Jan 16, 2016)

    • Added custom unboxing API that enables you to perform custom unboxing logic using a closure.
    • You can now unbox a value from a certain index in a nested array directly.
    • Unbox can now be used in an App extension.
    • Unboxer.dictionary can now be accessed from outside of Unbox.
    • Unboxer.allKeys has been removed in favor of Unboxer.dictionary.
    • Improved compile-time safety for nested Arrays.
    Source code(tar.gz)
    Source code(zip)
  • 1.2.3(Dec 24, 2015)

    This release of Unbox is all about nested dictionaries. You can now transform the keys in a nested dictionary to any Hashable type, with the same single unbox() method call. Unbox also will now also stop you at compile time if you accidentially try to unbox a dictionary of nested models that you have not yet implemented Unboxable for.

    Source code(tar.gz)
    Source code(zip)
  • 1.2.2(Dec 15, 2015)

    Unbox now provides built-in support for NSDate, through the new UnboxableWithFormatter protocol. This enables you to pass any NSDateFormatter when unboxing a String value - and format the unboxed value into an NSDate instance.

    Source code(tar.gz)
    Source code(zip)
  • 1.2.1(Dec 5, 2015)

  • 1.2(Nov 28, 2015)

    • Unbox JSON structures that have an array as their root object.
    • More code reuse between Unbox() and UnboxOrThrow() overloads.
    • Misc code cleanups.
    Source code(tar.gz)
    Source code(zip)
  • 1.1(Nov 19, 2015)

    Potentially breaking changes for users of Unbox 1.0

    Any instead of AnyObject in context & manual fail APIs Enables structs to be used as contextual objects, and when manually failing an unboxing process.

    fallbackValue renamed to unboxFallbackValue To avoid conflicting with other methods when confirming to an Unbox protocol.

    UnboxTransformer removed in favor of static transformation functions on UnboxableByTransform Enables transformations to be written directly on the type that is to be transformed, reducing the amount of code and decreasing complexity.

    Unboxer.requiredContextWithFallbackValue() has been removed A new UnboxableWithContext protocol has been introduced for types that require a contextual object to be unboxed, moving this check to compile time instead of rutime, rendering this method obsolete.

    Other changes

    Unbox enum values directly You no longer have to implement your own enum value decoding. Make your enum types conform to UnboxableEnum and then just unbox the values as normal:

    enum MyEnum: Int, UnboxableEnum {
       case First
       case Second
    
       static func unboxFallbackValue() {
          return .First
       }
    }
    
    struct MyModel: Unboxable {
       let myEnum: MyEnum
    
       init(unboxer: Unboxer) {
          self.myEnum = unboxer.unbox("myEnum")
       }
    }
    

    Allow types to require a contextual object to be unboxed using UnboxableWithContext This new protocol has another initializer (init(unboxer: Unboxer, context: Self.ContextType)) than the default Unboxable protocol, and requires a contextual object of a certain type to be passed into the unboxing process. This is super useful for managing dependencies between different models, or to pass some form of state into the unboxing process.

    Access all keys of the underlying dictionary that's being unboxed Now available through Unboxer.allKeys. Useful for iterations, checking if a key exists, etc.

    Included are also misc documentation fixes.

    Source code(tar.gz)
    Source code(zip)
  • 1.0(Nov 8, 2015)

Owner
John Sundell
I build apps, games and Swift developer tools! Passionate about open source & developer productivity. You can follow me on Twitter @JohnSundell.
John Sundell
PMJSON provides a pure-Swift strongly-typed JSON encoder/decoder

Now Archived and Forked PMJSON will not be maintained in this repository going forward. Please use, create issues on, and make PRs to the fork of PMJS

Postmates Inc. 364 Sep 28, 2022
A enhanced JSON decoder.

JSONDecoderEx A enhanced JSON decoder. Usage struct User: Codable { struct Role: OptionSet, Codable, CustomStringConvertible { let rawValu

SAGESSE-CN 105 Dec 19, 2022
A enhanced JSON decoder.

JSONDecoderEx A enhanced JSON decoder. Usage struct User: Codable { struct Role: OptionSet, Codable, CustomStringConvertible { let rawValu

SAGESSE-CN 105 Dec 19, 2022
SwiftyJSON decoder for Codable

SwiftyJSONDecoder 功能 继承自 JSONDecoder,在标准库源码基础上做了改动,与其主要区别如下 使用 SwiftyJSON 解析数据,使用其类型兼容功能 废弃 nonConformingFloatDecodingStrategy 属性设置,Double 及 Float 默认解

null 2 Aug 10, 2022
Dogtector: dog breed detection app for iOS using YOLOv5 model combined with Metal based object decoder optimized

Dogtector Project description Dogtector is dog breed detection app for iOS using YOLOv5 model combined with Metal based object decoder optimized for u

Bartłomiej Pluta 21 Aug 1, 2022
JSEN (JSON Swift Enum Notation) is a lightweight enum representation of a JSON, written in Swift.

JSEN /ˈdʒeɪsən/ JAY-sən JSEN (JSON Swift Enum Notation) is a lightweight enum representation of a JSON, written in Swift. A JSON, as defined in the EC

Roger Oba 8 Nov 22, 2022
Swift-json - High-performance json parsing in swift

json 0.1.4 swift-json is a pure-Swift JSON parsing library designed for high-per

kelvin 43 Dec 15, 2022
JSON-Practice - JSON Practice With Swift

JSON Practice Vista creada con: Programmatic + AutoLayout Breve explicación de l

Vanesa Giselle Korbenfeld 0 Oct 29, 2021
Ss-json - High-performance json parsing in swift

json 0.1.1 swift-json is a pure-Swift JSON parsing library designed for high-per

kelvin 43 Dec 15, 2022
Swift parser for JSON Feed — a new format similar to RSS and Atom but in JSON.

JSONFeed Swift parser for JSON Feed — a new format similar to RSS and Atom but in JSON. For more information about this new feed format visit: https:/

Toto Tvalavadze 31 Nov 22, 2021
Developed with use Swift language. As a third party library used SDWebImage. JSON parsing using URLSession with TMDB API. This app provide by the Core Data structure.

Capstone Project ?? About Developed with use Swift language. As a third party library used SDWebImage. JSON parsing using URLSession with TMDB API. Ad

Ensar Batuhan Unverdi 9 Aug 22, 2022
HandyJSON is a framework written in Swift which to make converting model objects to and from JSON easy on iOS.

HandyJSON To deal with crash on iOS 14 beta4 please try version 5.0.3-beta HandyJSON is a framework written in Swift which to make converting model ob

Alibaba 4.1k Dec 29, 2022
ObjectMapper is a framework written in Swift that makes it easy for you to convert your model objects to and from JSON.

ObjectMapper is a framework written in Swift that makes it easy for you to convert your model objects (classes and structs) to and from J

Tristan Himmelman 9k Jan 2, 2023
SwiftyJSON makes it easy to deal with JSON data in Swift.

SwiftyJSON SwiftyJSON makes it easy to deal with JSON data in Swift. Platform Build Status *OS Linux Why is the typical JSON handling in Swift NOT goo

SwiftyJSON 21.7k Jan 3, 2023
Magical Data Modeling Framework for JSON - allows rapid creation of smart data models. You can use it in your iOS, macOS, watchOS and tvOS apps.

JSONModel - Magical Data Modeling Framework for JSON JSONModel allows rapid creation of smart data models. You can use it in your iOS, macOS, watchOS

JSONModel 6.9k Dec 8, 2022
Magical Data Modeling Framework for JSON - allows rapid creation of smart data models. You can use it in your iOS, macOS, watchOS and tvOS apps.

JSONModel - Magical Data Modeling Framework for JSON JSONModel allows rapid creation of smart data models. You can use it in your iOS, macOS, watchOS

JSONModel 6.8k Nov 19, 2021
Argo is a library that lets you extract models from JSON or similar structures in a way that's concise, type-safe, and easy to extend

Argo is a library that lets you extract models from JSON or similar structures in a way that's concise, type-safe, and easy to extend. Using Argo

thoughtbot, inc. 3.5k Dec 20, 2022
Easy JSON to NSObject mapping using Cocoa's key value coding (KVC)

#Motis Object Mapping Easy JSON to NSObject mapping using Cocoa's key value coding (KVC) Motis is a user-friendly interface with Key Value Coding that

Mobile Jazz 249 Jun 29, 2022
🌟 Super light and easy automatic JSON to model mapper

magic-mapper-swift ?? Super light and easy automatic JSON to model mapper Finish writing README.md Ability to map NSManagedObject Ability to convert m

Adrian Mateoaea 26 Oct 6, 2019