Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/freshos/arrow
🏹 Parse JSON with style
https://github.com/freshos/arrow
arrow decoding freshos ios json json-parsing mapping micro-framework objectmapper simple swift swiftyjson type-inference unbox
Last synced: about 8 hours ago
JSON representation
🏹 Parse JSON with style
- Host: GitHub
- URL: https://github.com/freshos/arrow
- Owner: freshOS
- License: mit
- Created: 2015-06-07T12:42:50.000Z (over 9 years ago)
- Default Branch: master
- Last Pushed: 2024-09-24T23:09:35.000Z (about 2 months ago)
- Last Synced: 2024-11-06T20:24:29.294Z (8 days ago)
- Topics: arrow, decoding, freshos, ios, json, json-parsing, mapping, micro-framework, objectmapper, simple, swift, swiftyjson, type-inference, unbox
- Language: Swift
- Homepage:
- Size: 21.2 MB
- Stars: 387
- Watchers: 11
- Forks: 27
- Open Issues: 4
-
Metadata Files:
- Readme: README.md
- Funding: .github/FUNDING.yml
- License: LICENSE
- Code of conduct: CODE_OF_CONDUCT.md
Awesome Lists containing this project
README
![Arrow](https://raw.githubusercontent.com/freshOS/Arrow/master/banner.png)
# Arrow
[![Language: Swift 6](https://img.shields.io/badge/language-swift6-f48041.svg?style=flat)](https://developer.apple.com/swift)
![Platform: iOS 8+](https://img.shields.io/badge/platform-iOS%208%2B-blue.svg?style=flat)
[![SPM compatible](https://img.shields.io/badge/SPM-compatible-4BC51D.svg?style=flat)](https://swift.org/package-manager)
[![Build Status](https://app.bitrise.io/app/57b6b1b8959ef398/status.svg?token=WBTcuBRgfLeDB6-A3j7gFA)](https://app.bitrise.io/app/57b6b1b8959ef398)
[![codebeat badge](https://codebeat.co/badges/f037ac0c-b3d9-4132-9fca-64150a908113)](https://codebeat.co/projects/github-com-freshos-arrow)
[![License: MIT](http://img.shields.io/badge/license-MIT-lightgrey.svg?style=flat)](https://github.com/freshOS/Arrow/blob/master/LICENSE)
![Release version](https://img.shields.io/github/release/freshos/Arrow.svg)[Reason](#reason) - [Example](#example) - [Installation](#installation)
```swift
identifier <-- json["id"]
name <-- json["name"]
stats <-- json["stats"]
```Because parsing JSON in Swift is full of **unecessary if lets, obvious casts and nil-checks**
*There must be a better way*## Try it
Arrow is part of [freshOS](https://freshos.github.io/) iOS toolset. Try it in an example App! Download Starter Project
## How
By using a simple arrow operator that takes care of the boilerplate code for us.
Json mapping code becomes **concise** and **maintainable** ❤️## Why use Arrow
- [x] Infers types
- [x] Leaves your models clean
- [x] Handles custom & nested models
- [x] Dot and array syntax
- [x] Pure Swift, Simple & Lightweight## Example
### Swift Model
```swift
struct Profile {
var identifier = 0
var name = ""
var link:NSURL?
var weekday:WeekDay = .Monday
var stats = Stats()
var phoneNumbers = [PhoneNumber]()
}
```
### JSON File
```json
{
"id": 15678,
"name": "John Doe",
"link": "https://apple.com/steve",
"weekdayInt" : 3,
"stats": {
"numberOfFriends": 163,
"numberOfFans": 10987
},
"phoneNumbers": [{
"label": "house",
"number": "9809876545"
}, {
"label": "cell",
"number": "0908070656"
}, {
"label": "work",
"number": "0916570656"
}]
}
```### Before (Chaos)
```swift
var profile = Profile()// Int
if let id = json["id"] as? Int {
profile.identifier = id
}
// String
if let name = json["name"] as? String {
profile.name = name
}
// NSURL
if let link = json["link"] as? String, url = NSURL(string:link) {
profile.link = link
}
// Enum
if let weekdayInt = json["weekdayInt"] as? Int, weekday = WeekDay(rawValue:weekdayInt) {
profile.weekday = weekday
}
// Custom nested object
if let statsJson = json["stats"] as? AnyObject {
if let numberOfFans = statsJson["numberOfFans"] as? Int {
profile.stats.numberOfFans = numberOfFans
}
if let numberOfFriends = statsJson["numberOfFriends"] as? Int {
profile.stats.numberOfFriends = numberOfFriends
}
}
// Array of custom nested object
if let pns = json["phoneNumbers"] as? [AnyObject] {
for pn in pns {
phoneNumbers.append(PhoneNumber(json: pn))
}
}
```### After 🎉🎉🎉
```swift
extension Profile:ArrowParsable {
mutating func deserialize(_ json: JSON) {
identifier <-- json["id"]
link <-- json["link"]
name <-- json["name"]
weekday <-- json["weekdayInt"]
stats <- json["stats"]
phoneNumbers <-- json["phoneNumbers"]
}
}
```### Usage
```swift
let profile = Profile()
profile.deserialize(json)
```## Installation
The Swift Package Manager (SPM) is now the official way to install `Arrow`. The other package managers are now deprecated as of `5.1.2` and won't be supported in future versions.#### Swift Package Manager
`Xcode` > `File` > `Swift Packages` > `Add Package Dependency...` > `Paste` `https://github.com/freshOS/Arrow`
#### Carthage - Deprecated
```
github "freshOS/Arrow"
```
#### CocoaPods - Deprecated
```
target 'MyApp'
pod 'Arrow'
use_frameworks!
```## How Does That Work
Notice earlier we typed :
```swift
stats <-- json["stats"]
```
That's because we created and extension "Stats+Arrow.swift" enabling us to use the Arrow Operator```swift
// Stats+Arrow.swiftimport Foundation
extension Stats:ArrowParsable {
mutating func deserialize(json: JSON) {
numberOfFriends <-- json["numberOfFriends"]
numberOfFans <-- json["numberOfFans"]
}
}
```## Flexible you said
- DO I have to use the <-- for my sub models
- Nope, you could write it like so if you wanted :```swift
stats.numberOfFriends <-- json["stats.numberOfFriends"]
stats.numberOfFans <-- json["stats.numberOfFans"]
```## Date Parsing
### Globally
```swift
// Configure Global Date Parsing with one of those
Arrow.setDateFormat("yyyy-MM-dd'T'HH:mm:ssZZZZZ")
Arrow.setUseTimeIntervalSinceReferenceDate(true)
Arrow.setDateFormatter(aDateFormatter)// Then later dates can be parsed form custom date format or timestamps automatically 🎉
let json:JSON = JSON(["date": "2013-06-07T16:38:40+02:00", "timestamp": 392308720])
date1 <-- json["date"]
date2 <-- json["timestamp"]
```### On a per-key basis
```swift
createdAt <-- json["created_at"]?.dateFormat("yyyy-MM-dd'T'HH:mm:ssZZZZZ")
createdAt <-- json["created_at"]?.dateFormatter(aCustomDateFormatter)
```
Just provide it on a case per case basis ! 🎉## Accessing JSON values
### Nested values
```swift
value <-- json["nested.nested.nested.nestedValue"]
```### Object at index
```swift
value <-- json[12]
```### Combine both
```swift
value <-- json[1]?["someKey"]?[2]?["something.other"]
```### Looping on Array
```swift
if let collection = json.collection {
for jsonEntry in collection {
//Do something
}
}
```## Swift Version
- Swift 2 -> version [**2.0.3**](https://github.com/freshOS/Arrow/releases/tag/2.0.3)
- Swift 3 -> version [**3.0.5**](https://github.com/freshOS/Arrow/releases/tag/3.0.5)
- Swift 4 -> version [**4.0.0**](https://github.com/freshOS/Arrow/releases/tag/4.0.0)
- Swift 4.1 -> version [**4.1.0**](https://github.com/freshOS/Arrow/releases/tag/4.1.0)
- Swift 4.2 -> version [**4.2.0**](https://github.com/freshOS/Arrow/releases/tag/4.2.0)
- Swift 5.0 -> version [**5.0.0**](https://github.com/freshOS/Arrow/releases/tag/5.0.0)
- Swift 5.1 -> version [**5.1.0**](https://github.com/freshOS/Arrow/releases/tag/5.1.0)
- Swift 5.1.3 -> version [**5.1.1**](https://github.com/freshOS/Arrow/releases/tag/5.1.1)
- Swift 5.3 -> version [**6.0.0**](https://github.com/freshOS/Arrow/releases/tag/6.0.0)## Acknowledgements
This wouldn't exist without [YannickDot](https://github.com/YannickDot), [Damien-nd](https://github.com/damien-nd) and [maxkonovalov](https://github.com/maxkonovalov)### Backers
Like the project? Offer coffee or support us with a monthly donation and help us continue our activities :)### Sponsors
Become a sponsor and get your logo on our README on Github with a link to your site :)