├── .gitignore ├── .travis.yml ├── Documentation └── README.md ├── LICENSE ├── Podfile ├── Podfile.lock ├── README.md ├── SwiftDailyAPI.podspec ├── SwiftDailyAPI.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ └── contents.xcworkspacedata └── xcshareddata │ └── xcschemes │ ├── SwiftDailyAPI-Mac.xcscheme │ └── SwiftDailyAPI-iOS.xcscheme ├── SwiftDailyAPI.xcworkspace └── contents.xcworkspacedata ├── SwiftDailyAPI ├── Constants.swift ├── DailyAPI.swift ├── Extensions │ ├── NSDate.swift │ ├── NSURL+Decodable.swift │ └── toDecodedTypes.swift ├── Info.plist ├── Models │ ├── Comment.swift │ ├── Daily.swift │ ├── DateIndex.swift │ ├── LatestDaily.swift │ ├── News.swift │ ├── NewsExtra.swift │ ├── NewsMeta.swift │ └── TopNewsMeta.swift ├── SwiftDailyAPI.h └── Types.swift ├── SwiftDailyAPITests ├── DecodingPerformanceTests.swift ├── Info.plist ├── JSON │ ├── JSONFileReader.swift │ ├── comment.json │ ├── comment_with_reply_to.json │ ├── daily_news.json │ ├── daily_news_20150525.json │ ├── latest_daily_news.json │ ├── latest_daily_news_20150527.json │ ├── latest_daily_news_20150802.json │ ├── long_comments_4772308.json │ ├── multipic_news_meta.json │ ├── news.json │ ├── news_4770416.json │ ├── news_4820022.json │ ├── news_4859444.json │ ├── news_extra.json │ ├── news_extra_4770416.json │ ├── news_meta.json │ ├── news_meta_with_a_theme.json │ ├── objectFromFile.swift │ ├── short_comments_4772308.json │ └── top_news_meta.json └── Specs │ ├── DailyAPISpecs.swift │ ├── DateIndexSpec.swift │ ├── ExtensionSpecs.swift │ ├── ProofOfConceptSpecs.swift │ ├── ReadmeCodeSpecs.swift │ ├── RealDataModelDecodingSpecs.swift │ ├── TestDataModelDecodingSpecs.swift │ └── Xcode7PlusSwift2.swift └── bin ├── bump ├── merge ├── new_branch ├── setup └── update /.gitignore: -------------------------------------------------------------------------------- 1 | build/ 2 | *.pbxuser 3 | !default.pbxuser 4 | *.mode1v3 5 | !default.mode1v3 6 | *.mode2v3 7 | !default.mode2v3 8 | *.perspectivev3 9 | !default.perspectivev3 10 | xcuserdata 11 | *.xccheckout 12 | *.xcscmblueprint 13 | *.moved-aside 14 | DerivedData 15 | *.hmap 16 | *.ipa 17 | *.xcuserstate 18 | 19 | Carthage/Build 20 | Carthage/Checkouts 21 | 22 | Pods/ 23 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: objective-c 2 | osx_image: xcode7.2 3 | env: 4 | global: 5 | - LC_CTYPE=en_US.UTF-8 6 | - LANG=en_US.UTF-8 7 | script: 8 | - set -o pipefail 9 | - xcodebuild -version 10 | - xcodebuild -showsdks 11 | 12 | - xcodebuild -workspace SwiftDailyAPI.xcworkspace -scheme "SwiftDailyAPI-iOS" -destination "OS=9.2,name=iPhone 6s Plus" test GCC_INSTRUMENT_PROGRAM_FLOW_ARCS=YES GCC_GENERATE_TEST_COVERAGE_FILES=YES | xcpretty -c 13 | after_success: 14 | - bash <(curl -s https://codecov.io/bash) 15 | -------------------------------------------------------------------------------- /Documentation/README.md: -------------------------------------------------------------------------------- 1 | # SwiftDailyAPI 2 | 3 | [![Build Status](https://travis-ci.org/NicholasTD07/SwiftDailyAPI.svg?branch=develop)](https://travis-ci.org/NicholasTD07/SwiftDailyAPI) 4 | [![codecov.io](https://codecov.io/github/NicholasTD07/SwiftDailyAPI/coverage.svg?branch=develop)](https://codecov.io/github/NicholasTD07/SwiftDailyAPI?branch=develop) 5 | [![CocoaPods Compatible](https://img.shields.io/cocoapods/v/SwiftDailyAPI.svg)](https://img.shields.io/cocoapods/v/SwiftDailyAPI.svg) 6 | [![Carthage Compatible](https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat)](https://github.com/Carthage/Carthage) 7 | 8 | An API framework for ZhiHu's Daily News, built in Swift. It is powering my open 9 | source App [Swift-ZHI](https://github.com/NicholasTD07/Swift-ZHI) which is a 10 | newsreader App built for ZhiHu's Daily News. 11 | 12 | ## Requirement 13 | 14 | * iOS 8.0+ / Mac OS X 10.9+ 15 | * Xcode 7.2 + 16 | 17 | ## Installation 18 | 19 | > **Embedded frameworks require a minimum deployment target of iOS 8 or OS X Mavericks (10.9).** 20 | 21 | ### CocoaPods 22 | 23 | [CocoaPods](http://cocoapods.org) is a dependency manager for Cocoa projects. You can install it with the following command: 24 | 25 | ```bash 26 | $ gem install cocoapods 27 | ``` 28 | 29 | > CocoaPods 0.39.0+ is required to build SwiftDailyAPI 2.0.0+. 30 | 31 | To integrate SwiftDailyAPI into your Xcode project using CocoaPods, specify it in your `Podfile`: 32 | 33 | ```ruby 34 | platform :ios, '8.0' 35 | use_frameworks! 36 | 37 | pod 'SwiftDailyAPI', '~> 2.0' 38 | ``` 39 | 40 | Then, run the following command: 41 | 42 | ```bash 43 | $ pod install 44 | ``` 45 | ### [Carthage] 46 | 47 | [Carthage]: https://github.com/Carthage/Carthage 48 | 49 | Add the following to your Cartfile: 50 | 51 | ``` 52 | github "NicholasTD07/SwiftDailyAPI" ~> 2.0.0 # Swift 2.1 53 | github "NicholasTD07/SwiftDailyAPI" ~> 1.0.0 # Swift 1.2 54 | ``` 55 | 56 | Then run `carthage update`. 57 | 58 | Follow the current instructions in [Carthage's README][carthage-installation] 59 | for up to date installation instructions. 60 | 61 | [carthage-installation]: https://github.com/Carthage/Carthage#adding-frameworks-to-an-application 62 | 63 | ## Usage 64 | 65 | ```swift 66 | import SwiftDailyAPI 67 | 68 | // Setup 69 | var latestDaily: LatestDaily? 70 | var daily: Daily? 71 | var news: News? 72 | var newsExtra: NewsExtra? 73 | var shortComments, longComments: Comments? 74 | 75 | // Given 76 | let newsId = 4772308 77 | let date = NSDate.dateFromString("20150525", format: DailyConstants.dateFormat)! 78 | let api = DailyAPI(userAgent: "SwiftDailyAPI_ReadMe") 79 | 80 | // When 81 | api.latestDaily { latestDailyFromAPI in 82 | latestDaily = latestDailyFromAPI 83 | print(latestDaily?.news) 84 | print(latestDaily?.topNews) 85 | } 86 | 87 | api.daily(forDate: date) { dailyFromAPI in 88 | daily = dailyFromAPI 89 | print(daily?.news) 90 | } 91 | 92 | api.news(newsId) { newsFromAPI in 93 | news = newsFromAPI 94 | print(news?.newsId) 95 | print(news?.title) 96 | } 97 | 98 | api.newsExtra(newsId) { newsExtraFromAPI in 99 | newsExtra = newsExtraFromAPI 100 | print(newsExtra?.popularity) 101 | print(newsExtra?.comments) 102 | } 103 | 104 | api.comments(newsId, shortCommentsHandler: { comments in 105 | shortComments = comments 106 | print(shortComments?.comments) 107 | }, longCommentsHandler: { comments in 108 | longComments = comments 109 | print(longComments?.comments) 110 | }) 111 | 112 | // Then 113 | // expect all vars in `Setup` section to not be nil 114 | // code in `ReadmeCodeSpecs.swift` 115 | ``` 116 | 117 | This code is tested in [ReadmeCodeSpecs.swift](./SwiftDailyAPITests/Specs/ReadmeCodeSpecs.swift). There's also a `Then` part in the spec which expects all the vars in the `Setup` to not be nil. 118 | 119 | ## Frameworks 120 | 121 | * [Alamofire] - Elegant HTTP networking 122 | * [Argo] - Functional JSON parsing 123 | * [Quick] - Testing 124 | * [Nimble] - Matcher 125 | 126 | ## Appendix 127 | 128 | ### How does SwiftDailyAPI support both Carthage and CocoaPods while having 3rd parity dependencies? 129 | 130 | Well, it works like this. Before 2.0.1, I was using Carthage to manage 131 | dependencies so Carthage works for version 2.0.0. However, I switched to 132 | CocoaPods since 2.0.1 because it's easier to setup, more stable from my 133 | experience, also takes less time to install dependencies (Carthage has one extra 134 | build step) and Travis has caching for CocoaPods. 135 | 136 | [Alamofire]: https://github.com/Alamofire/Alamofire 137 | [Argo]: https://github.com/thoughtbot/Argo 138 | [Quick]: https://github.com/Quick/Quick 139 | [Nimble]: https://github.com/Quick/Nimble 140 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | Copyright (c) 2016 Nicholas T. 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 5 | 6 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 7 | 8 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 9 | -------------------------------------------------------------------------------- /Podfile: -------------------------------------------------------------------------------- 1 | platform :ios, '8.0' 2 | use_frameworks! 3 | 4 | pod 'Argo', '~> 2.2.0' 5 | pod 'Alamofire', '~> 3.0' 6 | 7 | def testing_pods 8 | pod 'Quick', '~> 0.8.0' 9 | pod 'Nimble', '~> 3.0.0' 10 | end 11 | 12 | target 'SwiftDailyAPI-iOSTests' do 13 | testing_pods 14 | end 15 | 16 | target 'SwiftDailyAPI-MacTests' do 17 | testing_pods 18 | end 19 | 20 | -------------------------------------------------------------------------------- /Podfile.lock: -------------------------------------------------------------------------------- 1 | PODS: 2 | - Alamofire (3.1.4) 3 | - Argo (2.2.0) 4 | - Nimble (3.0.0) 5 | - Quick (0.8.0) 6 | 7 | DEPENDENCIES: 8 | - Alamofire (~> 3.0) 9 | - Argo (~> 2.2.0) 10 | - Nimble (~> 3.0.0) 11 | - Quick (~> 0.8.0) 12 | 13 | SPEC CHECKSUMS: 14 | Alamofire: fbc829692f351fa1d8a31dd75fd7f7f56fea31fb 15 | Argo: 4f52a32b4cd913c204e5a45f420b3fccad3e3f24 16 | Nimble: 4c353d43735b38b545cbb4cb91504588eb5de926 17 | Quick: 563d0f6ec5f72e394645adb377708639b7dd38ab 18 | 19 | COCOAPODS: 0.39.0 20 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Documentation/README.md -------------------------------------------------------------------------------- /SwiftDailyAPI.podspec: -------------------------------------------------------------------------------- 1 | Pod::Spec.new do |s| 2 | s.name = "SwiftDailyAPI" 3 | s.version = "2.0.1" 4 | s.summary = "A Swift API framework for ZhiHu's Daily News." 5 | s.description = <<-DESC 6 | SwiftDailyAPI provides a simple API for ZhiHu's Daily News in Swift by using Alamofire and Argo for network request and JSON decoding. 7 | DESC 8 | s.homepage = "https://github.com/NicholasTD07/SwiftDailyAPI" 9 | s.license = { :type => "MIT", :file => "LICENSE" } 10 | s.author = { "Nicholas T." => "Nicholas.TD07@gmail.com" } 11 | s.ios.deployment_target = "8.0" 12 | s.source = { :git => "https://github.com/NicholasTD07/SwiftDailyAPI.git", :tag => s.version } 13 | s.source_files = "SwiftDailyAPI/", "SwiftDailyAPI/**/*.{swift}" 14 | s.requires_arc = true 15 | s.dependency 'Argo', '~> 2.2.0' 16 | s.dependency 'Alamofire', '~> 3.0' 17 | end 18 | -------------------------------------------------------------------------------- /SwiftDailyAPI.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 09B788DB0199C4C13AE9CE19 /* Pods.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7054775327EB9C28E7AE9651 /* Pods.framework */; }; 11 | 753053E81B19CAF500B28354 /* Constants.swift in Sources */ = {isa = PBXBuildFile; fileRef = 753053E71B19CAF500B28354 /* Constants.swift */; }; 12 | 753053E91B19CAF500B28354 /* Constants.swift in Sources */ = {isa = PBXBuildFile; fileRef = 753053E71B19CAF500B28354 /* Constants.swift */; }; 13 | 753053ED1B19CE1100B28354 /* news_4770416.json in Resources */ = {isa = PBXBuildFile; fileRef = 753053EA1B19CCEC00B28354 /* news_4770416.json */; }; 14 | 753053EE1B19CE1200B28354 /* news_4770416.json in Resources */ = {isa = PBXBuildFile; fileRef = 753053EA1B19CCEC00B28354 /* news_4770416.json */; }; 15 | 753053F01B1B18CD00B28354 /* NSURL+Decodable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 753053EF1B1B18CD00B28354 /* NSURL+Decodable.swift */; }; 16 | 753053F11B1B18CD00B28354 /* NSURL+Decodable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 753053EF1B1B18CD00B28354 /* NSURL+Decodable.swift */; }; 17 | 75319DCA1B198525002C7AFF /* News.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75319DC91B198525002C7AFF /* News.swift */; }; 18 | 75319DCB1B198525002C7AFF /* News.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75319DC91B198525002C7AFF /* News.swift */; }; 19 | 7532368A1B5629C9002C6BF1 /* news_4859444.json in Resources */ = {isa = PBXBuildFile; fileRef = 753236891B5629C9002C6BF1 /* news_4859444.json */; }; 20 | 7532368B1B5629C9002C6BF1 /* news_4859444.json in Resources */ = {isa = PBXBuildFile; fileRef = 753236891B5629C9002C6BF1 /* news_4859444.json */; }; 21 | 7532368C1B5629CD002C6BF1 /* news_4820022.json in Resources */ = {isa = PBXBuildFile; fileRef = 753236871B562936002C6BF1 /* news_4820022.json */; }; 22 | 7532368D1B5629CE002C6BF1 /* news_4820022.json in Resources */ = {isa = PBXBuildFile; fileRef = 753236871B562936002C6BF1 /* news_4820022.json */; }; 23 | 753B430E1B198BAA00EC8FEA /* TestDataModelDecodingSpecs.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7598B0161B1322C700E55D79 /* TestDataModelDecodingSpecs.swift */; }; 24 | 754196601B2EEBA80072B9B0 /* DateIndex.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7541965F1B2EEBA80072B9B0 /* DateIndex.swift */; }; 25 | 754196611B2EEBA80072B9B0 /* DateIndex.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7541965F1B2EEBA80072B9B0 /* DateIndex.swift */; }; 26 | 754196661B2FFFAB0072B9B0 /* ExtensionSpecs.swift in Sources */ = {isa = PBXBuildFile; fileRef = 754196651B2FFFAB0072B9B0 /* ExtensionSpecs.swift */; }; 27 | 754196671B2FFFAB0072B9B0 /* ExtensionSpecs.swift in Sources */ = {isa = PBXBuildFile; fileRef = 754196651B2FFFAB0072B9B0 /* ExtensionSpecs.swift */; }; 28 | 754235191C4733F300E0A1F9 /* DateIndexSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 754235171C4733DA00E0A1F9 /* DateIndexSpec.swift */; }; 29 | 7542351A1C4733F400E0A1F9 /* DateIndexSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 754235171C4733DA00E0A1F9 /* DateIndexSpec.swift */; }; 30 | 7545261A1C4554F8001940CF /* objectFromFile.swift in Sources */ = {isa = PBXBuildFile; fileRef = 754526181C4554B0001940CF /* objectFromFile.swift */; }; 31 | 7545261B1C4554F9001940CF /* objectFromFile.swift in Sources */ = {isa = PBXBuildFile; fileRef = 754526181C4554B0001940CF /* objectFromFile.swift */; }; 32 | 7547BAAC1B1FC7FA00F4B7A5 /* ReadmeCodeSpecs.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7547BAAB1B1FC7FA00F4B7A5 /* ReadmeCodeSpecs.swift */; }; 33 | 7547BAAD1B1FC7FA00F4B7A5 /* ReadmeCodeSpecs.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7547BAAB1B1FC7FA00F4B7A5 /* ReadmeCodeSpecs.swift */; }; 34 | 75507B171B168946006F41F9 /* daily_news_20150525.json in Resources */ = {isa = PBXBuildFile; fileRef = 75507B161B168946006F41F9 /* daily_news_20150525.json */; }; 35 | 75507B181B168946006F41F9 /* daily_news_20150525.json in Resources */ = {isa = PBXBuildFile; fileRef = 75507B161B168946006F41F9 /* daily_news_20150525.json */; }; 36 | 75522B881B1B1CBD003DA78E /* toDecodedTypes.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75522B871B1B1CBD003DA78E /* toDecodedTypes.swift */; }; 37 | 75522B891B1B1CC4003DA78E /* toDecodedTypes.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75522B871B1B1CBD003DA78E /* toDecodedTypes.swift */; }; 38 | 75522B8B1B1B1F9A003DA78E /* news_extra.json in Resources */ = {isa = PBXBuildFile; fileRef = 75522B8A1B1B1F9A003DA78E /* news_extra.json */; }; 39 | 75522B8C1B1B1F9A003DA78E /* news_extra.json in Resources */ = {isa = PBXBuildFile; fileRef = 75522B8A1B1B1F9A003DA78E /* news_extra.json */; }; 40 | 75522B8E1B1B1FE8003DA78E /* news_extra_4770416.json in Resources */ = {isa = PBXBuildFile; fileRef = 75522B8D1B1B1FE8003DA78E /* news_extra_4770416.json */; }; 41 | 75522B8F1B1B1FE8003DA78E /* news_extra_4770416.json in Resources */ = {isa = PBXBuildFile; fileRef = 75522B8D1B1B1FE8003DA78E /* news_extra_4770416.json */; }; 42 | 75522B911B1B2104003DA78E /* NewsExtra.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75522B901B1B2104003DA78E /* NewsExtra.swift */; }; 43 | 75522B921B1B2104003DA78E /* NewsExtra.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75522B901B1B2104003DA78E /* NewsExtra.swift */; }; 44 | 75522B951B1C188F003DA78E /* comment_with_reply_to.json in Resources */ = {isa = PBXBuildFile; fileRef = 75522B941B1C188F003DA78E /* comment_with_reply_to.json */; }; 45 | 75522B961B1C188F003DA78E /* comment_with_reply_to.json in Resources */ = {isa = PBXBuildFile; fileRef = 75522B941B1C188F003DA78E /* comment_with_reply_to.json */; }; 46 | 75522B971B1C1896003DA78E /* short_comments_4772308.json in Resources */ = {isa = PBXBuildFile; fileRef = 75522B931B1C1726003DA78E /* short_comments_4772308.json */; }; 47 | 75522B981B1C1896003DA78E /* short_comments_4772308.json in Resources */ = {isa = PBXBuildFile; fileRef = 75522B931B1C1726003DA78E /* short_comments_4772308.json */; }; 48 | 75522B9A1B1C1D7B003DA78E /* comment.json in Resources */ = {isa = PBXBuildFile; fileRef = 75522B991B1C1D7B003DA78E /* comment.json */; }; 49 | 75522B9B1B1C1D7B003DA78E /* comment.json in Resources */ = {isa = PBXBuildFile; fileRef = 75522B991B1C1D7B003DA78E /* comment.json */; }; 50 | 75522B9D1B1C1DDF003DA78E /* long_comments_4772308.json in Resources */ = {isa = PBXBuildFile; fileRef = 75522B9C1B1C1DDF003DA78E /* long_comments_4772308.json */; }; 51 | 75522B9E1B1C1DDF003DA78E /* long_comments_4772308.json in Resources */ = {isa = PBXBuildFile; fileRef = 75522B9C1B1C1DDF003DA78E /* long_comments_4772308.json */; }; 52 | 75522BA01B1C1E3C003DA78E /* Comment.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75522B9F1B1C1E3C003DA78E /* Comment.swift */; }; 53 | 75522BA11B1C1E3C003DA78E /* Comment.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75522B9F1B1C1E3C003DA78E /* Comment.swift */; }; 54 | 75522BA41B1C7EA4003DA78E /* RealDataModelDecodingSpecs.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75522BA21B1C7E9E003DA78E /* RealDataModelDecodingSpecs.swift */; }; 55 | 75522BA51B1C7EA6003DA78E /* RealDataModelDecodingSpecs.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75522BA21B1C7E9E003DA78E /* RealDataModelDecodingSpecs.swift */; }; 56 | 75522BA71B1C85D1003DA78E /* DecodingPerformanceTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75522BA61B1C85D1003DA78E /* DecodingPerformanceTests.swift */; }; 57 | 75522BA81B1C85D1003DA78E /* DecodingPerformanceTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75522BA61B1C85D1003DA78E /* DecodingPerformanceTests.swift */; }; 58 | 755F204F1B26C772001AB066 /* Types.swift in Sources */ = {isa = PBXBuildFile; fileRef = 755F204E1B26C772001AB066 /* Types.swift */; }; 59 | 755F20501B26C772001AB066 /* Types.swift in Sources */ = {isa = PBXBuildFile; fileRef = 755F204E1B26C772001AB066 /* Types.swift */; }; 60 | 75656CFD1B465017007D11EA /* Nimble.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 75656CFB1B465017007D11EA /* Nimble.framework */; }; 61 | 75656CFE1B465017007D11EA /* Quick.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 75656CFC1B465017007D11EA /* Quick.framework */; }; 62 | 75656CFF1B465029007D11EA /* Nimble.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 75656CFB1B465017007D11EA /* Nimble.framework */; }; 63 | 75656D001B465029007D11EA /* Quick.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 75656CFC1B465017007D11EA /* Quick.framework */; }; 64 | 756AAE6A1B12A3A40077DFFF /* SwiftDailyAPI.h in Headers */ = {isa = PBXBuildFile; fileRef = 756AAE691B12A3A40077DFFF /* SwiftDailyAPI.h */; settings = {ATTRIBUTES = (Public, ); }; }; 65 | 756AAE701B12A3A40077DFFF /* SwiftDailyAPI.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 756AAE641B12A3A40077DFFF /* SwiftDailyAPI.framework */; }; 66 | 756AAE811B12A3C60077DFFF /* JSONFileReader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 756AAE801B12A3C60077DFFF /* JSONFileReader.swift */; }; 67 | 756AAEA11B12A6700077DFFF /* SwiftDailyAPI.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 756AAE961B12A6700077DFFF /* SwiftDailyAPI.framework */; }; 68 | 756F6F201B28523D006D4E10 /* ProofOfConceptSpecs.swift in Sources */ = {isa = PBXBuildFile; fileRef = 756F6F1F1B28523D006D4E10 /* ProofOfConceptSpecs.swift */; }; 69 | 756F6F211B28523D006D4E10 /* ProofOfConceptSpecs.swift in Sources */ = {isa = PBXBuildFile; fileRef = 756F6F1F1B28523D006D4E10 /* ProofOfConceptSpecs.swift */; }; 70 | 758872F01B6E0109006ECF61 /* latest_daily_news_20150802.json in Resources */ = {isa = PBXBuildFile; fileRef = 758872EF1B6E0109006ECF61 /* latest_daily_news_20150802.json */; }; 71 | 758872F11B6E0109006ECF61 /* latest_daily_news_20150802.json in Resources */ = {isa = PBXBuildFile; fileRef = 758872EF1B6E0109006ECF61 /* latest_daily_news_20150802.json */; }; 72 | 7598B01D1B1328C800E55D79 /* SwiftDailyAPI.h in Headers */ = {isa = PBXBuildFile; fileRef = 756AAE691B12A3A40077DFFF /* SwiftDailyAPI.h */; settings = {ATTRIBUTES = (Public, ); }; }; 73 | 7598B01F1B1329F000E55D79 /* TestDataModelDecodingSpecs.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7598B0161B1322C700E55D79 /* TestDataModelDecodingSpecs.swift */; }; 74 | 7598B02E1B132D6A00E55D79 /* NewsMeta.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7598B02D1B132D6A00E55D79 /* NewsMeta.swift */; }; 75 | 7598B02F1B132D6A00E55D79 /* NewsMeta.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7598B02D1B132D6A00E55D79 /* NewsMeta.swift */; }; 76 | 7598B0331B13399600E55D79 /* news_meta.json in Resources */ = {isa = PBXBuildFile; fileRef = 75D2724C1B1315D5006991D8 /* news_meta.json */; }; 77 | 7598B0341B13399600E55D79 /* top_news_meta.json in Resources */ = {isa = PBXBuildFile; fileRef = 75D272521B131DF0006991D8 /* top_news_meta.json */; }; 78 | 7598B0351B13399600E55D79 /* multipic_news_meta.json in Resources */ = {isa = PBXBuildFile; fileRef = 75D2724E1B131BC6006991D8 /* multipic_news_meta.json */; }; 79 | 7598B0361B13399600E55D79 /* news.json in Resources */ = {isa = PBXBuildFile; fileRef = 75D272501B131CC8006991D8 /* news.json */; }; 80 | 7598B0371B13399E00E55D79 /* news_meta.json in Resources */ = {isa = PBXBuildFile; fileRef = 75D2724C1B1315D5006991D8 /* news_meta.json */; }; 81 | 7598B0381B13399E00E55D79 /* top_news_meta.json in Resources */ = {isa = PBXBuildFile; fileRef = 75D272521B131DF0006991D8 /* top_news_meta.json */; }; 82 | 7598B0391B13399E00E55D79 /* multipic_news_meta.json in Resources */ = {isa = PBXBuildFile; fileRef = 75D2724E1B131BC6006991D8 /* multipic_news_meta.json */; }; 83 | 7598B03A1B13399E00E55D79 /* news.json in Resources */ = {isa = PBXBuildFile; fileRef = 75D272501B131CC8006991D8 /* news.json */; }; 84 | 7598B03C1B1340F000E55D79 /* TopNewsMeta.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7598B03B1B1340F000E55D79 /* TopNewsMeta.swift */; }; 85 | 7598B03D1B1340F000E55D79 /* TopNewsMeta.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7598B03B1B1340F000E55D79 /* TopNewsMeta.swift */; }; 86 | 759B89941C45F2740017F5A4 /* Pods.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 759B89931C45F2740017F5A4 /* Pods.framework */; }; 87 | 75CE7AE31B271DB30001F534 /* Xcode7PlusSwift2.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75CE7AE21B271DB30001F534 /* Xcode7PlusSwift2.swift */; }; 88 | 75E237EF1B13451900F6DE3E /* JSONFileReader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 756AAE801B12A3C60077DFFF /* JSONFileReader.swift */; }; 89 | 75E237F31B1346A100F6DE3E /* latest_daily_news.json in Resources */ = {isa = PBXBuildFile; fileRef = 75E237F01B13468500F6DE3E /* latest_daily_news.json */; }; 90 | 75E237F41B1346A200F6DE3E /* latest_daily_news.json in Resources */ = {isa = PBXBuildFile; fileRef = 75E237F01B13468500F6DE3E /* latest_daily_news.json */; }; 91 | 75E237F61B134D1A00F6DE3E /* Daily.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75E237F51B134D1A00F6DE3E /* Daily.swift */; }; 92 | 75E237F71B134D1A00F6DE3E /* Daily.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75E237F51B134D1A00F6DE3E /* Daily.swift */; }; 93 | 75E237FD1B1351C100F6DE3E /* daily_news.json in Resources */ = {isa = PBXBuildFile; fileRef = 75E237F81B134FA700F6DE3E /* daily_news.json */; }; 94 | 75E237FE1B1351CB00F6DE3E /* daily_news.json in Resources */ = {isa = PBXBuildFile; fileRef = 75E237F81B134FA700F6DE3E /* daily_news.json */; }; 95 | 75E238001B13520D00F6DE3E /* LatestDaily.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75E237FF1B13520D00F6DE3E /* LatestDaily.swift */; }; 96 | 75E238011B13520D00F6DE3E /* LatestDaily.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75E237FF1B13520D00F6DE3E /* LatestDaily.swift */; }; 97 | 75E238031B13569D00F6DE3E /* news_meta_with_a_theme.json in Resources */ = {isa = PBXBuildFile; fileRef = 75E238021B13569D00F6DE3E /* news_meta_with_a_theme.json */; }; 98 | 75E238041B13569D00F6DE3E /* news_meta_with_a_theme.json in Resources */ = {isa = PBXBuildFile; fileRef = 75E238021B13569D00F6DE3E /* news_meta_with_a_theme.json */; }; 99 | 75F919561B15DD8B0053FF42 /* NSDate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75F919551B15DD8B0053FF42 /* NSDate.swift */; }; 100 | 75F919571B15DD8B0053FF42 /* NSDate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75F919551B15DD8B0053FF42 /* NSDate.swift */; }; 101 | 75F9195C1B15F1EB0053FF42 /* DailyAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75F9195B1B15F1EB0053FF42 /* DailyAPI.swift */; }; 102 | 75F9195D1B15F1EB0053FF42 /* DailyAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75F9195B1B15F1EB0053FF42 /* DailyAPI.swift */; }; 103 | 75F919601B15F3DA0053FF42 /* DailyAPISpecs.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75F919581B15F1310053FF42 /* DailyAPISpecs.swift */; }; 104 | 75F919611B15F3DB0053FF42 /* DailyAPISpecs.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75F919581B15F1310053FF42 /* DailyAPISpecs.swift */; }; 105 | 75F919651B1685150053FF42 /* latest_daily_news_20150527.json in Resources */ = {isa = PBXBuildFile; fileRef = 75F919641B1685150053FF42 /* latest_daily_news_20150527.json */; }; 106 | 75F919661B1685150053FF42 /* latest_daily_news_20150527.json in Resources */ = {isa = PBXBuildFile; fileRef = 75F919641B1685150053FF42 /* latest_daily_news_20150527.json */; }; 107 | 9DFBF0CE05237EAFC7E9664B /* Pods_SwiftDailyAPI_iOSTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9A73534CA90ADB0DFA6F0E73 /* Pods_SwiftDailyAPI_iOSTests.framework */; }; 108 | A68D3791F4F1ABE9C187DF0F /* Pods_SwiftDailyAPI_MacTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4B67A6B5F49898106C829AEB /* Pods_SwiftDailyAPI_MacTests.framework */; }; 109 | /* End PBXBuildFile section */ 110 | 111 | /* Begin PBXContainerItemProxy section */ 112 | 756AAE711B12A3A40077DFFF /* PBXContainerItemProxy */ = { 113 | isa = PBXContainerItemProxy; 114 | containerPortal = 756AAE5B1B12A3A40077DFFF /* Project object */; 115 | proxyType = 1; 116 | remoteGlobalIDString = 756AAE631B12A3A40077DFFF; 117 | remoteInfo = SwiftDailyAPI; 118 | }; 119 | 756AAEA21B12A6700077DFFF /* PBXContainerItemProxy */ = { 120 | isa = PBXContainerItemProxy; 121 | containerPortal = 756AAE5B1B12A3A40077DFFF /* Project object */; 122 | proxyType = 1; 123 | remoteGlobalIDString = 756AAE951B12A6700077DFFF; 124 | remoteInfo = "SwiftDailyAPI-Mac"; 125 | }; 126 | /* End PBXContainerItemProxy section */ 127 | 128 | /* Begin PBXCopyFilesBuildPhase section */ 129 | 7598B0251B132B6400E55D79 /* CopyFiles */ = { 130 | isa = PBXCopyFilesBuildPhase; 131 | buildActionMask = 2147483647; 132 | dstPath = ""; 133 | dstSubfolderSpec = 10; 134 | files = ( 135 | ); 136 | runOnlyForDeploymentPostprocessing = 0; 137 | }; 138 | /* End PBXCopyFilesBuildPhase section */ 139 | 140 | /* Begin PBXFileReference section */ 141 | 16B13FB15A04FBD3E207E964 /* Pods-SwiftDailyAPI-MacTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SwiftDailyAPI-MacTests.debug.xcconfig"; path = "Pods/Target Support Files/Pods-SwiftDailyAPI-MacTests/Pods-SwiftDailyAPI-MacTests.debug.xcconfig"; sourceTree = ""; }; 142 | 4262DB75DBB83D66D39E5D16 /* Pods-SwiftDailyAPI-MacTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SwiftDailyAPI-MacTests.release.xcconfig"; path = "Pods/Target Support Files/Pods-SwiftDailyAPI-MacTests/Pods-SwiftDailyAPI-MacTests.release.xcconfig"; sourceTree = ""; }; 143 | 45C36956AE5EE6619794D47C /* Pods.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = Pods.debug.xcconfig; path = "Pods/Target Support Files/Pods/Pods.debug.xcconfig"; sourceTree = ""; }; 144 | 4B67A6B5F49898106C829AEB /* Pods_SwiftDailyAPI_MacTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_SwiftDailyAPI_MacTests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 145 | 7054775327EB9C28E7AE9651 /* Pods.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 146 | 753053E71B19CAF500B28354 /* Constants.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Constants.swift; sourceTree = ""; }; 147 | 753053EA1B19CCEC00B28354 /* news_4770416.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = news_4770416.json; sourceTree = ""; }; 148 | 753053EF1B1B18CD00B28354 /* NSURL+Decodable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "NSURL+Decodable.swift"; sourceTree = ""; }; 149 | 75319DC91B198525002C7AFF /* News.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = News.swift; sourceTree = ""; }; 150 | 753236871B562936002C6BF1 /* news_4820022.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = news_4820022.json; sourceTree = ""; }; 151 | 753236891B5629C9002C6BF1 /* news_4859444.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = news_4859444.json; sourceTree = ""; }; 152 | 7541965F1B2EEBA80072B9B0 /* DateIndex.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DateIndex.swift; sourceTree = ""; }; 153 | 754196651B2FFFAB0072B9B0 /* ExtensionSpecs.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ExtensionSpecs.swift; sourceTree = ""; }; 154 | 754235171C4733DA00E0A1F9 /* DateIndexSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DateIndexSpec.swift; sourceTree = ""; }; 155 | 754526181C4554B0001940CF /* objectFromFile.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = objectFromFile.swift; sourceTree = ""; }; 156 | 7547BAAB1B1FC7FA00F4B7A5 /* ReadmeCodeSpecs.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReadmeCodeSpecs.swift; sourceTree = ""; }; 157 | 75507B161B168946006F41F9 /* daily_news_20150525.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = daily_news_20150525.json; sourceTree = ""; }; 158 | 75522B871B1B1CBD003DA78E /* toDecodedTypes.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = toDecodedTypes.swift; sourceTree = ""; }; 159 | 75522B8A1B1B1F9A003DA78E /* news_extra.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = news_extra.json; sourceTree = ""; }; 160 | 75522B8D1B1B1FE8003DA78E /* news_extra_4770416.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = news_extra_4770416.json; sourceTree = ""; }; 161 | 75522B901B1B2104003DA78E /* NewsExtra.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NewsExtra.swift; sourceTree = ""; }; 162 | 75522B931B1C1726003DA78E /* short_comments_4772308.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = short_comments_4772308.json; sourceTree = ""; }; 163 | 75522B941B1C188F003DA78E /* comment_with_reply_to.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = comment_with_reply_to.json; sourceTree = ""; }; 164 | 75522B991B1C1D7B003DA78E /* comment.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = comment.json; sourceTree = ""; }; 165 | 75522B9C1B1C1DDF003DA78E /* long_comments_4772308.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = long_comments_4772308.json; sourceTree = ""; }; 166 | 75522B9F1B1C1E3C003DA78E /* Comment.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Comment.swift; sourceTree = ""; }; 167 | 75522BA21B1C7E9E003DA78E /* RealDataModelDecodingSpecs.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RealDataModelDecodingSpecs.swift; sourceTree = ""; }; 168 | 75522BA61B1C85D1003DA78E /* DecodingPerformanceTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DecodingPerformanceTests.swift; sourceTree = ""; }; 169 | 755F204E1B26C772001AB066 /* Types.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Types.swift; sourceTree = ""; }; 170 | 75656CF61B464F86007D11EA /* Box.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Box.framework; path = ../../Build/iOS/Box.framework; sourceTree = ""; }; 171 | 75656CF91B464FB1007D11EA /* Box.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Box.framework; path = ../../Build/Mac/Box.framework; sourceTree = ""; }; 172 | 75656CFB1B465017007D11EA /* Nimble.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Nimble.framework; path = ../../Build/Mac/Nimble.framework; sourceTree = ""; }; 173 | 75656CFC1B465017007D11EA /* Quick.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Quick.framework; path = ../../Build/Mac/Quick.framework; sourceTree = ""; }; 174 | 756AAE641B12A3A40077DFFF /* SwiftDailyAPI.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SwiftDailyAPI.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 175 | 756AAE681B12A3A40077DFFF /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 176 | 756AAE691B12A3A40077DFFF /* SwiftDailyAPI.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SwiftDailyAPI.h; sourceTree = ""; }; 177 | 756AAE6F1B12A3A40077DFFF /* SwiftDailyAPI-iOSTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "SwiftDailyAPI-iOSTests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; 178 | 756AAE751B12A3A40077DFFF /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 179 | 756AAE801B12A3C60077DFFF /* JSONFileReader.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = JSONFileReader.swift; sourceTree = ""; }; 180 | 756AAE8B1B12A5530077DFFF /* Argo.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Argo.framework; path = Carthage/Build/iOS/Argo.framework; sourceTree = ""; }; 181 | 756AAE8D1B12A5740077DFFF /* Runes.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Runes.framework; path = Carthage/Build/iOS/Runes.framework; sourceTree = ""; }; 182 | 756AAE961B12A6700077DFFF /* SwiftDailyAPI.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SwiftDailyAPI.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 183 | 756AAEA01B12A6700077DFFF /* SwiftDailyAPI-MacTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "SwiftDailyAPI-MacTests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; 184 | 756F6F1F1B28523D006D4E10 /* ProofOfConceptSpecs.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ProofOfConceptSpecs.swift; sourceTree = ""; }; 185 | 758872EF1B6E0109006ECF61 /* latest_daily_news_20150802.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = latest_daily_news_20150802.json; sourceTree = ""; }; 186 | 7598B0161B1322C700E55D79 /* TestDataModelDecodingSpecs.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TestDataModelDecodingSpecs.swift; sourceTree = ""; }; 187 | 7598B02D1B132D6A00E55D79 /* NewsMeta.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NewsMeta.swift; sourceTree = ""; }; 188 | 7598B03B1B1340F000E55D79 /* TopNewsMeta.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TopNewsMeta.swift; sourceTree = ""; }; 189 | 7598D26B1B169F280096217F /* README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = ""; }; 190 | 759B89931C45F2740017F5A4 /* Pods.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Pods.framework; path = "../../Library/Developer/Xcode/DerivedData/SwiftDailyAPI-dhxscwezcszizoagoeohechxlzpe/Build/Products/Debug-iphonesimulator/Pods.framework"; sourceTree = ""; }; 191 | 75CE7AE21B271DB30001F534 /* Xcode7PlusSwift2.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Xcode7PlusSwift2.swift; sourceTree = ""; }; 192 | 75D256991B12AF87005F6645 /* Argo.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Argo.framework; path = Carthage/Build/Mac/Argo.framework; sourceTree = ""; }; 193 | 75D2569B1B12AF90005F6645 /* Runes.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Runes.framework; path = Carthage/Build/Mac/Runes.framework; sourceTree = ""; }; 194 | 75D2724C1B1315D5006991D8 /* news_meta.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = news_meta.json; sourceTree = ""; }; 195 | 75D2724E1B131BC6006991D8 /* multipic_news_meta.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = multipic_news_meta.json; sourceTree = ""; }; 196 | 75D272501B131CC8006991D8 /* news.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = news.json; sourceTree = ""; }; 197 | 75D272521B131DF0006991D8 /* top_news_meta.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = top_news_meta.json; sourceTree = ""; }; 198 | 75E237F01B13468500F6DE3E /* latest_daily_news.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = latest_daily_news.json; sourceTree = ""; }; 199 | 75E237F51B134D1A00F6DE3E /* Daily.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Daily.swift; sourceTree = ""; }; 200 | 75E237F81B134FA700F6DE3E /* daily_news.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = daily_news.json; sourceTree = ""; }; 201 | 75E237FF1B13520D00F6DE3E /* LatestDaily.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LatestDaily.swift; sourceTree = ""; }; 202 | 75E238021B13569D00F6DE3E /* news_meta_with_a_theme.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = news_meta_with_a_theme.json; sourceTree = ""; }; 203 | 75E238141B14260400F6DE3E /* Alamofire.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Alamofire.framework; path = Carthage/Build/iOS/Alamofire.framework; sourceTree = ""; }; 204 | 75E238161B14260F00F6DE3E /* Alamofire.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Alamofire.framework; path = Carthage/Build/Mac/Alamofire.framework; sourceTree = ""; }; 205 | 75F919551B15DD8B0053FF42 /* NSDate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NSDate.swift; sourceTree = ""; }; 206 | 75F919581B15F1310053FF42 /* DailyAPISpecs.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DailyAPISpecs.swift; sourceTree = ""; }; 207 | 75F9195B1B15F1EB0053FF42 /* DailyAPI.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DailyAPI.swift; sourceTree = ""; }; 208 | 75F919641B1685150053FF42 /* latest_daily_news_20150527.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = latest_daily_news_20150527.json; sourceTree = ""; }; 209 | 921F1F72C19F840E93CEC4FE /* Pods-SwiftDailyAPI-iOSTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SwiftDailyAPI-iOSTests.debug.xcconfig"; path = "Pods/Target Support Files/Pods-SwiftDailyAPI-iOSTests/Pods-SwiftDailyAPI-iOSTests.debug.xcconfig"; sourceTree = ""; }; 210 | 9A73534CA90ADB0DFA6F0E73 /* Pods_SwiftDailyAPI_iOSTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_SwiftDailyAPI_iOSTests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 211 | D468C75F82E16ED3BAFD0AC9 /* Pods.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = Pods.release.xcconfig; path = "Pods/Target Support Files/Pods/Pods.release.xcconfig"; sourceTree = ""; }; 212 | DD94845195E8D1FFF9D31B4F /* Pods-SwiftDailyAPI-iOSTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SwiftDailyAPI-iOSTests.release.xcconfig"; path = "Pods/Target Support Files/Pods-SwiftDailyAPI-iOSTests/Pods-SwiftDailyAPI-iOSTests.release.xcconfig"; sourceTree = ""; }; 213 | /* End PBXFileReference section */ 214 | 215 | /* Begin PBXFrameworksBuildPhase section */ 216 | 756AAE601B12A3A40077DFFF /* Frameworks */ = { 217 | isa = PBXFrameworksBuildPhase; 218 | buildActionMask = 2147483647; 219 | files = ( 220 | 09B788DB0199C4C13AE9CE19 /* Pods.framework in Frameworks */, 221 | ); 222 | runOnlyForDeploymentPostprocessing = 0; 223 | }; 224 | 756AAE6C1B12A3A40077DFFF /* Frameworks */ = { 225 | isa = PBXFrameworksBuildPhase; 226 | buildActionMask = 2147483647; 227 | files = ( 228 | 75656CFD1B465017007D11EA /* Nimble.framework in Frameworks */, 229 | 75656CFE1B465017007D11EA /* Quick.framework in Frameworks */, 230 | 756AAE701B12A3A40077DFFF /* SwiftDailyAPI.framework in Frameworks */, 231 | 9DFBF0CE05237EAFC7E9664B /* Pods_SwiftDailyAPI_iOSTests.framework in Frameworks */, 232 | ); 233 | runOnlyForDeploymentPostprocessing = 0; 234 | }; 235 | 756AAE921B12A6700077DFFF /* Frameworks */ = { 236 | isa = PBXFrameworksBuildPhase; 237 | buildActionMask = 2147483647; 238 | files = ( 239 | 759B89941C45F2740017F5A4 /* Pods.framework in Frameworks */, 240 | ); 241 | runOnlyForDeploymentPostprocessing = 0; 242 | }; 243 | 756AAE9D1B12A6700077DFFF /* Frameworks */ = { 244 | isa = PBXFrameworksBuildPhase; 245 | buildActionMask = 2147483647; 246 | files = ( 247 | 75656CFF1B465029007D11EA /* Nimble.framework in Frameworks */, 248 | 75656D001B465029007D11EA /* Quick.framework in Frameworks */, 249 | 756AAEA11B12A6700077DFFF /* SwiftDailyAPI.framework in Frameworks */, 250 | A68D3791F4F1ABE9C187DF0F /* Pods_SwiftDailyAPI_MacTests.framework in Frameworks */, 251 | ); 252 | runOnlyForDeploymentPostprocessing = 0; 253 | }; 254 | /* End PBXFrameworksBuildPhase section */ 255 | 256 | /* Begin PBXGroup section */ 257 | 754B26DA1B16878100B72C45 /* Test Data */ = { 258 | isa = PBXGroup; 259 | children = ( 260 | 75522B991B1C1D7B003DA78E /* comment.json */, 261 | 75522B941B1C188F003DA78E /* comment_with_reply_to.json */, 262 | 75D2724C1B1315D5006991D8 /* news_meta.json */, 263 | 75D272521B131DF0006991D8 /* top_news_meta.json */, 264 | 75D2724E1B131BC6006991D8 /* multipic_news_meta.json */, 265 | 75D272501B131CC8006991D8 /* news.json */, 266 | 75E237F01B13468500F6DE3E /* latest_daily_news.json */, 267 | 75E237F81B134FA700F6DE3E /* daily_news.json */, 268 | 75E238021B13569D00F6DE3E /* news_meta_with_a_theme.json */, 269 | 75522B8A1B1B1F9A003DA78E /* news_extra.json */, 270 | ); 271 | name = "Test Data"; 272 | sourceTree = ""; 273 | }; 274 | 754B26DB1B16878D00B72C45 /* Real Data */ = { 275 | isa = PBXGroup; 276 | children = ( 277 | 758872EF1B6E0109006ECF61 /* latest_daily_news_20150802.json */, 278 | 75F919641B1685150053FF42 /* latest_daily_news_20150527.json */, 279 | 75522B931B1C1726003DA78E /* short_comments_4772308.json */, 280 | 75522B9C1B1C1DDF003DA78E /* long_comments_4772308.json */, 281 | 75507B161B168946006F41F9 /* daily_news_20150525.json */, 282 | 753053EA1B19CCEC00B28354 /* news_4770416.json */, 283 | 75522B8D1B1B1FE8003DA78E /* news_extra_4770416.json */, 284 | 753236871B562936002C6BF1 /* news_4820022.json */, 285 | 753236891B5629C9002C6BF1 /* news_4859444.json */, 286 | ); 287 | name = "Real Data"; 288 | sourceTree = ""; 289 | }; 290 | 756AAE5A1B12A3A40077DFFF = { 291 | isa = PBXGroup; 292 | children = ( 293 | 75F919521B15B1000053FF42 /* Documentation */, 294 | 756AAE661B12A3A40077DFFF /* SwiftDailyAPI */, 295 | 756AAE731B12A3A40077DFFF /* SwiftDailyAPITests */, 296 | 756AAE651B12A3A40077DFFF /* Products */, 297 | 756AAE901B12A5F80077DFFF /* Frameworks */, 298 | BAD850C27618AF3DFC85797E /* Pods */, 299 | ); 300 | indentWidth = 2; 301 | sourceTree = ""; 302 | tabWidth = 2; 303 | }; 304 | 756AAE651B12A3A40077DFFF /* Products */ = { 305 | isa = PBXGroup; 306 | children = ( 307 | 756AAE641B12A3A40077DFFF /* SwiftDailyAPI.framework */, 308 | 756AAE6F1B12A3A40077DFFF /* SwiftDailyAPI-iOSTests.xctest */, 309 | 756AAE961B12A6700077DFFF /* SwiftDailyAPI.framework */, 310 | 756AAEA01B12A6700077DFFF /* SwiftDailyAPI-MacTests.xctest */, 311 | ); 312 | name = Products; 313 | sourceTree = ""; 314 | }; 315 | 756AAE661B12A3A40077DFFF /* SwiftDailyAPI */ = { 316 | isa = PBXGroup; 317 | children = ( 318 | 755F204E1B26C772001AB066 /* Types.swift */, 319 | 75F9195B1B15F1EB0053FF42 /* DailyAPI.swift */, 320 | 7598B0181B13238C00E55D79 /* Models */, 321 | 75F919541B15DD300053FF42 /* Extensions */, 322 | 756AAE671B12A3A40077DFFF /* Supporting Files */, 323 | ); 324 | path = SwiftDailyAPI; 325 | sourceTree = ""; 326 | }; 327 | 756AAE671B12A3A40077DFFF /* Supporting Files */ = { 328 | isa = PBXGroup; 329 | children = ( 330 | 756AAE691B12A3A40077DFFF /* SwiftDailyAPI.h */, 331 | 756AAE681B12A3A40077DFFF /* Info.plist */, 332 | 753053E71B19CAF500B28354 /* Constants.swift */, 333 | ); 334 | name = "Supporting Files"; 335 | sourceTree = ""; 336 | }; 337 | 756AAE731B12A3A40077DFFF /* SwiftDailyAPITests */ = { 338 | isa = PBXGroup; 339 | children = ( 340 | 75522BA61B1C85D1003DA78E /* DecodingPerformanceTests.swift */, 341 | 756AAE871B12A4800077DFFF /* Specs */, 342 | 756AAE821B12A3D40077DFFF /* JSON */, 343 | 756AAE741B12A3A40077DFFF /* Supporting Files */, 344 | ); 345 | path = SwiftDailyAPITests; 346 | sourceTree = ""; 347 | }; 348 | 756AAE741B12A3A40077DFFF /* Supporting Files */ = { 349 | isa = PBXGroup; 350 | children = ( 351 | 756AAE751B12A3A40077DFFF /* Info.plist */, 352 | ); 353 | name = "Supporting Files"; 354 | sourceTree = ""; 355 | }; 356 | 756AAE821B12A3D40077DFFF /* JSON */ = { 357 | isa = PBXGroup; 358 | children = ( 359 | 754526181C4554B0001940CF /* objectFromFile.swift */, 360 | 756AAE801B12A3C60077DFFF /* JSONFileReader.swift */, 361 | 754B26DA1B16878100B72C45 /* Test Data */, 362 | 754B26DB1B16878D00B72C45 /* Real Data */, 363 | ); 364 | path = JSON; 365 | sourceTree = ""; 366 | }; 367 | 756AAE871B12A4800077DFFF /* Specs */ = { 368 | isa = PBXGroup; 369 | children = ( 370 | 7547BAAB1B1FC7FA00F4B7A5 /* ReadmeCodeSpecs.swift */, 371 | 75F919581B15F1310053FF42 /* DailyAPISpecs.swift */, 372 | 7598B0161B1322C700E55D79 /* TestDataModelDecodingSpecs.swift */, 373 | 75522BA21B1C7E9E003DA78E /* RealDataModelDecodingSpecs.swift */, 374 | 75CE7AE21B271DB30001F534 /* Xcode7PlusSwift2.swift */, 375 | 756F6F1F1B28523D006D4E10 /* ProofOfConceptSpecs.swift */, 376 | 754196651B2FFFAB0072B9B0 /* ExtensionSpecs.swift */, 377 | 754235171C4733DA00E0A1F9 /* DateIndexSpec.swift */, 378 | ); 379 | path = Specs; 380 | sourceTree = ""; 381 | }; 382 | 756AAE8F1B12A5F20077DFFF /* iOS */ = { 383 | isa = PBXGroup; 384 | children = ( 385 | 75656CF61B464F86007D11EA /* Box.framework */, 386 | 75E238141B14260400F6DE3E /* Alamofire.framework */, 387 | 756AAE8D1B12A5740077DFFF /* Runes.framework */, 388 | 756AAE8B1B12A5530077DFFF /* Argo.framework */, 389 | ); 390 | name = iOS; 391 | sourceTree = ""; 392 | }; 393 | 756AAE901B12A5F80077DFFF /* Frameworks */ = { 394 | isa = PBXGroup; 395 | children = ( 396 | 759B89931C45F2740017F5A4 /* Pods.framework */, 397 | 75656CFB1B465017007D11EA /* Nimble.framework */, 398 | 75656CFC1B465017007D11EA /* Quick.framework */, 399 | 756AAE8F1B12A5F20077DFFF /* iOS */, 400 | 75D2569D1B12AFAD005F6645 /* Mac */, 401 | 7054775327EB9C28E7AE9651 /* Pods.framework */, 402 | 4B67A6B5F49898106C829AEB /* Pods_SwiftDailyAPI_MacTests.framework */, 403 | 9A73534CA90ADB0DFA6F0E73 /* Pods_SwiftDailyAPI_iOSTests.framework */, 404 | ); 405 | name = Frameworks; 406 | sourceTree = ""; 407 | }; 408 | 7598B0181B13238C00E55D79 /* Models */ = { 409 | isa = PBXGroup; 410 | children = ( 411 | 7541965F1B2EEBA80072B9B0 /* DateIndex.swift */, 412 | 75E4D8581B2EE5B200D27464 /* Daily */, 413 | ); 414 | path = Models; 415 | sourceTree = ""; 416 | }; 417 | 75D2569D1B12AFAD005F6645 /* Mac */ = { 418 | isa = PBXGroup; 419 | children = ( 420 | 75656CF91B464FB1007D11EA /* Box.framework */, 421 | 75E238161B14260F00F6DE3E /* Alamofire.framework */, 422 | 75D2569B1B12AF90005F6645 /* Runes.framework */, 423 | 75D256991B12AF87005F6645 /* Argo.framework */, 424 | ); 425 | name = Mac; 426 | sourceTree = ""; 427 | }; 428 | 75E4D8581B2EE5B200D27464 /* Daily */ = { 429 | isa = PBXGroup; 430 | children = ( 431 | 7598B02D1B132D6A00E55D79 /* NewsMeta.swift */, 432 | 7598B03B1B1340F000E55D79 /* TopNewsMeta.swift */, 433 | 75E237F51B134D1A00F6DE3E /* Daily.swift */, 434 | 75E237FF1B13520D00F6DE3E /* LatestDaily.swift */, 435 | 75319DC91B198525002C7AFF /* News.swift */, 436 | 75522B901B1B2104003DA78E /* NewsExtra.swift */, 437 | 75522B9F1B1C1E3C003DA78E /* Comment.swift */, 438 | ); 439 | name = Daily; 440 | sourceTree = ""; 441 | }; 442 | 75F919521B15B1000053FF42 /* Documentation */ = { 443 | isa = PBXGroup; 444 | children = ( 445 | 7598D26B1B169F280096217F /* README.md */, 446 | ); 447 | path = Documentation; 448 | sourceTree = ""; 449 | }; 450 | 75F919541B15DD300053FF42 /* Extensions */ = { 451 | isa = PBXGroup; 452 | children = ( 453 | 75F919551B15DD8B0053FF42 /* NSDate.swift */, 454 | 753053EF1B1B18CD00B28354 /* NSURL+Decodable.swift */, 455 | 75522B871B1B1CBD003DA78E /* toDecodedTypes.swift */, 456 | ); 457 | path = Extensions; 458 | sourceTree = ""; 459 | }; 460 | BAD850C27618AF3DFC85797E /* Pods */ = { 461 | isa = PBXGroup; 462 | children = ( 463 | 45C36956AE5EE6619794D47C /* Pods.debug.xcconfig */, 464 | D468C75F82E16ED3BAFD0AC9 /* Pods.release.xcconfig */, 465 | 16B13FB15A04FBD3E207E964 /* Pods-SwiftDailyAPI-MacTests.debug.xcconfig */, 466 | 4262DB75DBB83D66D39E5D16 /* Pods-SwiftDailyAPI-MacTests.release.xcconfig */, 467 | 921F1F72C19F840E93CEC4FE /* Pods-SwiftDailyAPI-iOSTests.debug.xcconfig */, 468 | DD94845195E8D1FFF9D31B4F /* Pods-SwiftDailyAPI-iOSTests.release.xcconfig */, 469 | ); 470 | name = Pods; 471 | sourceTree = ""; 472 | }; 473 | /* End PBXGroup section */ 474 | 475 | /* Begin PBXHeadersBuildPhase section */ 476 | 756AAE611B12A3A40077DFFF /* Headers */ = { 477 | isa = PBXHeadersBuildPhase; 478 | buildActionMask = 2147483647; 479 | files = ( 480 | 756AAE6A1B12A3A40077DFFF /* SwiftDailyAPI.h in Headers */, 481 | ); 482 | runOnlyForDeploymentPostprocessing = 0; 483 | }; 484 | 756AAE931B12A6700077DFFF /* Headers */ = { 485 | isa = PBXHeadersBuildPhase; 486 | buildActionMask = 2147483647; 487 | files = ( 488 | 7598B01D1B1328C800E55D79 /* SwiftDailyAPI.h in Headers */, 489 | ); 490 | runOnlyForDeploymentPostprocessing = 0; 491 | }; 492 | /* End PBXHeadersBuildPhase section */ 493 | 494 | /* Begin PBXNativeTarget section */ 495 | 756AAE631B12A3A40077DFFF /* SwiftDailyAPI-iOS */ = { 496 | isa = PBXNativeTarget; 497 | buildConfigurationList = 756AAE7A1B12A3A40077DFFF /* Build configuration list for PBXNativeTarget "SwiftDailyAPI-iOS" */; 498 | buildPhases = ( 499 | 51C057AA8D3B364BA1FEEAF1 /* Check Pods Manifest.lock */, 500 | 756AAE5F1B12A3A40077DFFF /* Sources */, 501 | 756AAE601B12A3A40077DFFF /* Frameworks */, 502 | 756AAE611B12A3A40077DFFF /* Headers */, 503 | A13DADD929716F4C47F19254 /* Copy Pods Resources */, 504 | ); 505 | buildRules = ( 506 | ); 507 | dependencies = ( 508 | ); 509 | name = "SwiftDailyAPI-iOS"; 510 | productName = SwiftDailyAPI; 511 | productReference = 756AAE641B12A3A40077DFFF /* SwiftDailyAPI.framework */; 512 | productType = "com.apple.product-type.framework"; 513 | }; 514 | 756AAE6E1B12A3A40077DFFF /* SwiftDailyAPI-iOSTests */ = { 515 | isa = PBXNativeTarget; 516 | buildConfigurationList = 756AAE7D1B12A3A40077DFFF /* Build configuration list for PBXNativeTarget "SwiftDailyAPI-iOSTests" */; 517 | buildPhases = ( 518 | 253B485FF3C3809AFE0B70D6 /* Check Pods Manifest.lock */, 519 | 756AAE6B1B12A3A40077DFFF /* Sources */, 520 | 756AAE6C1B12A3A40077DFFF /* Frameworks */, 521 | 756AAE6D1B12A3A40077DFFF /* Resources */, 522 | A9592286AECBC79C2A87F489 /* Embed Pods Frameworks */, 523 | EB3E00D34BF414BE66951D43 /* Copy Pods Resources */, 524 | ); 525 | buildRules = ( 526 | ); 527 | dependencies = ( 528 | 756AAE721B12A3A40077DFFF /* PBXTargetDependency */, 529 | ); 530 | name = "SwiftDailyAPI-iOSTests"; 531 | productName = SwiftDailyAPITests; 532 | productReference = 756AAE6F1B12A3A40077DFFF /* SwiftDailyAPI-iOSTests.xctest */; 533 | productType = "com.apple.product-type.bundle.unit-test"; 534 | }; 535 | 756AAE951B12A6700077DFFF /* SwiftDailyAPI-Mac */ = { 536 | isa = PBXNativeTarget; 537 | buildConfigurationList = 756AAEA91B12A6700077DFFF /* Build configuration list for PBXNativeTarget "SwiftDailyAPI-Mac" */; 538 | buildPhases = ( 539 | 756AAE911B12A6700077DFFF /* Sources */, 540 | 756AAE921B12A6700077DFFF /* Frameworks */, 541 | 756AAE931B12A6700077DFFF /* Headers */, 542 | 756AAE941B12A6700077DFFF /* Resources */, 543 | 7598B0251B132B6400E55D79 /* CopyFiles */, 544 | ); 545 | buildRules = ( 546 | ); 547 | dependencies = ( 548 | ); 549 | name = "SwiftDailyAPI-Mac"; 550 | productName = "SwiftDailyAPI-Mac"; 551 | productReference = 756AAE961B12A6700077DFFF /* SwiftDailyAPI.framework */; 552 | productType = "com.apple.product-type.framework"; 553 | }; 554 | 756AAE9F1B12A6700077DFFF /* SwiftDailyAPI-MacTests */ = { 555 | isa = PBXNativeTarget; 556 | buildConfigurationList = 756AAEAC1B12A6700077DFFF /* Build configuration list for PBXNativeTarget "SwiftDailyAPI-MacTests" */; 557 | buildPhases = ( 558 | 92FE53812889042EC1464544 /* Check Pods Manifest.lock */, 559 | 756AAE9C1B12A6700077DFFF /* Sources */, 560 | 756AAE9D1B12A6700077DFFF /* Frameworks */, 561 | 756AAE9E1B12A6700077DFFF /* Resources */, 562 | 1426ED523F4A6389A6B7617D /* Embed Pods Frameworks */, 563 | 57CA1071E0C65160AFC526A8 /* Copy Pods Resources */, 564 | ); 565 | buildRules = ( 566 | ); 567 | dependencies = ( 568 | 756AAEA31B12A6700077DFFF /* PBXTargetDependency */, 569 | ); 570 | name = "SwiftDailyAPI-MacTests"; 571 | productName = "SwiftDailyAPI-MacTests"; 572 | productReference = 756AAEA01B12A6700077DFFF /* SwiftDailyAPI-MacTests.xctest */; 573 | productType = "com.apple.product-type.bundle.unit-test"; 574 | }; 575 | /* End PBXNativeTarget section */ 576 | 577 | /* Begin PBXProject section */ 578 | 756AAE5B1B12A3A40077DFFF /* Project object */ = { 579 | isa = PBXProject; 580 | attributes = { 581 | LastSwiftUpdateCheck = 0700; 582 | LastUpgradeCheck = 0700; 583 | ORGANIZATIONNAME = nickTD; 584 | TargetAttributes = { 585 | 756AAE631B12A3A40077DFFF = { 586 | CreatedOnToolsVersion = 6.3.2; 587 | }; 588 | 756AAE6E1B12A3A40077DFFF = { 589 | CreatedOnToolsVersion = 6.3.2; 590 | }; 591 | 756AAE951B12A6700077DFFF = { 592 | CreatedOnToolsVersion = 6.3.2; 593 | }; 594 | 756AAE9F1B12A6700077DFFF = { 595 | CreatedOnToolsVersion = 6.3.2; 596 | }; 597 | }; 598 | }; 599 | buildConfigurationList = 756AAE5E1B12A3A40077DFFF /* Build configuration list for PBXProject "SwiftDailyAPI" */; 600 | compatibilityVersion = "Xcode 3.2"; 601 | developmentRegion = English; 602 | hasScannedForEncodings = 0; 603 | knownRegions = ( 604 | en, 605 | ); 606 | mainGroup = 756AAE5A1B12A3A40077DFFF; 607 | productRefGroup = 756AAE651B12A3A40077DFFF /* Products */; 608 | projectDirPath = ""; 609 | projectRoot = ""; 610 | targets = ( 611 | 756AAE631B12A3A40077DFFF /* SwiftDailyAPI-iOS */, 612 | 756AAE6E1B12A3A40077DFFF /* SwiftDailyAPI-iOSTests */, 613 | 756AAE951B12A6700077DFFF /* SwiftDailyAPI-Mac */, 614 | 756AAE9F1B12A6700077DFFF /* SwiftDailyAPI-MacTests */, 615 | ); 616 | }; 617 | /* End PBXProject section */ 618 | 619 | /* Begin PBXResourcesBuildPhase section */ 620 | 756AAE6D1B12A3A40077DFFF /* Resources */ = { 621 | isa = PBXResourcesBuildPhase; 622 | buildActionMask = 2147483647; 623 | files = ( 624 | 75E237FE1B1351CB00F6DE3E /* daily_news.json in Resources */, 625 | 7532368C1B5629CD002C6BF1 /* news_4820022.json in Resources */, 626 | 7598B0331B13399600E55D79 /* news_meta.json in Resources */, 627 | 753053ED1B19CE1100B28354 /* news_4770416.json in Resources */, 628 | 75E238031B13569D00F6DE3E /* news_meta_with_a_theme.json in Resources */, 629 | 75507B171B168946006F41F9 /* daily_news_20150525.json in Resources */, 630 | 758872F01B6E0109006ECF61 /* latest_daily_news_20150802.json in Resources */, 631 | 75522B9D1B1C1DDF003DA78E /* long_comments_4772308.json in Resources */, 632 | 7598B0341B13399600E55D79 /* top_news_meta.json in Resources */, 633 | 75522B9A1B1C1D7B003DA78E /* comment.json in Resources */, 634 | 7598B0351B13399600E55D79 /* multipic_news_meta.json in Resources */, 635 | 7598B0361B13399600E55D79 /* news.json in Resources */, 636 | 75E237F31B1346A100F6DE3E /* latest_daily_news.json in Resources */, 637 | 75F919651B1685150053FF42 /* latest_daily_news_20150527.json in Resources */, 638 | 7532368A1B5629C9002C6BF1 /* news_4859444.json in Resources */, 639 | 75522B971B1C1896003DA78E /* short_comments_4772308.json in Resources */, 640 | 75522B8B1B1B1F9A003DA78E /* news_extra.json in Resources */, 641 | 75522B8E1B1B1FE8003DA78E /* news_extra_4770416.json in Resources */, 642 | 75522B951B1C188F003DA78E /* comment_with_reply_to.json in Resources */, 643 | ); 644 | runOnlyForDeploymentPostprocessing = 0; 645 | }; 646 | 756AAE941B12A6700077DFFF /* Resources */ = { 647 | isa = PBXResourcesBuildPhase; 648 | buildActionMask = 2147483647; 649 | files = ( 650 | ); 651 | runOnlyForDeploymentPostprocessing = 0; 652 | }; 653 | 756AAE9E1B12A6700077DFFF /* Resources */ = { 654 | isa = PBXResourcesBuildPhase; 655 | buildActionMask = 2147483647; 656 | files = ( 657 | 75E237FD1B1351C100F6DE3E /* daily_news.json in Resources */, 658 | 7532368D1B5629CE002C6BF1 /* news_4820022.json in Resources */, 659 | 7598B0371B13399E00E55D79 /* news_meta.json in Resources */, 660 | 753053EE1B19CE1200B28354 /* news_4770416.json in Resources */, 661 | 75E238041B13569D00F6DE3E /* news_meta_with_a_theme.json in Resources */, 662 | 75507B181B168946006F41F9 /* daily_news_20150525.json in Resources */, 663 | 758872F11B6E0109006ECF61 /* latest_daily_news_20150802.json in Resources */, 664 | 75522B9E1B1C1DDF003DA78E /* long_comments_4772308.json in Resources */, 665 | 7598B0381B13399E00E55D79 /* top_news_meta.json in Resources */, 666 | 75522B9B1B1C1D7B003DA78E /* comment.json in Resources */, 667 | 7598B0391B13399E00E55D79 /* multipic_news_meta.json in Resources */, 668 | 7598B03A1B13399E00E55D79 /* news.json in Resources */, 669 | 75E237F41B1346A200F6DE3E /* latest_daily_news.json in Resources */, 670 | 75F919661B1685150053FF42 /* latest_daily_news_20150527.json in Resources */, 671 | 7532368B1B5629C9002C6BF1 /* news_4859444.json in Resources */, 672 | 75522B981B1C1896003DA78E /* short_comments_4772308.json in Resources */, 673 | 75522B8C1B1B1F9A003DA78E /* news_extra.json in Resources */, 674 | 75522B8F1B1B1FE8003DA78E /* news_extra_4770416.json in Resources */, 675 | 75522B961B1C188F003DA78E /* comment_with_reply_to.json in Resources */, 676 | ); 677 | runOnlyForDeploymentPostprocessing = 0; 678 | }; 679 | /* End PBXResourcesBuildPhase section */ 680 | 681 | /* Begin PBXShellScriptBuildPhase section */ 682 | 1426ED523F4A6389A6B7617D /* Embed Pods Frameworks */ = { 683 | isa = PBXShellScriptBuildPhase; 684 | buildActionMask = 2147483647; 685 | files = ( 686 | ); 687 | inputPaths = ( 688 | ); 689 | name = "Embed Pods Frameworks"; 690 | outputPaths = ( 691 | ); 692 | runOnlyForDeploymentPostprocessing = 0; 693 | shellPath = /bin/sh; 694 | shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-SwiftDailyAPI-MacTests/Pods-SwiftDailyAPI-MacTests-frameworks.sh\"\n"; 695 | showEnvVarsInLog = 0; 696 | }; 697 | 253B485FF3C3809AFE0B70D6 /* Check Pods Manifest.lock */ = { 698 | isa = PBXShellScriptBuildPhase; 699 | buildActionMask = 2147483647; 700 | files = ( 701 | ); 702 | inputPaths = ( 703 | ); 704 | name = "Check Pods Manifest.lock"; 705 | outputPaths = ( 706 | ); 707 | runOnlyForDeploymentPostprocessing = 0; 708 | shellPath = /bin/sh; 709 | shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [[ $? != 0 ]] ; then\n cat << EOM\nerror: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\nEOM\n exit 1\nfi\n"; 710 | showEnvVarsInLog = 0; 711 | }; 712 | 51C057AA8D3B364BA1FEEAF1 /* Check Pods Manifest.lock */ = { 713 | isa = PBXShellScriptBuildPhase; 714 | buildActionMask = 2147483647; 715 | files = ( 716 | ); 717 | inputPaths = ( 718 | ); 719 | name = "Check Pods Manifest.lock"; 720 | outputPaths = ( 721 | ); 722 | runOnlyForDeploymentPostprocessing = 0; 723 | shellPath = /bin/sh; 724 | shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [[ $? != 0 ]] ; then\n cat << EOM\nerror: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\nEOM\n exit 1\nfi\n"; 725 | showEnvVarsInLog = 0; 726 | }; 727 | 57CA1071E0C65160AFC526A8 /* Copy Pods Resources */ = { 728 | isa = PBXShellScriptBuildPhase; 729 | buildActionMask = 2147483647; 730 | files = ( 731 | ); 732 | inputPaths = ( 733 | ); 734 | name = "Copy Pods Resources"; 735 | outputPaths = ( 736 | ); 737 | runOnlyForDeploymentPostprocessing = 0; 738 | shellPath = /bin/sh; 739 | shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-SwiftDailyAPI-MacTests/Pods-SwiftDailyAPI-MacTests-resources.sh\"\n"; 740 | showEnvVarsInLog = 0; 741 | }; 742 | 92FE53812889042EC1464544 /* Check Pods Manifest.lock */ = { 743 | isa = PBXShellScriptBuildPhase; 744 | buildActionMask = 2147483647; 745 | files = ( 746 | ); 747 | inputPaths = ( 748 | ); 749 | name = "Check Pods Manifest.lock"; 750 | outputPaths = ( 751 | ); 752 | runOnlyForDeploymentPostprocessing = 0; 753 | shellPath = /bin/sh; 754 | shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [[ $? != 0 ]] ; then\n cat << EOM\nerror: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\nEOM\n exit 1\nfi\n"; 755 | showEnvVarsInLog = 0; 756 | }; 757 | A13DADD929716F4C47F19254 /* Copy Pods Resources */ = { 758 | isa = PBXShellScriptBuildPhase; 759 | buildActionMask = 2147483647; 760 | files = ( 761 | ); 762 | inputPaths = ( 763 | ); 764 | name = "Copy Pods Resources"; 765 | outputPaths = ( 766 | ); 767 | runOnlyForDeploymentPostprocessing = 0; 768 | shellPath = /bin/sh; 769 | shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods/Pods-resources.sh\"\n"; 770 | showEnvVarsInLog = 0; 771 | }; 772 | A9592286AECBC79C2A87F489 /* Embed Pods Frameworks */ = { 773 | isa = PBXShellScriptBuildPhase; 774 | buildActionMask = 2147483647; 775 | files = ( 776 | ); 777 | inputPaths = ( 778 | ); 779 | name = "Embed Pods Frameworks"; 780 | outputPaths = ( 781 | ); 782 | runOnlyForDeploymentPostprocessing = 0; 783 | shellPath = /bin/sh; 784 | shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-SwiftDailyAPI-iOSTests/Pods-SwiftDailyAPI-iOSTests-frameworks.sh\"\n"; 785 | showEnvVarsInLog = 0; 786 | }; 787 | EB3E00D34BF414BE66951D43 /* Copy Pods Resources */ = { 788 | isa = PBXShellScriptBuildPhase; 789 | buildActionMask = 2147483647; 790 | files = ( 791 | ); 792 | inputPaths = ( 793 | ); 794 | name = "Copy Pods Resources"; 795 | outputPaths = ( 796 | ); 797 | runOnlyForDeploymentPostprocessing = 0; 798 | shellPath = /bin/sh; 799 | shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-SwiftDailyAPI-iOSTests/Pods-SwiftDailyAPI-iOSTests-resources.sh\"\n"; 800 | showEnvVarsInLog = 0; 801 | }; 802 | /* End PBXShellScriptBuildPhase section */ 803 | 804 | /* Begin PBXSourcesBuildPhase section */ 805 | 756AAE5F1B12A3A40077DFFF /* Sources */ = { 806 | isa = PBXSourcesBuildPhase; 807 | buildActionMask = 2147483647; 808 | files = ( 809 | 754196601B2EEBA80072B9B0 /* DateIndex.swift in Sources */, 810 | 75F9195C1B15F1EB0053FF42 /* DailyAPI.swift in Sources */, 811 | 75F919561B15DD8B0053FF42 /* NSDate.swift in Sources */, 812 | 75522B881B1B1CBD003DA78E /* toDecodedTypes.swift in Sources */, 813 | 755F204F1B26C772001AB066 /* Types.swift in Sources */, 814 | 7598B02E1B132D6A00E55D79 /* NewsMeta.swift in Sources */, 815 | 75522B911B1B2104003DA78E /* NewsExtra.swift in Sources */, 816 | 75E238001B13520D00F6DE3E /* LatestDaily.swift in Sources */, 817 | 75319DCA1B198525002C7AFF /* News.swift in Sources */, 818 | 75522BA01B1C1E3C003DA78E /* Comment.swift in Sources */, 819 | 75E237F61B134D1A00F6DE3E /* Daily.swift in Sources */, 820 | 7598B03C1B1340F000E55D79 /* TopNewsMeta.swift in Sources */, 821 | 753053F01B1B18CD00B28354 /* NSURL+Decodable.swift in Sources */, 822 | 753053E81B19CAF500B28354 /* Constants.swift in Sources */, 823 | ); 824 | runOnlyForDeploymentPostprocessing = 0; 825 | }; 826 | 756AAE6B1B12A3A40077DFFF /* Sources */ = { 827 | isa = PBXSourcesBuildPhase; 828 | buildActionMask = 2147483647; 829 | files = ( 830 | 756AAE811B12A3C60077DFFF /* JSONFileReader.swift in Sources */, 831 | 754196661B2FFFAB0072B9B0 /* ExtensionSpecs.swift in Sources */, 832 | 753B430E1B198BAA00EC8FEA /* TestDataModelDecodingSpecs.swift in Sources */, 833 | 75522BA41B1C7EA4003DA78E /* RealDataModelDecodingSpecs.swift in Sources */, 834 | 7545261A1C4554F8001940CF /* objectFromFile.swift in Sources */, 835 | 756F6F201B28523D006D4E10 /* ProofOfConceptSpecs.swift in Sources */, 836 | 754235191C4733F300E0A1F9 /* DateIndexSpec.swift in Sources */, 837 | 7547BAAC1B1FC7FA00F4B7A5 /* ReadmeCodeSpecs.swift in Sources */, 838 | 75522BA71B1C85D1003DA78E /* DecodingPerformanceTests.swift in Sources */, 839 | 75CE7AE31B271DB30001F534 /* Xcode7PlusSwift2.swift in Sources */, 840 | 75F919611B15F3DB0053FF42 /* DailyAPISpecs.swift in Sources */, 841 | ); 842 | runOnlyForDeploymentPostprocessing = 0; 843 | }; 844 | 756AAE911B12A6700077DFFF /* Sources */ = { 845 | isa = PBXSourcesBuildPhase; 846 | buildActionMask = 2147483647; 847 | files = ( 848 | 754196611B2EEBA80072B9B0 /* DateIndex.swift in Sources */, 849 | 75F9195D1B15F1EB0053FF42 /* DailyAPI.swift in Sources */, 850 | 75F919571B15DD8B0053FF42 /* NSDate.swift in Sources */, 851 | 75522B891B1B1CC4003DA78E /* toDecodedTypes.swift in Sources */, 852 | 755F20501B26C772001AB066 /* Types.swift in Sources */, 853 | 7598B02F1B132D6A00E55D79 /* NewsMeta.swift in Sources */, 854 | 75522B921B1B2104003DA78E /* NewsExtra.swift in Sources */, 855 | 75E238011B13520D00F6DE3E /* LatestDaily.swift in Sources */, 856 | 75319DCB1B198525002C7AFF /* News.swift in Sources */, 857 | 75522BA11B1C1E3C003DA78E /* Comment.swift in Sources */, 858 | 75E237F71B134D1A00F6DE3E /* Daily.swift in Sources */, 859 | 7598B03D1B1340F000E55D79 /* TopNewsMeta.swift in Sources */, 860 | 753053F11B1B18CD00B28354 /* NSURL+Decodable.swift in Sources */, 861 | 753053E91B19CAF500B28354 /* Constants.swift in Sources */, 862 | ); 863 | runOnlyForDeploymentPostprocessing = 0; 864 | }; 865 | 756AAE9C1B12A6700077DFFF /* Sources */ = { 866 | isa = PBXSourcesBuildPhase; 867 | buildActionMask = 2147483647; 868 | files = ( 869 | 75E237EF1B13451900F6DE3E /* JSONFileReader.swift in Sources */, 870 | 756F6F211B28523D006D4E10 /* ProofOfConceptSpecs.swift in Sources */, 871 | 75F919601B15F3DA0053FF42 /* DailyAPISpecs.swift in Sources */, 872 | 75522BA51B1C7EA6003DA78E /* RealDataModelDecodingSpecs.swift in Sources */, 873 | 7547BAAD1B1FC7FA00F4B7A5 /* ReadmeCodeSpecs.swift in Sources */, 874 | 7545261B1C4554F9001940CF /* objectFromFile.swift in Sources */, 875 | 75522BA81B1C85D1003DA78E /* DecodingPerformanceTests.swift in Sources */, 876 | 7542351A1C4733F400E0A1F9 /* DateIndexSpec.swift in Sources */, 877 | 754196671B2FFFAB0072B9B0 /* ExtensionSpecs.swift in Sources */, 878 | 7598B01F1B1329F000E55D79 /* TestDataModelDecodingSpecs.swift in Sources */, 879 | ); 880 | runOnlyForDeploymentPostprocessing = 0; 881 | }; 882 | /* End PBXSourcesBuildPhase section */ 883 | 884 | /* Begin PBXTargetDependency section */ 885 | 756AAE721B12A3A40077DFFF /* PBXTargetDependency */ = { 886 | isa = PBXTargetDependency; 887 | target = 756AAE631B12A3A40077DFFF /* SwiftDailyAPI-iOS */; 888 | targetProxy = 756AAE711B12A3A40077DFFF /* PBXContainerItemProxy */; 889 | }; 890 | 756AAEA31B12A6700077DFFF /* PBXTargetDependency */ = { 891 | isa = PBXTargetDependency; 892 | target = 756AAE951B12A6700077DFFF /* SwiftDailyAPI-Mac */; 893 | targetProxy = 756AAEA21B12A6700077DFFF /* PBXContainerItemProxy */; 894 | }; 895 | /* End PBXTargetDependency section */ 896 | 897 | /* Begin XCBuildConfiguration section */ 898 | 756AAE781B12A3A40077DFFF /* Debug */ = { 899 | isa = XCBuildConfiguration; 900 | buildSettings = { 901 | ALWAYS_SEARCH_USER_PATHS = NO; 902 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 903 | CLANG_CXX_LIBRARY = "libc++"; 904 | CLANG_ENABLE_MODULES = YES; 905 | CLANG_ENABLE_OBJC_ARC = YES; 906 | CLANG_WARN_BOOL_CONVERSION = YES; 907 | CLANG_WARN_CONSTANT_CONVERSION = YES; 908 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 909 | CLANG_WARN_EMPTY_BODY = YES; 910 | CLANG_WARN_ENUM_CONVERSION = YES; 911 | CLANG_WARN_INT_CONVERSION = YES; 912 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 913 | CLANG_WARN_UNREACHABLE_CODE = YES; 914 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 915 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 916 | COPY_PHASE_STRIP = NO; 917 | CURRENT_PROJECT_VERSION = 1; 918 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 919 | ENABLE_STRICT_OBJC_MSGSEND = YES; 920 | ENABLE_TESTABILITY = YES; 921 | GCC_C_LANGUAGE_STANDARD = gnu99; 922 | GCC_DYNAMIC_NO_PIC = NO; 923 | GCC_NO_COMMON_BLOCKS = YES; 924 | GCC_OPTIMIZATION_LEVEL = 0; 925 | GCC_PREPROCESSOR_DEFINITIONS = ( 926 | "DEBUG=1", 927 | "$(inherited)", 928 | ); 929 | GCC_SYMBOLS_PRIVATE_EXTERN = NO; 930 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 931 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 932 | GCC_WARN_UNDECLARED_SELECTOR = YES; 933 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 934 | GCC_WARN_UNUSED_FUNCTION = YES; 935 | GCC_WARN_UNUSED_VARIABLE = YES; 936 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 937 | MTL_ENABLE_DEBUG_INFO = YES; 938 | ONLY_ACTIVE_ARCH = YES; 939 | SDKROOT = iphoneos; 940 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 941 | TARGETED_DEVICE_FAMILY = "1,2"; 942 | VERSIONING_SYSTEM = "apple-generic"; 943 | VERSION_INFO_PREFIX = ""; 944 | }; 945 | name = Debug; 946 | }; 947 | 756AAE791B12A3A40077DFFF /* Release */ = { 948 | isa = XCBuildConfiguration; 949 | buildSettings = { 950 | ALWAYS_SEARCH_USER_PATHS = NO; 951 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 952 | CLANG_CXX_LIBRARY = "libc++"; 953 | CLANG_ENABLE_MODULES = YES; 954 | CLANG_ENABLE_OBJC_ARC = YES; 955 | CLANG_WARN_BOOL_CONVERSION = YES; 956 | CLANG_WARN_CONSTANT_CONVERSION = YES; 957 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 958 | CLANG_WARN_EMPTY_BODY = YES; 959 | CLANG_WARN_ENUM_CONVERSION = YES; 960 | CLANG_WARN_INT_CONVERSION = YES; 961 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 962 | CLANG_WARN_UNREACHABLE_CODE = YES; 963 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 964 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 965 | COPY_PHASE_STRIP = NO; 966 | CURRENT_PROJECT_VERSION = 1; 967 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 968 | ENABLE_NS_ASSERTIONS = NO; 969 | ENABLE_STRICT_OBJC_MSGSEND = YES; 970 | GCC_C_LANGUAGE_STANDARD = gnu99; 971 | GCC_NO_COMMON_BLOCKS = YES; 972 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 973 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 974 | GCC_WARN_UNDECLARED_SELECTOR = YES; 975 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 976 | GCC_WARN_UNUSED_FUNCTION = YES; 977 | GCC_WARN_UNUSED_VARIABLE = YES; 978 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 979 | MTL_ENABLE_DEBUG_INFO = NO; 980 | SDKROOT = iphoneos; 981 | TARGETED_DEVICE_FAMILY = "1,2"; 982 | VALIDATE_PRODUCT = YES; 983 | VERSIONING_SYSTEM = "apple-generic"; 984 | VERSION_INFO_PREFIX = ""; 985 | }; 986 | name = Release; 987 | }; 988 | 756AAE7B1B12A3A40077DFFF /* Debug */ = { 989 | isa = XCBuildConfiguration; 990 | baseConfigurationReference = 45C36956AE5EE6619794D47C /* Pods.debug.xcconfig */; 991 | buildSettings = { 992 | CLANG_ENABLE_MODULES = YES; 993 | DEFINES_MODULE = YES; 994 | DYLIB_COMPATIBILITY_VERSION = 1; 995 | DYLIB_CURRENT_VERSION = 1; 996 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 997 | ENABLE_TESTABILITY = YES; 998 | FRAMEWORK_SEARCH_PATHS = "$(inherited)"; 999 | INFOPLIST_FILE = SwiftDailyAPI/Info.plist; 1000 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 1001 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 1002 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 1003 | PRODUCT_BUNDLE_IDENTIFIER = "com.nickTD.$(PRODUCT_NAME)"; 1004 | PRODUCT_NAME = SwiftDailyAPI; 1005 | SKIP_INSTALL = YES; 1006 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 1007 | }; 1008 | name = Debug; 1009 | }; 1010 | 756AAE7C1B12A3A40077DFFF /* Release */ = { 1011 | isa = XCBuildConfiguration; 1012 | baseConfigurationReference = D468C75F82E16ED3BAFD0AC9 /* Pods.release.xcconfig */; 1013 | buildSettings = { 1014 | CLANG_ENABLE_MODULES = YES; 1015 | DEFINES_MODULE = YES; 1016 | DYLIB_COMPATIBILITY_VERSION = 1; 1017 | DYLIB_CURRENT_VERSION = 1; 1018 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 1019 | ENABLE_TESTABILITY = YES; 1020 | FRAMEWORK_SEARCH_PATHS = "$(inherited)"; 1021 | INFOPLIST_FILE = SwiftDailyAPI/Info.plist; 1022 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 1023 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 1024 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 1025 | PRODUCT_BUNDLE_IDENTIFIER = "com.nickTD.$(PRODUCT_NAME)"; 1026 | PRODUCT_NAME = SwiftDailyAPI; 1027 | SKIP_INSTALL = YES; 1028 | }; 1029 | name = Release; 1030 | }; 1031 | 756AAE7E1B12A3A40077DFFF /* Debug */ = { 1032 | isa = XCBuildConfiguration; 1033 | baseConfigurationReference = 921F1F72C19F840E93CEC4FE /* Pods-SwiftDailyAPI-iOSTests.debug.xcconfig */; 1034 | buildSettings = { 1035 | FRAMEWORK_SEARCH_PATHS = ( 1036 | "$(SDKROOT)/Developer/Library/Frameworks", 1037 | "$(inherited)", 1038 | ); 1039 | GCC_PREPROCESSOR_DEFINITIONS = ( 1040 | "DEBUG=1", 1041 | "$(inherited)", 1042 | ); 1043 | INFOPLIST_FILE = SwiftDailyAPITests/Info.plist; 1044 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 1045 | PRODUCT_BUNDLE_IDENTIFIER = "com.nickTD.$(PRODUCT_NAME:rfc1034identifier)"; 1046 | PRODUCT_NAME = "SwiftDailyAPI-iOSTests"; 1047 | }; 1048 | name = Debug; 1049 | }; 1050 | 756AAE7F1B12A3A40077DFFF /* Release */ = { 1051 | isa = XCBuildConfiguration; 1052 | baseConfigurationReference = DD94845195E8D1FFF9D31B4F /* Pods-SwiftDailyAPI-iOSTests.release.xcconfig */; 1053 | buildSettings = { 1054 | FRAMEWORK_SEARCH_PATHS = ( 1055 | "$(SDKROOT)/Developer/Library/Frameworks", 1056 | "$(inherited)", 1057 | ); 1058 | INFOPLIST_FILE = SwiftDailyAPITests/Info.plist; 1059 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 1060 | PRODUCT_BUNDLE_IDENTIFIER = "com.nickTD.$(PRODUCT_NAME:rfc1034identifier)"; 1061 | PRODUCT_NAME = "SwiftDailyAPI-iOSTests"; 1062 | }; 1063 | name = Release; 1064 | }; 1065 | 756AAEAA1B12A6700077DFFF /* Debug */ = { 1066 | isa = XCBuildConfiguration; 1067 | buildSettings = { 1068 | CLANG_ENABLE_MODULES = YES; 1069 | COMBINE_HIDPI_IMAGES = YES; 1070 | DEBUG_INFORMATION_FORMAT = dwarf; 1071 | DEFINES_MODULE = YES; 1072 | DYLIB_COMPATIBILITY_VERSION = 1; 1073 | DYLIB_CURRENT_VERSION = 1; 1074 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 1075 | ENABLE_TESTABILITY = YES; 1076 | FRAMEWORK_SEARCH_PATHS = "$(inherited)"; 1077 | FRAMEWORK_VERSION = A; 1078 | GCC_PREPROCESSOR_DEFINITIONS = ( 1079 | "DEBUG=1", 1080 | "$(inherited)", 1081 | ); 1082 | INFOPLIST_FILE = "$(SRCROOT)/SwiftDailyAPI/Info.plist"; 1083 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 1084 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks"; 1085 | MACOSX_DEPLOYMENT_TARGET = 10.10; 1086 | PRODUCT_BUNDLE_IDENTIFIER = "com.nickTD.$(PRODUCT_NAME)"; 1087 | PRODUCT_NAME = SwiftDailyAPI; 1088 | SDKROOT = macosx; 1089 | SKIP_INSTALL = YES; 1090 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 1091 | }; 1092 | name = Debug; 1093 | }; 1094 | 756AAEAB1B12A6700077DFFF /* Release */ = { 1095 | isa = XCBuildConfiguration; 1096 | buildSettings = { 1097 | CLANG_ENABLE_MODULES = YES; 1098 | COMBINE_HIDPI_IMAGES = YES; 1099 | DEFINES_MODULE = YES; 1100 | DYLIB_COMPATIBILITY_VERSION = 1; 1101 | DYLIB_CURRENT_VERSION = 1; 1102 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 1103 | ENABLE_TESTABILITY = YES; 1104 | FRAMEWORK_SEARCH_PATHS = "$(inherited)"; 1105 | FRAMEWORK_VERSION = A; 1106 | INFOPLIST_FILE = "$(SRCROOT)/SwiftDailyAPI/Info.plist"; 1107 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 1108 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks"; 1109 | MACOSX_DEPLOYMENT_TARGET = 10.10; 1110 | PRODUCT_BUNDLE_IDENTIFIER = "com.nickTD.$(PRODUCT_NAME)"; 1111 | PRODUCT_NAME = SwiftDailyAPI; 1112 | SDKROOT = macosx; 1113 | SKIP_INSTALL = YES; 1114 | }; 1115 | name = Release; 1116 | }; 1117 | 756AAEAD1B12A6700077DFFF /* Debug */ = { 1118 | isa = XCBuildConfiguration; 1119 | baseConfigurationReference = 16B13FB15A04FBD3E207E964 /* Pods-SwiftDailyAPI-MacTests.debug.xcconfig */; 1120 | buildSettings = { 1121 | COMBINE_HIDPI_IMAGES = YES; 1122 | DEBUG_INFORMATION_FORMAT = dwarf; 1123 | FRAMEWORK_SEARCH_PATHS = ( 1124 | "$(DEVELOPER_FRAMEWORKS_DIR)", 1125 | "$(inherited)", 1126 | ); 1127 | GCC_PREPROCESSOR_DEFINITIONS = ( 1128 | "DEBUG=1", 1129 | "$(inherited)", 1130 | ); 1131 | INFOPLIST_FILE = SwiftDailyAPITests/Info.plist; 1132 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; 1133 | MACOSX_DEPLOYMENT_TARGET = 10.10; 1134 | PRODUCT_BUNDLE_IDENTIFIER = "com.nickTD.$(PRODUCT_NAME:rfc1034identifier)"; 1135 | PRODUCT_NAME = "$(TARGET_NAME)"; 1136 | SDKROOT = macosx; 1137 | }; 1138 | name = Debug; 1139 | }; 1140 | 756AAEAE1B12A6700077DFFF /* Release */ = { 1141 | isa = XCBuildConfiguration; 1142 | baseConfigurationReference = 4262DB75DBB83D66D39E5D16 /* Pods-SwiftDailyAPI-MacTests.release.xcconfig */; 1143 | buildSettings = { 1144 | COMBINE_HIDPI_IMAGES = YES; 1145 | FRAMEWORK_SEARCH_PATHS = ( 1146 | "$(DEVELOPER_FRAMEWORKS_DIR)", 1147 | "$(inherited)", 1148 | ); 1149 | INFOPLIST_FILE = SwiftDailyAPITests/Info.plist; 1150 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; 1151 | MACOSX_DEPLOYMENT_TARGET = 10.10; 1152 | PRODUCT_BUNDLE_IDENTIFIER = "com.nickTD.$(PRODUCT_NAME:rfc1034identifier)"; 1153 | PRODUCT_NAME = "$(TARGET_NAME)"; 1154 | SDKROOT = macosx; 1155 | }; 1156 | name = Release; 1157 | }; 1158 | /* End XCBuildConfiguration section */ 1159 | 1160 | /* Begin XCConfigurationList section */ 1161 | 756AAE5E1B12A3A40077DFFF /* Build configuration list for PBXProject "SwiftDailyAPI" */ = { 1162 | isa = XCConfigurationList; 1163 | buildConfigurations = ( 1164 | 756AAE781B12A3A40077DFFF /* Debug */, 1165 | 756AAE791B12A3A40077DFFF /* Release */, 1166 | ); 1167 | defaultConfigurationIsVisible = 0; 1168 | defaultConfigurationName = Release; 1169 | }; 1170 | 756AAE7A1B12A3A40077DFFF /* Build configuration list for PBXNativeTarget "SwiftDailyAPI-iOS" */ = { 1171 | isa = XCConfigurationList; 1172 | buildConfigurations = ( 1173 | 756AAE7B1B12A3A40077DFFF /* Debug */, 1174 | 756AAE7C1B12A3A40077DFFF /* Release */, 1175 | ); 1176 | defaultConfigurationIsVisible = 0; 1177 | defaultConfigurationName = Release; 1178 | }; 1179 | 756AAE7D1B12A3A40077DFFF /* Build configuration list for PBXNativeTarget "SwiftDailyAPI-iOSTests" */ = { 1180 | isa = XCConfigurationList; 1181 | buildConfigurations = ( 1182 | 756AAE7E1B12A3A40077DFFF /* Debug */, 1183 | 756AAE7F1B12A3A40077DFFF /* Release */, 1184 | ); 1185 | defaultConfigurationIsVisible = 0; 1186 | defaultConfigurationName = Release; 1187 | }; 1188 | 756AAEA91B12A6700077DFFF /* Build configuration list for PBXNativeTarget "SwiftDailyAPI-Mac" */ = { 1189 | isa = XCConfigurationList; 1190 | buildConfigurations = ( 1191 | 756AAEAA1B12A6700077DFFF /* Debug */, 1192 | 756AAEAB1B12A6700077DFFF /* Release */, 1193 | ); 1194 | defaultConfigurationIsVisible = 0; 1195 | defaultConfigurationName = Release; 1196 | }; 1197 | 756AAEAC1B12A6700077DFFF /* Build configuration list for PBXNativeTarget "SwiftDailyAPI-MacTests" */ = { 1198 | isa = XCConfigurationList; 1199 | buildConfigurations = ( 1200 | 756AAEAD1B12A6700077DFFF /* Debug */, 1201 | 756AAEAE1B12A6700077DFFF /* Release */, 1202 | ); 1203 | defaultConfigurationIsVisible = 0; 1204 | defaultConfigurationName = Release; 1205 | }; 1206 | /* End XCConfigurationList section */ 1207 | }; 1208 | rootObject = 756AAE5B1B12A3A40077DFFF /* Project object */; 1209 | } 1210 | -------------------------------------------------------------------------------- /SwiftDailyAPI.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /SwiftDailyAPI.xcodeproj/xcshareddata/xcschemes/SwiftDailyAPI-Mac.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 29 | 35 | 36 | 37 | 38 | 39 | 45 | 46 | 48 | 54 | 55 | 56 | 57 | 58 | 64 | 65 | 66 | 67 | 68 | 69 | 79 | 80 | 86 | 87 | 88 | 89 | 90 | 91 | 97 | 98 | 104 | 105 | 106 | 107 | 109 | 110 | 113 | 114 | 115 | -------------------------------------------------------------------------------- /SwiftDailyAPI.xcodeproj/xcshareddata/xcschemes/SwiftDailyAPI-iOS.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 16 | 22 | 23 | 24 | 31 | 37 | 38 | 39 | 40 | 41 | 47 | 48 | 50 | 56 | 57 | 58 | 59 | 60 | 66 | 67 | 68 | 69 | 70 | 71 | 81 | 82 | 88 | 89 | 90 | 91 | 92 | 93 | 99 | 100 | 106 | 107 | 108 | 109 | 111 | 112 | 115 | 116 | 117 | -------------------------------------------------------------------------------- /SwiftDailyAPI.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /SwiftDailyAPI/Constants.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Constants.swift 3 | // SwiftDailyAPI 4 | // 5 | // Created by Nicholas Tian on 30/05/2015. 6 | // Copyright (c) 2015 nickTD. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | public struct DailyConstants { 12 | public static let dateFormat = "yyyyMMdd" 13 | public static let defaultUserAgent = "SwiftDailyAPI/\(SwiftDailyAPIVersionNumber)" 14 | public static let decodingQueueIdentifier = "com.nickTD.api-decoding-queue" 15 | } -------------------------------------------------------------------------------- /SwiftDailyAPI/DailyAPI.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DailyAPI.swift 3 | // SwiftDailyAPI 4 | // 5 | // Created by Nicholas Tian on 27/05/2015. 6 | // Copyright (c) 2015 nickTD. All rights reserved. 7 | // 8 | 9 | import Alamofire 10 | import Argo 11 | 12 | /// Notes: 13 | /// * Do keep a reference to any instance of `DailyAPI`, otherwise URLRequest will be canceled. 14 | public final class DailyAPI { 15 | /** 16 | The queue which all `completionHandler` runs on. 17 | If it is not set, then `completionHandler` will run on the default decoding queue. 18 | */ 19 | public var completionQueue: dispatch_queue_t? 20 | 21 | private let manager: Manager 22 | private let queue = dispatch_queue_create(DailyConstants.decodingQueueIdentifier, DISPATCH_QUEUE_CONCURRENT) 23 | 24 | private enum DailyRouter: URLRequestConvertible { 25 | static let baseURLString = "http://news.at.zhihu.com/api/4" 26 | 27 | case LastestDaily 28 | case Daily(forDate: NSDate) 29 | case News(newsId: Int) 30 | case NewsExtra(newsId: Int) 31 | case ShortComments(newsId: Int) 32 | case MoreShortComments(newsId: Int, beforeCommentId: Int) 33 | case LongComments(newsId: Int) 34 | 35 | var path: String { 36 | switch self { 37 | case .LastestDaily: 38 | return "/news/latest" 39 | case .Daily(let date): 40 | let dateString = date.dayAfter().toString(format: "yyyyMMdd") 41 | return "/news/before/\(dateString)" 42 | case .News(let newsId): 43 | return "/news/\(newsId)" 44 | case .NewsExtra(let newsId): 45 | return "/news-extra/\(newsId)" 46 | case .ShortComments(let newsId): 47 | return "/news/\(newsId)/short-comments" 48 | case .MoreShortComments(let newsId, let commentId): 49 | return "/news/\(newsId)/short-comments/before/\(commentId)" 50 | case .LongComments(let newsId): 51 | return "/news/\(newsId)/long-comments" 52 | } 53 | } 54 | 55 | var URLRequest: NSMutableURLRequest { 56 | let URL = NSURL(string: DailyRouter.baseURLString)! 57 | let URLRequest = NSMutableURLRequest(URL: URL.URLByAppendingPathComponent(path)) 58 | 59 | return URLRequest 60 | } 61 | } 62 | 63 | /** 64 | Initialize DailyAPI with optional parameters: configuration and userAgent. 65 | 66 | - parameter configuration: The configuration used to construct the underlying NSURLSession. 67 | - parameter userAgent: The "User-Agent" header. Defaults to "SwiftDailyAPI/:version" 68 | - parameter completionQueue: The queue which all `completionHandler` runs on. 69 | 70 | - returns: A new DailyAPI. 71 | */ 72 | public init(completionQueue queue: dispatch_queue_t? = nil, 73 | configuration: NSURLSessionConfiguration = .defaultSessionConfiguration(), 74 | userAgent: String = DailyConstants.defaultUserAgent) { 75 | self.completionQueue = queue 76 | configuration.HTTPAdditionalHeaders = ["User-Agent": userAgent] 77 | self.manager = Manager(configuration: configuration) 78 | } 79 | 80 | /** 81 | Creates a `Alamofire.Request` to fetch the `LatestDaily`. Once the request has finished then the JSON will be decoded and it will call the completionHandler with the deceded object. 82 | 83 | - parameter completionHandler: A closure to be executed once the request has finished and the response JSON has been decoded. The closure takes one argument: the optional decoded object. 84 | 85 | - returns: The request. 86 | */ 87 | public final func latestDaily(completionHandler: (LatestDaily) -> Void) -> Request { 88 | return request(DailyRouter.LastestDaily, completionHandler: completionHandler) 89 | } 90 | 91 | /** 92 | Creates a `Alamofire.Request` to fetch the `Daily` at given date. Once the request has finished then the JSON will be decoded and it will call the completionHandler with the deceded object. 93 | 94 | - parameter date: The date when the `Daily` is published. 95 | - parameter completionHandler: A closure to be executed once the request has finished and the response JSON has been decoded. The closure takes one argument: the optional decoded object. 96 | 97 | - returns: The request. 98 | */ 99 | public final func daily(forDate date: NSDate, completionHandler: (Daily) -> Void) -> Request { 100 | return request(DailyRouter.Daily(forDate: date), completionHandler: completionHandler) 101 | } 102 | 103 | /** 104 | Creates a `Alamofire.Request` to fetch the `News` with given `newsId`. Once the request has finished then the JSON will be decoded and it will call the completionHandler with the deceded object. 105 | 106 | - parameter newsId: The indentifier key for the `News`. 107 | - parameter completionHandler: A closure to be executed once the request has finished and the response JSON has been decoded. The closure takes one argument: the optional decoded object. 108 | 109 | - returns: The request. 110 | */ 111 | public final func news(newsId: Int, completionHandler: NewsHandler) -> Request { 112 | return request(DailyRouter.News(newsId: newsId), completionHandler: completionHandler) 113 | } 114 | 115 | /** 116 | Creates a `Alamofire.Request` to fetch the `NewsExtra` with given `newsId`. Once the request has finished then the JSON will be decoded and it will call the completionHandler with the deceded object. 117 | 118 | - parameter newsId: The indentifier key for the `NewsExtra`. 119 | - parameter completionHandler: A closure to be executed once the request has finished and the response JSON has been decoded. The closure takes one argument: the optional decoded object. 120 | 121 | - returns: The request. 122 | */ 123 | public final func newsExtra(newsId: Int, completionHandler: (NewsExtra) -> Void) -> Request { 124 | return request(DailyRouter.NewsExtra(newsId: newsId), completionHandler: completionHandler) 125 | } 126 | 127 | /** 128 | Creates a `Alamofire.Request` to fetch the short `Comments` with given `newsId`. Once the request has finished then the JSON will be decoded and it will call the completionHandler with the deceded object. 129 | 130 | - parameter newsId: The indentifier key for the short `Comments`. 131 | - parameter completionHandler: A closure to be executed once the request has finished and the response JSON has been decoded. The closure takes one argument: the optional decoded object. 132 | 133 | - returns: The request. 134 | */ 135 | public final func shortComments(newsId: Int, commentsHandler: (Comments) -> Void) -> Request { 136 | return request(DailyRouter.ShortComments(newsId: newsId), completionHandler: commentsHandler) 137 | } 138 | 139 | public final func shortComments(newsId: Int, beforeCommentId commentId: Int, 140 | commentsHandler: (Comments) -> Void) -> Request { 141 | return request(DailyRouter.MoreShortComments(newsId: newsId, beforeCommentId: commentId), completionHandler: commentsHandler) 142 | } 143 | 144 | /** 145 | Creates a `Alamofire.Request` to fetch the long `Comments` with given `newsId`. Once the request has finished then the JSON will be decoded and it will call the completionHandler with the deceded object. 146 | 147 | - parameter newsId: The indentifier key for the long `Comments`. 148 | - parameter completionHandler: A closure to be executed once the request has finished and the response JSON has been decoded. The closure takes one argument: the optional decoded object. 149 | 150 | - returns: The request. 151 | */ 152 | public final func longComments(newsId: Int, commentsHandler: (Comments) -> Void) -> Request { 153 | return request(DailyRouter.LongComments(newsId: newsId), completionHandler: commentsHandler) 154 | } 155 | 156 | /** 157 | Creates a `Alamofire.Request` to fetch all the `Comments` with given `newsId`. Once the request has finished then the JSON will be decoded and it will call the completionHandler with the deceded object. 158 | 159 | - parameter newsId: The indentifier key for the `Comments`. 160 | - parameter completionHandler: A closure to be executed once the request has finished and the response JSON has been decoded. The closure takes one argument: the optional decoded object. 161 | 162 | - returns: The request. 163 | */ 164 | public final func comments(newsId: Int, shortCommentsHandler: (Comments) -> Void, longCommentsHandler: (Comments) -> Void) -> (shortCommentsRequest: Request, longCommentsRequest: Request) { 165 | let shortCommentsRequest = request(DailyRouter.ShortComments(newsId: newsId), completionHandler: shortCommentsHandler) 166 | let longCommentsRequest = request(DailyRouter.LongComments(newsId: newsId), completionHandler: longCommentsHandler) 167 | return (shortCommentsRequest: shortCommentsRequest, longCommentsRequest: longCommentsRequest) 168 | } 169 | 170 | private final func request(URLRequest: URLRequestConvertible, completionHandler: T -> Void) -> Request { 171 | return manager 172 | .request(URLRequest) 173 | .response(queue: queue, responseSerializer: Request.JSONResponseSerializer()) { (response) -> Void in 174 | guard let value = response.result.value else { 175 | // TODO: Decoding Error from Alamofire 176 | return 177 | } 178 | 179 | let JSON = Argo.JSON.parse(value) 180 | 181 | guard let decoded = T.decode(JSON).value else { 182 | // TODO: Decoding Error from Argo 183 | // Expected and actual data 184 | return 185 | } 186 | 187 | if let completionQueue = self.completionQueue { 188 | dispatch_async(completionQueue) { 189 | completionHandler(decoded) 190 | } 191 | } else { 192 | completionHandler(decoded) // on decoding queue 193 | return 194 | } 195 | } 196 | } 197 | } 198 | -------------------------------------------------------------------------------- /SwiftDailyAPI/Extensions/NSDate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // NSDate+String.swift 3 | // SwiftDailyAPI 4 | // 5 | // Created by Nicholas Tian on 27/05/2015. 6 | // Copyright (c) 2015 nickTD. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | extension NSDate: Comparable { } 12 | 13 | public func == (lhs: NSDate, rhs: NSDate) -> Bool { 14 | return lhs.compare(rhs) == .OrderedSame 15 | } 16 | 17 | public func < (lhs: NSDate, rhs: NSDate) -> Bool { 18 | return lhs.compare(rhs) == .OrderedAscending 19 | } 20 | 21 | extension NSDate { 22 | public class func dateAt(year year: Int, month: Int, day: Int) -> NSDate? { 23 | let components = NSDateComponents() 24 | components.year = year 25 | components.month = month 26 | components.day = day 27 | return NSCalendar.currentCalendar().dateFromComponents(components) 28 | } 29 | } 30 | 31 | // MARK: forward and backward 32 | extension NSDate { 33 | public func daysBefore(days: Int = 1) -> NSDate { 34 | return NSCalendar.currentCalendar().dateByAddingUnit(.Day, value: -days, toDate: self, options: [])! 35 | } 36 | 37 | public func dayBefore() -> NSDate { 38 | return daysBefore(1) 39 | } 40 | 41 | public func daysAfter(days: Int = 1) -> NSDate { 42 | return NSCalendar.currentCalendar().dateByAddingUnit(.Day, value: days, toDate: self, options: [])! 43 | } 44 | 45 | public func dayAfter() -> NSDate { 46 | return daysAfter(1) 47 | } 48 | } 49 | 50 | // MARK: String 51 | extension NSDate { 52 | public class func dateFromString(string: String, format: String) -> NSDate? { 53 | let dateFormatter = NSDateFormatter() 54 | dateFormatter.dateFormat = format 55 | return dateFormatter.dateFromString(string) 56 | } 57 | 58 | public func toString(format format: String) -> String { 59 | let dateFormatter = NSDateFormatter() 60 | dateFormatter.dateFormat = format 61 | return dateFormatter.stringFromDate(self) 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /SwiftDailyAPI/Extensions/NSURL+Decodable.swift: -------------------------------------------------------------------------------- 1 | // 2 | // NSURL+Decodable.swift 3 | // SwiftDailyAPI 4 | // 5 | // Created by Nicholas Tian on 31/05/2015. 6 | // Copyright (c) 2015 nickTD. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import Argo 11 | 12 | extension NSURL: Decodable { 13 | public static func decode(j: JSON) -> Decoded { 14 | switch(j) { 15 | case let .String(s): return .fromOptional(NSURL(string: s)) 16 | default: return .Failure(.TypeMismatch(expected: "NSURL", actual: "\(j)")) 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /SwiftDailyAPI/Extensions/toDecodedTypes.swift: -------------------------------------------------------------------------------- 1 | // 2 | // toInt.swift 3 | // SwiftDailyAPI 4 | // 5 | // Created by Nicholas Tian on 31/05/2015. 6 | // Copyright (c) 2015 nickTD. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import Argo 11 | 12 | public func toNSDate(format: String)(dateString: String) -> Decoded { 13 | return .fromOptional(NSDate.dateFromString(dateString, format: format)) 14 | } 15 | 16 | public func toNSDate(fromTimeStamp fromTimeStamp: NSTimeInterval) -> Decoded { 17 | return pure(NSDate(timeIntervalSince1970: fromTimeStamp)) 18 | } 19 | 20 | public func toInt(string: String) -> Decoded { 21 | return .fromOptional(Int(string)) 22 | } 23 | -------------------------------------------------------------------------------- /SwiftDailyAPI/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 2.0.1 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | $(CURRENT_PROJECT_VERSION) 23 | NSPrincipalClass 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /SwiftDailyAPI/Models/Comment.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Comment.swift 3 | // SwiftDailyAPI 4 | // 5 | // Created by Nicholas Tian on 1/06/2015. 6 | // Copyright (c) 2015 nickTD. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import Argo 11 | 12 | public struct Comments { 13 | public let comments: [Comment] 14 | } 15 | 16 | extension Comments: Decodable { 17 | private static func create(comments: [Comment]) -> Comments { 18 | return Comments(comments: comments) 19 | } 20 | 21 | public static func decode(j: JSON) -> Decoded { 22 | return Comments.create 23 | <^> j <|| "comments" 24 | } 25 | } 26 | 27 | public struct Comment { 28 | public let commentId: Int 29 | public let authorName: String 30 | public let content: String 31 | public let likes: Int 32 | public let repliedAt: NSDate 33 | public let avatarURL: NSURL 34 | public let replyToComment: ReplyToComment? 35 | } 36 | 37 | extension Comment: Decodable { 38 | private static func create(commentId: Int)(authorName: String)(content: String)(likes: Int)(repliedAt: NSDate)(avatarURL: NSURL)(replyToComment: ReplyToComment?) -> Comment { 39 | return Comment(commentId: commentId, authorName: authorName, content: content, likes: likes, repliedAt: repliedAt, avatarURL: avatarURL, replyToComment: replyToComment) 40 | } 41 | 42 | public static func decode(j: JSON) -> Decoded { 43 | return Comment.create 44 | <^> j <| "id" 45 | <*> j <| "author" 46 | <*> j <| "content" 47 | <*> j <| "likes" 48 | <*> ((j <| "time") >>- toNSDate) 49 | <*> j <| "avatar" 50 | <*> j <|? "reply_to" 51 | } 52 | } 53 | 54 | public struct ReplyToComment { 55 | public let authorName: String 56 | public let content: String 57 | } 58 | 59 | extension ReplyToComment: Decodable { 60 | private static func create(authorName: String)(content: String) -> ReplyToComment { 61 | return ReplyToComment(authorName: authorName, content: content) 62 | } 63 | 64 | public static func decode(j: JSON) -> Decoded { 65 | return ReplyToComment.create 66 | <^> j <| "author" 67 | <*> j <| "content" 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /SwiftDailyAPI/Models/Daily.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Daily.swift 3 | // SwiftDailyAPI 4 | // 5 | // Created by Nicholas Tian on 25/05/2015. 6 | // Copyright (c) 2015 nickTD. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import Argo 11 | 12 | public struct Daily { 13 | public let date: NSDate 14 | public let news: [NewsMeta] 15 | } 16 | 17 | extension Daily { 18 | public init(_ latestDaily: LatestDaily) { 19 | date = latestDaily.date 20 | news = latestDaily.news 21 | } 22 | } 23 | 24 | extension Daily: Decodable { 25 | private static func create(date: NSDate)(news: [NewsMeta]) -> Daily { 26 | return Daily(date: date, news: news) 27 | } 28 | 29 | public static func decode(j: JSON) -> Decoded { 30 | return Daily.create 31 | <^> ((j <| "date") >>- toNSDate(DailyConstants.dateFormat)) 32 | <*> j <|| "stories" 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /SwiftDailyAPI/Models/DateIndex.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DateIndex.swift 3 | // SwiftDailyAPI 4 | // 5 | // Created by Nicholas Tian on 15/06/2015. 6 | // Copyright © 2015 nickTD. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | public struct DateIndex { 12 | public let date: NSDate 13 | private var calendar = NSCalendar.currentCalendar() 14 | 15 | public init(_ date: NSDate = NSDate()) { 16 | self.date = calendar.startOfDayForDate(date) 17 | } 18 | } 19 | 20 | public func == (lhs: DateIndex, rhs: DateIndex) -> Bool { 21 | return lhs.date == rhs.date 22 | } 23 | 24 | extension DateIndex: Equatable { } 25 | 26 | extension DateIndex: Hashable { 27 | public var hashValue: Int { 28 | return date.hashValue 29 | } 30 | } 31 | 32 | extension DateIndex: RandomAccessIndexType { 33 | public func successor() -> DateIndex { 34 | return advancedBy(1) 35 | } 36 | 37 | public func predecessor() -> DateIndex { 38 | return advancedBy(-1) 39 | } 40 | 41 | public func advancedBy(n: Int) -> DateIndex { 42 | let advancedDate = calendar.dateByAddingUnit(.Day, value: n, toDate: date, options: [])! 43 | return DateIndex(advancedDate) 44 | } 45 | 46 | public func distanceTo(other: DateIndex) -> Int { 47 | return calendar.components(.Day, fromDate: date, toDate: other.date, options: []).day 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /SwiftDailyAPI/Models/LatestDaily.swift: -------------------------------------------------------------------------------- 1 | // 2 | // LatestDaily.swift 3 | // SwiftDailyAPI 4 | // 5 | // Created by Nicholas Tian on 25/05/2015. 6 | // Copyright (c) 2015 nickTD. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import Argo 11 | 12 | public struct LatestDaily { 13 | public let date: NSDate 14 | public let news: [NewsMeta] 15 | public let topNews: [TopNewsMeta] 16 | } 17 | 18 | extension LatestDaily: Decodable { 19 | private static func create(date: NSDate)(news: [NewsMeta])(topNews: [TopNewsMeta]) -> LatestDaily { 20 | return LatestDaily(date: date, news: news, topNews: topNews) 21 | } 22 | 23 | public static func decode(j: JSON) -> Decoded { 24 | return LatestDaily.create 25 | <^> ((j <| "date") >>- toNSDate(DailyConstants.dateFormat)) 26 | <*> j <|| "stories" 27 | <*> j <|| "top_stories" 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /SwiftDailyAPI/Models/News.swift: -------------------------------------------------------------------------------- 1 | // 2 | // News.swift 3 | // SwiftDailyAPI 4 | // 5 | // Created by Nicholas Tian on 30/05/2015. 6 | // Copyright (c) 2015 nickTD. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import Argo 11 | 12 | public struct News { 13 | public let newsId: Int 14 | public let title: String 15 | public let body: String 16 | public let cssURLs: [NSURL] 17 | public let imageURL: NSURL? 18 | public let imageSourceText: String? 19 | public let shareURL: NSURL 20 | } 21 | 22 | extension News: Decodable { 23 | private static func create(newsId: Int)(title: String)(body: String)(cssURLs: [NSURL])(imageURL: NSURL?)(imageSourceText: String?)(shareURL: NSURL) -> News { 24 | return News(newsId: newsId, title: title, body: body, cssURLs: cssURLs, imageURL: imageURL, imageSourceText: imageSourceText, shareURL: shareURL) 25 | } 26 | 27 | public static func decode(j: JSON) -> Decoded { 28 | return News.create 29 | <^> j <| "id" 30 | <*> j <| "title" 31 | <*> j <| "body" 32 | <*> j <|| "css" 33 | <*> j <|? "image" 34 | <*> j <|? "image_source" 35 | <*> j <| "share_url" 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /SwiftDailyAPI/Models/NewsExtra.swift: -------------------------------------------------------------------------------- 1 | // 2 | // NewsExtra.swift 3 | // SwiftDailyAPI 4 | // 5 | // Created by Nicholas Tian on 31/05/2015. 6 | // Copyright (c) 2015 nickTD. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import Argo 11 | 12 | public struct NewsExtra { 13 | public let popularity: Int 14 | public let shortComments: Int 15 | public let longComments: Int 16 | public let comments: Int 17 | } 18 | 19 | extension NewsExtra: Decodable { 20 | private static func create(popularity: Int)(shortComments: Int)(longComments: Int)(comments: Int) -> NewsExtra { 21 | return NewsExtra(popularity: popularity, shortComments: shortComments, longComments: longComments, comments: comments) 22 | } 23 | 24 | public static func decode(j: JSON) -> Decoded { 25 | return NewsExtra.create 26 | <^> j <| "popularity" 27 | <*> j <| "short_comments" 28 | <*> j <| "long_comments" 29 | <*> j <| "comments" 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /SwiftDailyAPI/Models/NewsMeta.swift: -------------------------------------------------------------------------------- 1 | // 2 | // NewsMeta.swift 3 | // SwiftDailyAPI 4 | // 5 | // Created by Nicholas Tian on 25/05/2015. 6 | // Copyright (c) 2015 nickTD. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import Argo 11 | 12 | public struct NewsMeta { 13 | public let newsId: Int 14 | public let title: String 15 | public let imageURLs: [NSURL]? 16 | public let gaPrefix: Int /// This can be used as the key to order news. 17 | } 18 | 19 | extension NewsMeta: Decodable { 20 | private static func create(newsId: Int)(title: String)(imageURLs: [NSURL]?)(gaPrefix: Int) -> NewsMeta { 21 | return NewsMeta(newsId: newsId, title: title, imageURLs: imageURLs, gaPrefix: gaPrefix) 22 | } 23 | 24 | public static func decode(j: JSON) -> Decoded { 25 | return NewsMeta.create 26 | <^> j <| "id" 27 | <*> j <| "title" 28 | <*> j <||? "images" 29 | <*> ((j <| "ga_prefix") >>- toInt) 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /SwiftDailyAPI/Models/TopNewsMeta.swift: -------------------------------------------------------------------------------- 1 | // 2 | // TopNewsMeta.swift 3 | // SwiftDailyAPI 4 | // 5 | // Created by Nicholas Tian on 25/05/2015. 6 | // Copyright (c) 2015 nickTD. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import Argo 11 | 12 | public struct TopNewsMeta { 13 | public let newsId: Int 14 | public let title: String 15 | public let imageURL: NSURL 16 | } 17 | 18 | extension TopNewsMeta: Decodable { 19 | private static func create(newsId: Int)(title: String)(imageURL: NSURL) -> TopNewsMeta { 20 | return TopNewsMeta(newsId: newsId, title: title, imageURL: imageURL) 21 | } 22 | 23 | public static func decode(j: JSON) -> Decoded { 24 | return TopNewsMeta.create 25 | <^> j <| "id" 26 | <*> j <| "title" 27 | <*> j <| "image" 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /SwiftDailyAPI/SwiftDailyAPI.h: -------------------------------------------------------------------------------- 1 | // 2 | // SwiftDailyAPI.h 3 | // SwiftDailyAPI 4 | // 5 | // Created by Nicholas Tian on 25/05/2015. 6 | // Copyright (c) 2015 nickTD. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | //! Project version number for SwiftDailyAPI. 12 | FOUNDATION_EXPORT double SwiftDailyAPIVersionNumber; 13 | 14 | //! Project version string for SwiftDailyAPI. 15 | FOUNDATION_EXPORT const unsigned char SwiftDailyAPIVersionString[]; 16 | 17 | // In this header, you should import all the public headers of your framework using statements like #import 18 | 19 | 20 | -------------------------------------------------------------------------------- /SwiftDailyAPI/Types.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Types.swift 3 | // SwiftDailyAPI 4 | // 5 | // Created by Nicholas Tian on 9/06/2015. 6 | // Copyright (c) 2015 nickTD. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | public typealias LatestDailyHandler = (LatestDaily) -> Void 12 | public typealias DailyHandler = (Daily) -> Void 13 | public typealias NewsHandler = (News) -> Void 14 | -------------------------------------------------------------------------------- /SwiftDailyAPITests/DecodingPerformanceTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // PerformanceTests.swift 3 | // SwiftDailyAPI 4 | // 5 | // Created by Nicholas Tian on 1/06/2015. 6 | // Copyright (c) 2015 nickTD. All rights reserved. 7 | // 8 | 9 | import XCTest 10 | import SwiftDailyAPI 11 | import Argo 12 | 13 | class DecodingPerformanceTests: XCTestCase { 14 | func testDecodingDaily() { 15 | measureDecodingModel(Daily.self, fromFile: "daily_news_20150525") 16 | } 17 | 18 | func testDecodingLatestDaily() { 19 | measureDecodingModel(LatestDaily.self, fromFile: "latest_daily_news_20150527") 20 | } 21 | 22 | func testDecodingNews() { 23 | measureDecodingModel(News.self, fromFile: "news_4770416") 24 | } 25 | 26 | func testDecodingNewsExtra() { 27 | measureDecodingModel(NewsExtra.self, fromFile: "news_extra_4770416") 28 | } 29 | 30 | func testDecodingShortComments() { 31 | measureDecodingModel(Comments.self, fromFile: "short_comments_4772308") 32 | } 33 | 34 | func testDecodingLongComments() { 35 | measureDecodingModel(Comments.self, fromFile: "long_comments_4772308") 36 | } 37 | 38 | func measureDecodingModel(type: T.Type, fromFile file: String) { 39 | let json: AnyObject = JSONFileReader.JSON(fromFile: file)! 40 | 41 | measureBlock { 42 | let model: T? = T.decode(JSON.parse(json)).value 43 | assert(model != nil) 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /SwiftDailyAPITests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | 24 | 25 | -------------------------------------------------------------------------------- /SwiftDailyAPITests/JSON/JSONFileReader.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | class JSONFileReader { 4 | class func JSON(fromFile file: String) -> AnyObject? { 5 | let path = NSBundle(forClass: self).pathForResource(file, ofType: "json") 6 | 7 | if path != nil { 8 | if let data = NSData(contentsOfFile: path!) { 9 | return try! NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(rawValue: 0)) 10 | } 11 | } 12 | 13 | return .None 14 | } 15 | } 16 | 17 | -------------------------------------------------------------------------------- /SwiftDailyAPITests/JSON/comment.json: -------------------------------------------------------------------------------- 1 | { 2 | "author": "The Master", 3 | "content": "How about that? I win.", 4 | "avatar": "http://httpbin.org/image/jpeg", 5 | "time": 1234567890, 6 | "id": 12345, 7 | "likes": 1200 8 | } 9 | -------------------------------------------------------------------------------- /SwiftDailyAPITests/JSON/comment_with_reply_to.json: -------------------------------------------------------------------------------- 1 | { 2 | "author": "The Master", 3 | "content": "How about that? I win.", 4 | "avatar": "http://httpbin.org/image/jpeg", 5 | "time": 1234567890, 6 | "reply_to": { 7 | "content": "Just regenerate! Regenerate!", 8 | "status": 0, 9 | "id": 67890, 10 | "author": "Doctor Who" 11 | }, 12 | "id": 12345, 13 | "likes": 1200 14 | } 15 | -------------------------------------------------------------------------------- /SwiftDailyAPITests/JSON/daily_news.json: -------------------------------------------------------------------------------- 1 | { 2 | "date": "20150525", 3 | "stories": [ 4 | { 5 | "id": 12345, 6 | "title": "Title of the News", 7 | "images": [ 8 | "http://httpbin.org/image/jpeg" 9 | ], 10 | "type": 0, 11 | "ga_prefix": "67890", 12 | } 13 | ] 14 | } 15 | -------------------------------------------------------------------------------- /SwiftDailyAPITests/JSON/daily_news_20150525.json: -------------------------------------------------------------------------------- 1 | { 2 | "date": "20150525", 3 | "stories": [ 4 | { 5 | "images": [ 6 | "http://pic2.zhimg.com/900b2f23178afb129396d3504d13b0c5.jpg" 7 | ], 8 | "type": 0, 9 | "id": 4758714, 10 | "ga_prefix": "052522", 11 | "title": "深夜惊奇 · 抓个人" 12 | }, 13 | { 14 | "title": "本来就超想吃,在影视剧里面看到之后就更想吃了(多图)", 15 | "ga_prefix": "052521", 16 | "images": [ 17 | "http://pic4.zhimg.com/6a56c91c23a50c8f82215cadde3994eb.jpg" 18 | ], 19 | "multipic": true, 20 | "type": 0, 21 | "id": 4760792 22 | }, 23 | { 24 | "images": [ 25 | "http://pic2.zhimg.com/115c3c9e43caa10c2df24b8095a479a1.jpg" 26 | ], 27 | "type": 0, 28 | "id": 4760754, 29 | "ga_prefix": "052520", 30 | "title": "跑步圈看了会沉默,举铁界读了会流泪,看到哪条你转发了?" 31 | }, 32 | { 33 | "images": [ 34 | "http://pic2.zhimg.com/76cdabab8730d5755257cffa710dc68d.jpg" 35 | ], 36 | "type": 0, 37 | "id": 4759313, 38 | "ga_prefix": "052519", 39 | "title": "在家就可以试试:面巾纸滴上酒精是不会变皱的" 40 | }, 41 | { 42 | "images": [ 43 | "http://pic1.zhimg.com/54f86b913057d270cb69cd863cb95524.jpg" 44 | ], 45 | "type": 0, 46 | "id": 4760672, 47 | "ga_prefix": "052518", 48 | "title": "从哈佛毕业的「人生赢家」们,都去了哪里?" 49 | }, 50 | { 51 | "images": [ 52 | "http://pic1.zhimg.com/9dac92633b3c796829407bc2b5f8f5d8.jpg" 53 | ], 54 | "type": 0, 55 | "id": 4755473, 56 | "ga_prefix": "052517", 57 | "title": "饿了 · 一碗苏式阳春面,何等梦幻的时光" 58 | }, 59 | { 60 | "images": [ 61 | "http://pic1.zhimg.com/d21ddbe692c6b42b5735a212a67ec088.jpg" 62 | ], 63 | "type": 0, 64 | "id": 4758516, 65 | "ga_prefix": "052516", 66 | "title": "江西和安徽有哪些值得一逛的小城?(多图)" 67 | }, 68 | { 69 | "images": [ 70 | "http://pic4.zhimg.com/39f5d50cc75287b970aedefa952cdc6f.jpg" 71 | ], 72 | "type": 0, 73 | "id": 4760440, 74 | "ga_prefix": "052515", 75 | "title": "你个奇葩,欺骗感情(多图)" 76 | }, 77 | { 78 | "images": [ 79 | "http://pic3.zhimg.com/24fa6e5accd0bf3ae0406f754a5fab12.jpg" 80 | ], 81 | "type": 0, 82 | "id": 4760166, 83 | "ga_prefix": "052514", 84 | "title": "侯孝贤在戛纳拿了最佳导演,来看看新片有什么看点" 85 | }, 86 | { 87 | "title": "你的密码保护问题真的安全吗?", 88 | "theme": { 89 | "id": 10, 90 | "subscribed": false, 91 | "name": "互联网安全" 92 | }, 93 | "ga_prefix": "052513", 94 | "images": [ 95 | "http://pic4.zhimg.com/fabeb6ece13d1b4f3fecd484f475feeb_t.jpg" 96 | ], 97 | "type": 2, 98 | "id": 4759968 99 | }, 100 | { 101 | "images": [ 102 | "http://pic1.zhimg.com/5b83a30362ba2d53568ad9032cd0ceb4.jpg" 103 | ], 104 | "type": 0, 105 | "id": 4755858, 106 | "ga_prefix": "052512", 107 | "title": "主业作家,「兼职 DJ」 的村上春树君" 108 | }, 109 | { 110 | "images": [ 111 | "http://pic4.zhimg.com/c9b24817e61cc269e6caae3fa92945b3.jpg" 112 | ], 113 | "type": 0, 114 | "id": 4758765, 115 | "ga_prefix": "052511", 116 | "title": "又涨工资了?你可能会影响经济" 117 | }, 118 | { 119 | "images": [ 120 | "http://pic2.zhimg.com/fa0ce61344f9af6aa9cb874b613b8579.jpg" 121 | ], 122 | "type": 0, 123 | "id": 4758436, 124 | "ga_prefix": "052510", 125 | "title": "Google 收购的是一群 geek 凑出来的全明星战队" 126 | }, 127 | { 128 | "images": [ 129 | "http://pic4.zhimg.com/13f5e3b9f95c2de3dd67346fd28c58e3.jpg" 130 | ], 131 | "type": 0, 132 | "id": 4759499, 133 | "ga_prefix": "052509", 134 | "title": "我在联合国实习的时候,强力掺和了一下马尔代夫的内政(多图)" 135 | }, 136 | { 137 | "images": [ 138 | "http://pic1.zhimg.com/138fd9e641421ff1500aae7a6796b2c4.jpg" 139 | ], 140 | "type": 0, 141 | "id": 4759481, 142 | "ga_prefix": "052508", 143 | "title": "这些统治诺奖的聪明大脑,其实都在一个「家谱」里" 144 | }, 145 | { 146 | "images": [ 147 | "http://pic2.zhimg.com/36cff9d05198272fc63f6a44974e8889.jpg" 148 | ], 149 | "type": 0, 150 | "id": 4759218, 151 | "ga_prefix": "052507", 152 | "title": "编剧想省事儿怎么办?让主角加入海军陆战队呀" 153 | }, 154 | { 155 | "images": [ 156 | "http://pic1.zhimg.com/43eabb4a91fb2c126fe76215b5d038a4.jpg" 157 | ], 158 | "type": 0, 159 | "id": 4757838, 160 | "ga_prefix": "052507", 161 | "title": "开车时,学会用正确的姿势查看「后视镜里的世界」" 162 | }, 163 | { 164 | "images": [ 165 | "http://pic2.zhimg.com/f620b15710b8dfec7154648a1414332d.jpg" 166 | ], 167 | "type": 0, 168 | "id": 4759110, 169 | "ga_prefix": "052506", 170 | "title": "瞎扯 · 如何正确地吐槽" 171 | } 172 | ] 173 | } 174 | -------------------------------------------------------------------------------- /SwiftDailyAPITests/JSON/latest_daily_news.json: -------------------------------------------------------------------------------- 1 | { 2 | "date": "20150525", 3 | "stories": [ 4 | { 5 | "id": 12345, 6 | "title": "Title of the News", 7 | "images": [ 8 | "http://httpbin.org/image/jpeg" 9 | ], 10 | "type": 0, 11 | "ga_prefix": "67890" 12 | } 13 | ], 14 | "top_stories": [ 15 | { 16 | "id": 12345, 17 | "title": "Title of the News", 18 | "image": "http://httpbin.org/image/jpeg", 19 | "type": 0, 20 | "ga_prefix": "67890" 21 | } 22 | ] 23 | } 24 | -------------------------------------------------------------------------------- /SwiftDailyAPITests/JSON/latest_daily_news_20150527.json: -------------------------------------------------------------------------------- 1 | { 2 | "date": "20150527", 3 | "stories": [ 4 | { 5 | "images": [ 6 | "http://pic2.zhimg.com/31e2384cb29c886c86ade430a8b0cdf1.jpg" 7 | ], 8 | "type": 0, 9 | "id": 4763403, 10 | "ga_prefix": "052722", 11 | "title": "深夜惊奇 · 遇到陌生老人家" 12 | }, 13 | { 14 | "title": "这些好看的电影,能激起心头一点文艺小情绪(多图)", 15 | "ga_prefix": "052721", 16 | "images": [ 17 | "http://pic1.zhimg.com/a4c3fdaef193a20d918c2ea40a0099d4.jpg" 18 | ], 19 | "multipic": true, 20 | "type": 0, 21 | "id": 4765058 22 | }, 23 | { 24 | "images": [ 25 | "http://pic2.zhimg.com/27afb2ad5ab594f8c92a6208ee465f6d.jpg" 26 | ], 27 | "type": 0, 28 | "id": 4764958, 29 | "ga_prefix": "052720", 30 | "title": "人体内为什么会产生结石?(没图,放心)" 31 | }, 32 | { 33 | "images": [ 34 | "http://pic4.zhimg.com/eb81115c069181786b8dc018d3705eaf.jpg" 35 | ], 36 | "type": 0, 37 | "id": 4764105, 38 | "ga_prefix": "052719", 39 | "title": "有哪些法律上名词的定义,在现实里容易被大众误解?" 40 | }, 41 | { 42 | "images": [ 43 | "http://pic1.zhimg.com/f6e674e03e7f5a03d50ed891d1157cfc.jpg" 44 | ], 45 | "type": 0, 46 | "id": 4765196, 47 | "ga_prefix": "052718", 48 | "title": "这种类型的帅哥美女,基本都是白人" 49 | }, 50 | { 51 | "title": "饿了 · 花式「调教」众人心目中的黑暗粮食——藜麦(多图)", 52 | "ga_prefix": "052717", 53 | "images": [ 54 | "http://pic1.zhimg.com/fa597c483519257da058bdad21599628.jpg" 55 | ], 56 | "multipic": true, 57 | "type": 0, 58 | "id": 4760891 59 | }, 60 | { 61 | "images": [ 62 | "http://pic1.zhimg.com/1f506f90144412a2a3ebdf64ae3b951c.jpg" 63 | ], 64 | "type": 0, 65 | "id": 4765130, 66 | "ga_prefix": "052716", 67 | "title": "我用力一握拳,会捏死手上的细菌吗?" 68 | }, 69 | { 70 | "images": [ 71 | "http://pic2.zhimg.com/ea071d12dca5fb5785d858eefe128f89.jpg" 72 | ], 73 | "type": 0, 74 | "id": 4764740, 75 | "ga_prefix": "052715", 76 | "title": "长得丑不丑没关系,先给自己做一个「心理整形」" 77 | }, 78 | { 79 | "title": "清朝「皇帝的新衣」超讲究,跟别人的不一样,自己的也不一样(多图)", 80 | "ga_prefix": "052714", 81 | "images": [ 82 | "http://pic2.zhimg.com/5ad4076d6b5ad350d3270d132556d87d.jpg" 83 | ], 84 | "multipic": true, 85 | "type": 0, 86 | "id": 4763934 87 | }, 88 | { 89 | "images": [ 90 | "http://pic3.zhimg.com/a3246a209825b5e595c7f65bebaf696e.jpg" 91 | ], 92 | "type": 0, 93 | "id": 4762132, 94 | "ga_prefix": "052713", 95 | "title": "老年人要不要手术,一句话说不清" 96 | }, 97 | { 98 | "title": "看完此教程,你就能给任何人穿上宇宙流行款大花棉衣了(多图)", 99 | "ga_prefix": "052712", 100 | "images": [ 101 | "http://pic1.zhimg.com/3b9df5918a9e9f99f440634bd598dd5c.jpg" 102 | ], 103 | "multipic": true, 104 | "type": 0, 105 | "id": 4764524 106 | }, 107 | { 108 | "images": [ 109 | "http://pic3.zhimg.com/6ea93d4c8b61779acab577760825231a.jpg" 110 | ], 111 | "type": 0, 112 | "id": 4762567, 113 | "ga_prefix": "052711", 114 | "title": "当你的灵魂不能承受景色的壮丽,就会哭(勿吐)" 115 | }, 116 | { 117 | "images": [ 118 | "http://pic3.zhimg.com/24736a9bcf14880918f1ef32582189d6.jpg" 119 | ], 120 | "type": 0, 121 | "id": 4758644, 122 | "ga_prefix": "052710", 123 | "title": "一辆车一生可能跨过无数大山大海,只能进一次烘烤房" 124 | }, 125 | { 126 | "images": [ 127 | "http://pic2.zhimg.com/d3e806f4a418f7107d890a6a75912ced.jpg" 128 | ], 129 | "type": 0, 130 | "id": 4763493, 131 | "ga_prefix": "052709", 132 | "title": "为什么我认为日本动画会越来越好?因为有很多敢于作死的人在" 133 | }, 134 | { 135 | "images": [ 136 | "http://pic1.zhimg.com/ecb2a3907b33aa3ffbfc38e16962a344.jpg" 137 | ], 138 | "type": 0, 139 | "id": 4763771, 140 | "ga_prefix": "052708", 141 | "title": "面子带里子一起拼回来了,火箭又到了 1-3(多图)" 142 | }, 143 | { 144 | "images": [ 145 | "http://pic2.zhimg.com/94aadc55cd4c1c1802acd2e2cb5f9635.jpg" 146 | ], 147 | "type": 0, 148 | "id": 4761767, 149 | "ga_prefix": "052707", 150 | "title": "对女性来说,生化妊娠非常常见,把它当一次月经就好" 151 | }, 152 | { 153 | "images": [ 154 | "http://pic3.zhimg.com/d78ef4bcc8d8db5dbd2ac5c7b95787aa.jpg" 155 | ], 156 | "type": 0, 157 | "id": 4763557, 158 | "ga_prefix": "052707", 159 | "title": "范冰冰的律师有错,可挑错的律师也没对" 160 | }, 161 | { 162 | "images": [ 163 | "http://pic3.zhimg.com/6b5bc16fc8fa638622b9cf4a65e074b6.jpg" 164 | ], 165 | "type": 0, 166 | "id": 4762602, 167 | "ga_prefix": "052707", 168 | "title": "电影里几个主演同时拿奥斯卡奖,非常稀奇(多图)" 169 | }, 170 | { 171 | "images": [ 172 | "http://pic1.zhimg.com/343367c73429cd2928a8c3860b597294.jpg" 173 | ], 174 | "type": 0, 175 | "id": 4761128, 176 | "ga_prefix": "052706", 177 | "title": "瞎扯 · 如何正确地吐槽" 178 | } 179 | ], 180 | "top_stories": [ 181 | { 182 | "image": "http://pic2.zhimg.com/b795aad72f0e5b617d8531b4632389d5.jpg", 183 | "type": 0, 184 | "id": 4765058, 185 | "ga_prefix": "052721", 186 | "title": "这些好看的电影,能激起心头一点文艺小情绪(多图)" 187 | }, 188 | { 189 | "image": "http://pic2.zhimg.com/475f9b02a80fffbcba4515502ab7a6ed.jpg", 190 | "type": 0, 191 | "id": 4760891, 192 | "ga_prefix": "052717", 193 | "title": "饿了 · 花式「调教」众人心目中的黑暗粮食——藜麦(多图)" 194 | }, 195 | { 196 | "image": "http://pic3.zhimg.com/dd1f1292eeb786a405d788e955512fd2.jpg", 197 | "type": 0, 198 | "id": 4764524, 199 | "ga_prefix": "052712", 200 | "title": "看完此教程,你就能给任何人穿上宇宙流行款大花棉衣了(多图)" 201 | }, 202 | { 203 | "image": "http://pic1.zhimg.com/1cb74fec09774049696e551773b61da4.jpg", 204 | "type": 0, 205 | "id": 4763557, 206 | "ga_prefix": "052707", 207 | "title": "范冰冰的律师有错,可挑错的律师也没对" 208 | }, 209 | { 210 | "image": "http://pic4.zhimg.com/561655005cb9c4c8788085ba7c64e90f.jpg", 211 | "type": 0, 212 | "id": 4761767, 213 | "ga_prefix": "052707", 214 | "title": "对女性来说,生化妊娠非常常见,把它当一次月经就好" 215 | } 216 | ] 217 | } 218 | -------------------------------------------------------------------------------- /SwiftDailyAPITests/JSON/latest_daily_news_20150802.json: -------------------------------------------------------------------------------- 1 | { 2 | "date": "20150802", 3 | "stories": [ 4 | { 5 | "title": "觉得生活太无聊,来点不一样的艺术品(多图)", 6 | "ga_prefix": "080215", 7 | "images": [ 8 | "http://pic1.zhimg.com/0de02cb9561aacc757decb6725404910.jpg" 9 | ], 10 | "multipic": true, 11 | "type": 0, 12 | "id": 7013948 13 | }, 14 | { 15 | "images": [ 16 | "http://pic3.zhimg.com/d21a81436057760661ed07332af3d7c6.jpg" 17 | ], 18 | "type": 0, 19 | "id": 7014977, 20 | "ga_prefix": "080214", 21 | "title": "笑或者哭,心里却没什么感觉,我很困扰" 22 | }, 23 | { 24 | "theme": { 25 | "id": 12, 26 | "subscribed": false, 27 | "name": "用户推荐日报" 28 | }, 29 | "type": 0, 30 | "id": 7013775, 31 | "ga_prefix": "080213", 32 | "title": "充电线一类的绳子怎么总是自动拧卷起来?" 33 | }, 34 | { 35 | "images": [ 36 | "http://pic3.zhimg.com/aa5dbc9b5135f1294041d2ef5cd13f46.jpg" 37 | ], 38 | "type": 0, 39 | "id": 7015616, 40 | "ga_prefix": "080212", 41 | "title": "去美丽的青藏高原净化心灵,要小心暴风雪" 42 | }, 43 | { 44 | "title": "下次去故宫或者苏州园林,记得先读这篇文章(多图)", 45 | "ga_prefix": "080211", 46 | "images": [ 47 | "http://pic4.zhimg.com/dec782a748598bf18ad49bcf68809817.jpg" 48 | ], 49 | "multipic": true, 50 | "type": 0, 51 | "id": 7013223 52 | }, 53 | { 54 | "images": [ 55 | "http://pic3.zhimg.com/c3700672085a5304c2c80ecc05a693ae.jpg" 56 | ], 57 | "type": 0, 58 | "id": 7020375, 59 | "ga_prefix": "080210", 60 | "title": "为什么她不愿离开伤害她的人?" 61 | }, 62 | { 63 | "title": "开一场摇滚演唱会(多图)", 64 | "ga_prefix": "080209", 65 | "images": [ 66 | "http://pic1.zhimg.com/301b47e54162e596d27ef4ea0d507708.jpg" 67 | ], 68 | "multipic": true, 69 | "type": 0, 70 | "id": 7026811 71 | }, 72 | { 73 | "images": [ 74 | "http://pic3.zhimg.com/2831f8c7b213b59c12c1b07267cc5c1e.jpg" 75 | ], 76 | "type": 0, 77 | "id": 4879165, 78 | "ga_prefix": "080208", 79 | "title": "动画起源于皮影戏,只是美丽的误会" 80 | }, 81 | { 82 | "images": [ 83 | "http://pic1.zhimg.com/09cc7ed7c0da51dfdd0b473343f829d4.jpg" 84 | ], 85 | "type": 0, 86 | "id": 7026820, 87 | "ga_prefix": "080207", 88 | "title": "很多人搞不清楚的 Espresso、意式咖啡、浓缩咖啡,到底有什么区别" 89 | }, 90 | { 91 | "images": [ 92 | "http://pic2.zhimg.com/281585cfbb8e5176334c429cf1a4306d.jpg" 93 | ], 94 | "type": 0, 95 | "id": 7012202, 96 | "ga_prefix": "080207", 97 | "title": "激将和温柔都能让人很快鸡血满满,然而不是长久之计" 98 | }, 99 | { 100 | "images": [ 101 | "http://pic1.zhimg.com/b0e8986da88bd8ea70e426631e4cf890.jpg" 102 | ], 103 | "type": 0, 104 | "id": 7019376, 105 | "ga_prefix": "080207", 106 | "title": "小时候没有金城武吴彦祖,每年都盼着这两位男神带来欢乐" 107 | }, 108 | { 109 | "images": [ 110 | "http://pic2.zhimg.com/f1f0b97913e11a6575827f9dea50c2ed.jpg" 111 | ], 112 | "type": 0, 113 | "id": 7026738, 114 | "ga_prefix": "080206", 115 | "title": "瞎扯 · 如何正确地吐槽" 116 | } 117 | ], 118 | "top_stories": [ 119 | { 120 | "image": "http://pic2.zhimg.com/073fb2d4bf13f70bde17d53ad17c8871.jpg", 121 | "type": 0, 122 | "id": 7020375, 123 | "ga_prefix": "080210", 124 | "title": "为什么她不愿离开伤害她的人?" 125 | }, 126 | { 127 | "image": "http://pic1.zhimg.com/614002df30c90a46ac2f3137b8705614.jpg", 128 | "type": 0, 129 | "id": 7013223, 130 | "ga_prefix": "080211", 131 | "title": "下次去故宫或者苏州园林,记得先读这篇文章(多图)" 132 | }, 133 | { 134 | "image": "http://pic2.zhimg.com/da5e7c5278c3f2ec66d75ab3c82ea76d.jpg", 135 | "type": 0, 136 | "id": 7019376, 137 | "ga_prefix": "080207", 138 | "title": "小时候没有金城武吴彦祖,每年都盼着这两位男神带来欢乐" 139 | }, 140 | { 141 | "image": "http://pic3.zhimg.com/ed81965dec92b12ca654f8ff573ae46e.jpg", 142 | "type": 0, 143 | "id": 7013059, 144 | "ga_prefix": "080107", 145 | "title": "号称「蒙面歌王」却似化妆舞会,摘下面具原版都在笑,国内全哭了(多图)" 146 | }, 147 | { 148 | "image": "http://pic2.zhimg.com/e98473d578c4154bead85d8fb13121f9.jpg", 149 | "type": 0, 150 | "id": 7020041, 151 | "ga_prefix": "080115", 152 | "title": "酸奶里的「益生菌」为什么不会被我们的肠道干掉?" 153 | } 154 | ] 155 | } 156 | -------------------------------------------------------------------------------- /SwiftDailyAPITests/JSON/long_comments_4772308.json: -------------------------------------------------------------------------------- 1 | { 2 | "comments": [ 3 | { 4 | "author": "Dr_Subres", 5 | "content": "几两瘦肉和米饭挺好哒(●°u°●)​ 」\n个人超喜欢炒鸡蛋(●°u°●)​ 」!!超好吃超好吃!能下酒能配菜有木有有木有!!(●°u°●)​ 」!!\n\n感觉这样吃会腻的……还可以了那些蛋黄……\n健身的话 力量训练后要补充蛋白质,有条件准备一顿好吃的就准备以上的瘦肉(任性的话牛腿肉、牛腱子等)和米饭青菜,不行的话蛋白粉按@斌卡 教练的文表明还是挺不错的,也不贵(教练的文很详细的呢。)", 6 | "avatar": "http://pic3.zhimg.com/87a07400749c2b5735bb4501584fb0e6_im.jpg", 7 | "time": 1433128365, 8 | "reply_to": { 9 | "content": "在健身,每次练完12个蛋白,2个蛋黄,隔天吃感觉还好……其实小时候一个蛋白也吃不进去,不过为了肌肉我也是蛮拼的,现在觉得蛋白挺好吃的。另外我研究过一个蛋白大概也就3~4g蛋白质,所以10个也不多,而且考虑到蛋黄的热量太高,所以我觉得对于健身者来说,蛋白的价值大于蛋黄,以上仅是个人观点。", 10 | "status": 0, 11 | "id": 1136041, 12 | "author": "AIR卡比" 13 | }, 14 | "id": 1137350, 15 | "likes": 1 16 | }, 17 | { 18 | "author": "孙大圣又出差了orz", 19 | "content": "小时候胃病+挑食+海鲜过敏~~貌似能吃的只有鸡蛋了,曾连续十年平均每天5+个鸡蛋,略保守,自我感觉应该能到7+~~~小时候爷爷家养五只母鸡,基本上每只每天下一个蛋,然后每周还要买好多。。当年的菜谱就是早晨煮鸡蛋中午炒鸡蛋晚上蒸鸡蛋。。现在胃病好了,也基本不挑食了,但仍然酷爱吃鸡蛋,煮蛋器用坏了俩。。身体各项指标正常,177cm,65kg~~", 20 | "avatar": "http://pic2.zhimg.com/19ea53749_im.jpg", 21 | "time": 1433121775, 22 | "id": 1137186, 23 | "likes": 3 24 | }, 25 | { 26 | "author": "优徨", 27 | "content": "日报前些日子有说这个事情,今年美国膳食指南取消了鸡蛋的每日摄入量推荐,因为研究结论证明健康人体的代谢能力会保证你在摄入较多胆固醇的时候,血液中的胆固醇含量没有明显升高,当然对于部分亚健康人群还是需要控制摄入的(大意)\n\n其实我只是觉得好好的蛋黄就那么扔了很浪费┑( ̄Д  ̄)┍", 28 | "avatar": "http://pic2.zhimg.com/3ed24d885_im.jpg", 29 | "time": 1433089514, 30 | "id": 1136551, 31 | "likes": 5 32 | }, 33 | { 34 | "author": "AIR卡比", 35 | "content": "在健身,每次练完12个蛋白,2个蛋黄,隔天吃感觉还好……其实小时候一个蛋白也吃不进去,不过为了肌肉我也是蛮拼的,现在觉得蛋白挺好吃的。另外我研究过一个蛋白大概也就3~4g蛋白质,所以10个也不多,而且考虑到蛋黄的热量太高,所以我觉得对于健身者来说,蛋白的价值大于蛋黄,以上仅是个人观点。", 36 | "avatar": "http://pic4.zhimg.com/6bfe457b7_im.jpg", 37 | "time": 1433076930, 38 | "id": 1136041, 39 | "likes": 7 40 | }, 41 | { 42 | "author": "冒凯", 43 | "content": "终于有一个我能回答的。我从小极度挑食,上大学之前的很长一段时间,主食就是鸡蛋,只吃鸡蛋、红烧肉和豆制品。注意,是红烧肉,排骨汤之类的都不吃。其他都不吃,包括所有的蔬菜、鸡鸭牛虾海鲜等等。每天大概12个鸡蛋最少,最多22个鸡蛋,现在食谱拓宽许多,但鸡蛋还是占重要位置,平均每天5个,体检一切ok。", 44 | "avatar": "http://pic1.zhimg.com/da8e974dc_im.jpg", 45 | "time": 1433075420, 46 | "id": 1135990, 47 | "likes": 17 48 | }, 49 | { 50 | "author": "非典型吐槽", 51 | "content": "有的有的!不开心的蛋含有毒素、激素、抗生素、麦丽素……营养成分也要低一些,因为开心的蛋吃的都是大自然纯天然无公害饲料,不开心的蛋只能吃没营养的人工饲料;而且不开心的蛋由于缺乏运动,所以煮出来以后皮肤松垮粗糙,不如开心的蛋那么紧致嫩滑……😝", 52 | "avatar": "http://pic3.zhimg.com/c4facda2a_im.jpg", 53 | "time": 1433066603, 54 | "reply_to": { 55 | "content": "话说我好想知道…现在那些大规模的养殖场,把母鸡关在狭小的笼子里那种,这种不开心的鸡的不开心的蛋和那些开心的鸡生的开心的蛋,有什么区别?好想匿名…", 56 | "status": 0, 57 | "id": 1135493, 58 | "author": "啊呜啊呜的兔" 59 | }, 60 | "id": 1135641, 61 | "likes": 53 62 | }, 63 | { 64 | "author": "xiaoshj", 65 | "content": "这个胆固醇的论调已经过时了,今年美国的饮食指引已经没有明确限制蛋黄的摄入了,因为其实研究到现在,也没有明确的证据证明胆固醇对人体到底造成了什么伤害!个人小结,平常体检没问题的话,蛋黄吃吃没问题,不用担心太多!", 66 | "avatar": "http://pic3.zhimg.com/f8b9a17e2_im.jpg", 67 | "time": 1433065780, 68 | "id": 1135616, 69 | "likes": 26 70 | }, 71 | { 72 | "author": "Toretto_Liu", 73 | "content": "学校旁边买煎饼果子\n每次都让她放三个蛋\n其实更想放四个蛋的\n但是麻麻一直教导我\n每天最多能吃两个蛋\n但鸡蛋越多越好吃啊\n但我又不能不听麻麻\n终于待到今天看到它\n现在总算可以放下心\n下周再去买煎饼果子\n就可以淡定地对她说\n学挖掘机到底哪家强?", 74 | "avatar": "http://pic1.zhimg.com/a381c075a679f7bd5b530e0a10e2e378_im.jpg", 75 | "time": 1433060488, 76 | "id": 1135444, 77 | "likes": 84 78 | }, 79 | { 80 | "author": "猫的国Alex", 81 | "content": "感觉作者的第三点有点问题,胆固醇的吸收率只有30%,随着食物胆固醇含量的增加,吸收率还要下降,所以摄入一个鸡蛋实际吸收的胆固醇应该是 60 左右,所以人体每天所需的胆固醇量应该等于 3-4 个鸡蛋的转化量……", 82 | "avatar": "http://pic1.zhimg.com/c1a2b3880_im.jpg", 83 | "time": 1433060095, 84 | "id": 1135420, 85 | "likes": 6 86 | } 87 | ] 88 | } 89 | -------------------------------------------------------------------------------- /SwiftDailyAPITests/JSON/multipic_news_meta.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": 12345, 3 | "title": "Title of the News", 4 | "multipic": true, 5 | "images": [ 6 | "http://httpbin.org/image/jpeg" 7 | ], 8 | "type": 0, 9 | "ga_prefix": "67890" 10 | } -------------------------------------------------------------------------------- /SwiftDailyAPITests/JSON/news.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": 12345, 3 | "title": "Title of the News", 4 | "body": "HTML body", 5 | "css": [ 6 | "http://news.at.zhihu.com/css/news_qa.auto.css?v=1edab" 7 | ], 8 | "image_source": "Image Source", 9 | "image": "http://httpbin.org/image/jpeg", 10 | "share_url": "http://daily.zhihu.com/story/12345", 11 | "ga_prefix": "67890", 12 | "type": 0, 13 | "js": [ ], 14 | "recommenders": [ 15 | { 16 | "avatar": "http://httpbin.org/image/jpeg" 17 | } 18 | ] 19 | } 20 | -------------------------------------------------------------------------------- /SwiftDailyAPITests/JSON/news_4770416.json: -------------------------------------------------------------------------------- 1 | { 2 | "body": "
\n
\n\n
\n\n\n\n
\n\n
\n\n\n\n\n
\n

英国博物馆数量众多,有哪些有趣的博物馆?

\n\n
\n\n
\n\n铭蔚,生态建筑批尺地\n
\n\n
\n

\"\"

\r\n

伦敦博物馆众多,仅凭个人喜好分享下面这个博物馆。

\r\n

顺着肯辛顿和海德两个园子中间的 Carriage Drive 一路向南,你会突然发现自己走在一条马赛克的大街上,行人和车辆的关系似乎仅仅只能依靠双方的克制。这就是 Exhibition Road。“展览馆路”途径皇家音乐学院,科学博物馆和自然博物馆。若是你的注意力一直放在这条路的西侧,你大概会错过这片区域内最大的一个博物馆——V&A 博物馆的侧翼就在路的另一侧。

\r\n

\"\"

\r\n

(V&A 接展览馆路的入口)

\r\n

V&A,Victoria and Albert。Victoria 指的是维多利亚女王;Albert 意指女王的王夫阿尔伯特亲王。然而在这个博物馆正式使用这一名字的时候(1899 年),亲王大人已经逝世 38 年了。这个馆名可以说是女王悼念深爱的亡夫而起。阿尔伯特不但在教育,福利,废除农奴制和君主立宪上对女王助益很大;他之所以从甫一见面就颇受维多利亚青睐除了颜值很高外还有另一个原因:那就是他对艺术的热爱与年轻的维多利亚颇为契合。说起来,南肯辛顿在教育和文化上的兴盛源自于 1851 年不远处海德公园举办的第一届世界博览会的盈余后的一系列开支,而那次成功博览会的推手就是时任皇家艺术学会主席的阿尔伯特亲王本人。那么,曾经是伦敦设计学院教学收藏室,借由万博会收益迁址扩建并向公共展示的南肯辛顿博物馆(曾用名)就该提到女王“贤内助”的名字。

\r\n

\"\"

\r\n

Queen Victoria and Prince Albert at home at Windsor Castle in Berkshire, England

\r\n

这就是为什么这个 1857 年启用的博物馆在一路扩建完善并用一个新名字迎接 20 世纪的原因。

\r\n

而这一路扩建也很有意思,从Plan sheet A里提供的平面变迁来看,你不光可以发现博物馆在走向公共文化建筑的道路上不断丰满,还可以感觉到其周边的南肯辛顿地区从城郊野地的逐步进化。

\r\n

\"\"

\r\n

\"\"

\r\n

\"\"

\r\n

\"\"

\r\n

\"\"

\r\n

\"\"

\r\n

\"\"

\r\n

\"\"

\r\n

(现在成形的主立面 Grand Entrance)

\r\n

然而,

\r\n

世界上首家煤气照明的博物馆,世界上开创先河地拥有餐厅的博物馆,占地面积几乎等同于大英博物馆的博物馆,却在运营中逐渐暴露出问题:为了展示丰富的藏品,原有的室内装饰被无情地破坏;彩色玻璃窗和马赛克铺地也被视为有碍展示或使用被移出;在封闭拥挤的,曲里拐弯的,昏暗气闷的博物馆里连解释牌都没有的亚洲的瓷器,伊斯兰的地毯或者是文艺复兴时期的版画都变得温吞无味。与曾经为设计学院教学所用的雕塑和古建的仿制品一起,莫名的给人一种廉价的气息。

\r\n

V&A 的声誉一度下滑,游客寥寥。

\r\n

但正如这所博物馆在 19 世纪下半叶的成长节奏,它还在想办法求变。这也正是这个馆有意思的地方。

\r\n

无论是 1951 年举办英国节(Festival of Britain),还是 1973 年为吸引年轻人而在博物馆里举办摇滚演唱会和相关宣讲会(演唱会请的是 70 年代当红前卫 - 乡村 - 摇滚乐队 Gryphon 狮鹫,不知为什么听他们的歌就想玩冒险岛),都表达着博物馆的不懈努力。而到了 20 世纪 80 年代,博物馆董事罗伊·斯特朗做出了一次很重要的调整,他认为既然自己这家博物馆强调的是艺术和设计,那为什么不从博物馆本身就好好的表现出来呢?这看似理所当然的事情实际上却让 V&A 的求变方向在此之后豁然开朗。博物馆的名字也变更为The Victoria and Albert Museum, the National Museum of Art and Design(维多利亚&阿尔伯特博物馆——国立艺术设计馆)。 世界上最大的专注于艺术和设计的博物馆慢慢浮出水面。一个以厚重背景为骨架拥抱现代化技术和优秀观展体验的博物馆逐渐成型。

\r\n

到了 2012 年,年游客人次达到三百二十万,虽然只是大英博物馆的一半,但却很容易让到访者在两馆中有些互有胜负的比较。甚至单说室内陈设这一点,V&A 应该是不输于前者的。

\r\n

\"\"

\r\n

(V&A 里中世纪和文艺复兴时期雕塑展廊)

\r\n

更重要的是,V&A 又从 2000 年开始经历着一个预期二十年的进化——FuturePlan而这一次有意启用年轻设计师担当改造主角,又同时强调与原博物馆文化融合的计划有着不少亮点。虽不能一股脑罗列下来,但是可以稍微摘出几个来推荐,也许下次知乎上的朋友去的时候可以着意看一看。

\r\n

\"\"

\r\n

先从主要观展的一二层来说,由图底中部标号为 10 的主入口进入 V&A,穿过南向主立面上突出塔楼下的穹顶就会到达图上回字形的区域,此处是咨询和售票的前台(V&A 内大部分永久展馆都是免费进入但是有些特殊和时效的展览就需要购票)。咨询台向右就是之前给出照片的中世纪和文艺复兴的展廊,陈设和采光都很不错。往里走还能去到 Simon Sainsbury Gallery,很有些老房子的家伙什,被巧妙地展示在这里。

\r\n

\"\"

\r\n

而,从咨询台像左走,进入的这个小馆就总是承接一些新锐设计师或团队的展示。比如前些年意气风发的 Thomas Heatherwick 在那办的展。

\r\n

\"\"

\r\n

接着是从咨询台向北走,黄色框框内(4 号区)的中东伊斯兰文化馆是围绕一块 10.5m*5m 的波斯地毯打造的,这块地毯就是楼上有朋友提到的阿尔比勒地毯,可我的映像里,这世界唯二的地毯一直是在 V&A 内保存(另一块在洛杉矶),因为一直找不到合适的布展而无缘和公众见面,之前 BBC 一个节目,现任负责人当着兴奋的主持人的面让人展开了这张地毯,并大度地说你可以站上来,如果你愿意(她的意思是站在保护地毯侧边的布套上),结果主持人差点一脚踩在地毯上,负责人整个脸都绿了。。。下一个画面就直接跳到主持人老老实实站在边缘外……

\r\n

\"\"

\r\n

(如今好歹这个地毯可以让民众看见了)

\r\n

老实说,一二楼我到现在还没有走全。除了图上特意标记出的红色虚线的 11(展示服装时尚,看铅笔拿不稳的小学萝莉簇拥在华丽的宫廷服装前把蕾丝婚纱画成一把韭菜也是让我醉了)以及蓝色虚线的那块外(此处常承办收费的展览,且规格很高,比如 2013 年的中古古代绘画名品 700-1900 展)还可以去 Cast Courts 转转。虽然都是以前教学用的仿制品,但是有的东西看起来还是很有意思,比如这根顶天立地大柱子,哈。

\r\n

\"\"

\r\n

(1:1 Trajan's Column,因为太大所以切成两半放着……)

\r\n

大柱子的坐标?图上标记的圆圈便是。

\r\n

再然后“服装潮流风尚馆”的北面 13 号区域之前一直是 V&A 靠近展览馆路的一个室外边庭,但是将承载一个重要的扩建项目,可以结合 -1 层来说~

\r\n

\"\"

\r\n

历史建筑扩建项目里,做地下扩建是常用的手法。V&A 的 -1 层(此处的 Level 0)就有一个这样的扩建(西侧,左边虚线框中的 7 号区域,延伸地下 15 米并连接现有的博物馆地铁入口)

\r\n

\"\"

\r\n

\"\"

\r\n

这个 4200 万英镑的扩建由 AL_A 事务所设计,预计 2016 年完工。现在去的话还是这个样子:

\r\n

\"\"

\r\n

另一方面,在负一层的空间里,有一个我十分好奇的女厕所……

\r\n

在 Grand Entrance(就是建筑南部中间的入口)进来,顺着侧面的楼梯下到负一层,男女厕所分列两旁,而女厕所这边由瑞士艺术家 Felice Varini 和博物馆设计团队一同打造,颇有视觉趣味。

\r\n

\"\"

\r\n

放弃窥伺女厕,而往上走的话,也许对建筑学专业的同学比较有吸引力。第三层南遍右侧是建筑馆,设计了各个年代的大量模型,有些老做法也很能启发人。而西北的独立 8 号区是皇家建筑协会的档案馆,不过大概不对外开放,需要以研究院的身份去申请进入。

\r\n

\"\"

\r\n

不过瘾的话还可以再上一层(有错层),图上标记为绿色的长廊,收集了不少家具,是家具设计的展览空间 The Dr. Susan Weber Gallery,从 1420 年代的书桌到现代的橱柜都有展示,据说负责这一块改造的 NORD Architects 还有些利用数字技术的小巧思,等他弄完了,也许可以一看。

\r\n

\"\"

\r\n

展品存量很有诚意的博物馆往往比较头疼于如何让参观者在繁多的信息量中不致疲劳。V&A 也许在提供他们摸索的经验,趁着这个馆还没有像大英博物馆那么人挤人, 抓紧时间去一下挺好的。除了海量的藏品,安静的博物馆也有不少可以打盹的地方,若是想满足一下自己透着点粉红色的文艺小心思,这个“世界首家博物馆餐厅”也可以去光顾一下哦~

\r\n

\"\"

\n
\n
\n\n\n\n\n
\n\n\n
\n
", 3 | "image_source": "Yestone.com 版权图片库", 4 | "title": "去伦敦,别错过世界上最大的专注于艺术和设计的博物馆(多图)", 5 | "image": "http://pic1.zhimg.com/2f9848d2817ef94b3cb987d7883ba9ac.jpg", 6 | "share_url": "http://daily.zhihu.com/story/4770416", 7 | "js": [ ], 8 | "ga_prefix": "053010", 9 | "type": 0, 10 | "id": 4770416, 11 | "css": [ 12 | "http://news.at.zhihu.com/css/news_qa.auto.css?v=1edab" 13 | ] 14 | } 15 | -------------------------------------------------------------------------------- /SwiftDailyAPITests/JSON/news_4820022.json: -------------------------------------------------------------------------------- 1 | { 2 | "body": "
\n
\n\n\n

就这样面对爱人的糟糕情绪

\n\n\n\n\n
\n\n
\n\n\n\n
\n

如何面对爱人的糟糕情绪

\n
\n\n
\n\n冯丹彤,精神分析师、长程动力取向心理治疗师\n
\n\n
\n

当你为家人准备晚餐,经过一两个小时的忙碌,一切就绪,爱人却带着一脸的沮丧推开家门;当你下班后开心而着急地赶往和爱人约好的商场,但在门口见到他时,他却烦不可耐地质问“你怎么才来?”

面对这些情绪冲击时,你会如何化解自己的情绪、如何帮助对方、帮助彼此走出负向的情绪互动呢?

深层心理学有一个说法:潜意识中,伴侣需要用来处理负性的情感体验。这句话可以从两方面理解:

一方面,是自己潜在地寻找一个可以承载自己对于家庭的渴望与理解的“理想对象”,他/她甚至某些层面会像自己的父母,或者原来家庭中的某个成员。但是在新的亲密关系里,肯定有一些特别的地方,是自己很不满意的、渴望对方去改变的。借着排斥对方的某些性格特质、生活习惯,试图让自己不再感到曾经在原生的家庭里难以承受的感觉。

另一个方面,成为对方的伴侣和爱人,某个层面就在扮演对方情绪的蓄水池的角色。对方情绪太汹涌了,就需要为对方暂时“蓄水”,而对方情绪麻木、没有新鲜感时,又需要为对方注入“活水”,让彼此互动起来。这种角色成为一种使命、一种重要性的体现。

这样来看,两种状态都不那么轻松,那么当对方或彼此的互动处于情绪糟糕的情况下,其中情绪的承担者应该注意些什么,能够实现情绪的调节、达成负性情绪体验的代谢呢?

英国的心理学家温尼科特提出一个理论:在人际互动中构建“抱持性环境”,有助于心灵的疗愈和成长。大意是,当一个处于情感受挫、需要帮助的人如果能遇到情感的支持、理解,对于这个暂时“孩子气”的人去发泄情绪、调节人际关系的尝试,能给予宽容和关怀,那么这个人会通过一段时间的调整,会从焦虑、抑郁以及愤怒中走出来,而且心灵会因为这种环境的照顾而获得成长。这个环境就称为抱持性环境。

温尼科特的这个观点被广泛地应用于心理咨询、儿童教育、医疗,乃至商业协商等领域。因为从实践中大家发现,抱持性的环境的实施并不需要高昂的建设费用、不需要特别复杂的受训背景。那么如果应用到家庭里,在亲密关系中又需要做到什么,才能具备“抱持”的特点、成为抱持性环境呢?

第一、不否认、不拒绝对方当下的情绪

以开头为例,虽然你在家很辛苦的准备了晚餐,但是爱人情绪确实正处于低落的状态,那么,不要否认他/她的情绪“没什么”、“过会儿就好了”,也不要责怪对方“有”当下的情绪。试着理解对方真实地处于一种不太舒服的情绪中,去关注到他/她当下的情绪体验,去接纳这种情绪的存在。试着去询问:“看起来,你有些情绪不好,是不是愿意和我谈一谈呢?”

第二、不要主观推断和妄想,而试着去问一问真实的情况

“他肯定是在单位被领导骂了,要拿我撒气;或者嫌我昨晚没有给他手机充好电,借题发挥呢;或者惩罚我今早出门前收拾东西动作慢,让他着急忙慌地往单位赶····· ”。当我们处于这种主观想象和心理的封闭状态时,很难看到对方真实的感受与状态。最好的办法,是温和地问问:“刚才等着急了?怎么好像带着情绪呢?”也许这的确有些难——面对对方给予的情绪压力,还要放下自己,而先关注对方——但是,蓄水池,就是需要暂时地承担一下对方汹涌而来的情绪。而一旦他的情绪平静下来,对方会心存感激,彼此关系也会增进、关系的耐受性也会提高。

第三、耐心的倾听与情感的关注

在自己能放下想象,而关注于对方的真实后,对方往往会有故事要讲,这时,耐心听着就好。然后把听到的情感,反馈给他,也许那正是他缺少理解和关注的,因为他是“当局者迷”。比如他会说:“这个月业绩不好,而且不是我不好,是小组的不好,所以我是被牵连者,这个恼人的业绩考核方式,团队能达到时,大家都开心;可是我个人做得足够好,反因为他人的情况而拖累时,真是别扭······”。尽量不打断他,即使他说的极端、偏颇,乃至不很理性都不要紧,最关键是他要讲一讲受挫的感受,而你的陪伴是一种巨大的安慰与关怀。等他讲完,可以试着简短地反馈他的情绪,“听起来,你自己能达到目标,本来是很值得开心的,但是因为所在小组其他成员的问题,影响到了你,所以你很失望、还有一些责怪他们。因为好的时候看不出来,出现问题时,你是无辜的受害者。这让你很不舒服。现在跟我说说,有没有感觉好一些了?”

第四、为对方的体验增加正向的解读

当对方的情绪得到照顾,逐渐恢复平静时,如果你能发现他“钻牛角尖”的思路、想法,而且你能提供更建设性的理解,可以尝试告诉他,毕竟你“旁观者清”。比如“我觉得你既然自己可以达标,试着把自己的经验分享出去,让大家和你一起优秀,要比你这样责怪他们更能解决问题,毕竟你们之前团队合作还是挺好的。也许是最近的工作中,他们需要一些帮助呢?也许大家这时候也挺不好意思的,牵连了你,你要是能挺身而出,大度一些,也许以后就再不发生,也算亡羊补牢了。兴许大家因此而更欣赏你的组织能力、专业能力”。在每一个情绪背后,都会有个人乃至团队的意义,有时候,情绪体验过于痛苦,让当事人难以承受,所以暂时看不到、看不清楚。

第五、当对于总在重复体验一些情结时,建议他接受专业咨询帮助

“情结”是心理学家荣格总结出来的概念,意思是,每个人都有一些固定或者容易发展的倾向,即使与现实发生冲突,也很不容易调整,或者很难从自我反思中走出来。但是,这种情结与现实的不协调往往造成持久的痛苦与矛盾体验。假如你的爱人总在重复体验着某项情绪,难以有效地调节,可以推荐他接受专业的心理咨询。当然首选注重内心体验的精神分析取向咨询。

\n\n

———————————————

\n

发自知乎专栏「冯丹彤

\n\n
\n
\n
\n\n\n
\n
", 3 | "title": "就这样面对爱人的糟糕情绪", 4 | "recommenders": [ 5 | { 6 | "avatar": "http://pic1.zhimg.com/0a6456810_m.jpg" 7 | } 8 | ], 9 | "share_url": "http://daily.zhihu.com/story/4820022", 10 | "js": [ ], 11 | "theme": { 12 | "thumbnail": "http://pic3.zhimg.com/0e71e90fd6be47630399d63c58beebfc.jpg", 13 | "id": 13, 14 | "name": "日常心理学" 15 | }, 16 | "ga_prefix": "062318", 17 | "type": 0, 18 | "id": 4820022, 19 | "css": [ 20 | "http://news.at.zhihu.com/css/news_qa.auto.css?v=811bb" 21 | ] 22 | } -------------------------------------------------------------------------------- /SwiftDailyAPITests/JSON/news_4859444.json: -------------------------------------------------------------------------------- 1 | { 2 | "body": "
\n\n\n
\n\n\n\n
\n

1997年NBA状元,蒂姆-邓肯,时代如何开始

\n
\n\n
\n\n张佳玮,微信公众号:张佳玮写字的地方\n
\n\n
\n

1996 年春天,大卫 - 罗宾逊对乔丹提出了一点质疑。

\r\n

“我不知道迈克尔在做什么。他为什么要复出?他有个美丽的妻子,有三个孩子,他还想证明些什么自己没证明过的事儿吗?他不是已经证明过他是我们所见过最好的球员了吗?我们知道啊。在我看来,他是在追着自己的尾巴。为什么他就不能享受和自己家庭的时光呢?”

\r\n

也许,这就是大卫 - 罗宾逊和迈克尔 - 乔丹的不同。他是个绅士,是个完美公民,但他不能理解乔丹那种人:那种不顾一切想要更多胜利的偏执狂。

\r\n

但罗宾逊依然是圣安东尼奥马刺不可或缺的王牌。1996-97 季,因为背伤,罗宾逊缺席了赛季开始的六周比赛,马刺 3 胜 15 负。背伤好了,罗宾逊复出,随即左脚又伤了。实际上,那个赛季,马刺的伤病简直流行如瘟疫:罗宾逊、查克 - 佩森、查尔斯 - 史密斯和埃利奥特合计缺阵了 264 场比赛。

\r\n

于是,当时已经是球队总经理的波波维奇,把主教练鲍勃 - 希尔炒掉,自己亲自上任了。

\r\n

从此,波波维奇时代,正式开始——虽然这个开头,实在不大好。

\r\n

马刺以 20 胜 62 负结束了 1996-97 季常规赛。

\r\n

他们上一次这么糟糕,还是 1988-89 季。众所周知,那之后,他们迎来了大卫 - 罗宾逊这个救世主。1997 年这次呢?

\r\n

1997 年 1 月 29 日,在另一个不叫做 NBA 的世界里,NCAA 的沃夫德大学即将对阵威克森林大学。比赛前夜,沃夫德的教练理查德 - 约翰逊对队员们说:

\r\n

“我来告诉你们明天即将对垒的是谁,那是威克森林大学的蒂姆 - 邓肯,将来有一天,你们的六岁小孩会问你们要一件邓肯的球衣当圣诞节礼物的。这是你们对垒一个未来 NBA 名人堂成员的机会。这是你们这辈子能对垒的,最伟大的球员。”

\r\n

这是那个,在八年前,放弃了游泳,开始打篮球的,美属维京群岛的蒂姆 - 邓肯。

\r\n

很多年后,威克森林大学的主教练戴夫 - 奥多姆先生还是不时后怕:他曾因为观察不细致,险些与一个伟大球员失之交臂。那是 1992 年,奥多姆先生被请去看一场五对五的友谊赛。“会有 1992 年 NBA 榜眼中锋阿朗佐 - 莫宁哟”。奥多姆教练来了,希望找到他一直需要的,“有运动能力的,喜欢在篮筐附近打球的大个子”。

\r\n

然后他看见了一个 16 岁的大个子。哎?那个小子似乎不错的样子?他是哪来的?维京群岛?那是什么地方?那里的人可知道,篮球和椰子的区别?

\r\n

——奥多姆教练去和蒂姆 - 邓肯搭话,结果大失所望。这个大个子低头看着他,嘴唇紧抿,双目圆睁。既不像是生气,又不像是高兴。他看待奥多姆的表情中,唯一能够辨析的是好奇——一条小狗初次看到螳螂那种表情。等好奇心衰减后,他停止了对奥多姆的观察,表现出一副“如果我对你的话表示不在意,你不会生气吧”的模样。嘿,这个精神不集中的小子,他知道我在说什么吗?如果不是因为他的个子和宽肩,我干嘛浪费这么多时间?

\r\n

幸好之后,奥多姆教练又和邓肯交谈了一次,于是发觉先前的认识是错误的。这孩子逻辑清晰,思维敏捷,而且居然还会说点冷笑话。经常魂不守舍般发呆?那是他关注的方式。他不仅是运动天才,而且理解能力惊人。

\r\n

于是定了:1993 年夏天,邓肯带着一张没有表情的脸,去到了威克森林大学。连他那对尖尖的、酷似撒旦的耳朵,都像是为这个队名——威克森林大学魔鬼执事队——准备的。

\r\n

就在离开维京群岛的那个夏天,在后院的单挑中,他终于击败了姐夫里基 - 罗瑞——虽然罗瑞一直相信,邓肯早就可以击败他了。

\r\n

“他是一直故意让着我的。”

\r\n

邓肯是个岛上来的孩子,理所当然,会被人到处问。比如:

\r\n

“你身上这些衣服,都是岛上穿来的吗?”

\r\n

“不。是我到了这里买的。”

\r\n

他也会问队友,比如他跟队友柴尔兹的对话。

\r\n

“你家在哪儿?”

\r\n

“DC。”

\r\n

“DC 是哪儿?”

\r\n

“DC 就是华盛顿 DC 的缩写呀。”

\r\n

“那又是哪儿?”

\r\n

“……那是国家首都,是总统住的地方。”

\r\n

但无所谓,邓肯很快就让全美国记住他了。1995 年他读到大二,NBA 金州勇士队的总经理戴夫 - 特瓦基克已经说了,“当下大学篮球第一人是蒂姆 - 邓肯。没人接近他。”

\r\n

他用了 51 场比赛就创下了学校历史盖帽记录。大二他场均 16.8 分 12.5 个篮板。柴尔兹说起他第一次看邓肯打球时,依然会两眼发直:

\r\n

“他抓到后场篮板,一个胯下运球变向,推进到前场,然后像组织后卫那样传球!”

\r\n

那会儿,邓肯已经有 208 公分了。

\r\n

1996 年读完大三,邓肯场均 19 分 12 篮板 3 助攻 4 封盖,甚至还偶尔投投三分球。全 NBA 都在等他,但他还是决定继续在威克森林大学读大四,拿到心理学学士学位。这意味着,整个大学篮球界得继续多做一年噩梦。

\r\n

弗吉尼亚的教练巴特 - 贝莱尔说他在对阵邓肯前,做过这么个梦:他运着球穿过一个超市,看见个垃圾桶,他想把球投进垃圾桶里,但邓肯忽然出现,把球盖掉了。一次,两次,三次,邓肯毫不费力、略无表情地拒绝了每次投篮。贝莱尔教练记得日期:1996 年 11 月 24 日,凌晨 3 点 28。那天稍后,弗吉尼亚确实被威克森林大学摧毁了:92 比 63。贝莱尔教练说:

\r\n

“邓肯,一如我梦里一样,没允许任何人接近篮筐。”

\r\n

在邓肯对阵密苏里,拿到 18 分 20 个篮板 4 助攻 3 封盖后,密苏里的前锋德雷克 - 格力姆如是形容那种噩梦之感:

\r\n

“好像每次你回头看,邓肯都在盯着你。我简直要发誓,有五个邓肯在场上。”也就在这一晚,邓肯的盖帽数超过了前乔治城大学的铁血中锋阿朗佐 - 莫宁:他成了大学篮球史上盖帽第二人。然后,他很顺利的登了顶。实际上,不只是盖帽出色,整个大四赛季,他场均 21 分 15 篮板 3 助攻 3 封盖,投篮命中率是可怖的 61%。

\r\n

而且,他冠绝天下的封盖,只是他防守的副产品。所有教练众口一词的承认:邓肯的防守一点都不像其他盖帽大师那么劲爆,而是早熟沉稳。他的移动步伐,他的判断和意识,每一记封盖都不让人激动,而是水到渠成,仿佛在说“我早就计算到位了”。他几乎没有弱点。他就是个魔鬼。

\r\n

那年,凯文 - 拉尚斯的球探报告如是说:

\r\n

“邓肯是 1997 年选秀大会上最好的球员,肯定锁定状元;他有机会成为 NBA 的超级巨星……他可能成为一个统治级的大前锋,但他拥有成为统治级中锋的天分……有人把他和大卫 - 罗宾逊相比,但大梦可能更接近:他们有相似的灵活性和身高……邓肯有长臂和出色绝伦的时机判断,步伐和低位技巧则在持续不停的进步……他有全套的技巧:能以各种方式得分,能在低位单打,也能翻身跳投。他也能在外围中投。作为他这样尺寸的球员而言,他的传球技巧简直匪夷所思。他比绝大多数内线球员运球都要出色……而他最棒的地方还是其完美的防守。”

\r\n

而杜克大学的德尔曼的球探比较简洁,主要是这句话:

\r\n

“如果你不是每晚都看他打球,你无法欣赏他的美妙所在。”

\r\n

为什么呢?威克森林大学的奥多姆教练解释了:

\r\n

“我不太想把邓肯跟以前的伟大中锋做比较,只是,如果你在找一个每晚都稳定打出 A 级状态的无畏勇士,你很难找到比邓肯更好的了。”

\r\n

更重要的:

\r\n

“我相信每个球员,包括作为教练的我,都抱着为邓肯而战的心思打每场比赛。我们不想让邓肯失望。我们无比欣赏他为我们所做的一切。而且,他可是放弃了去 NBA 当百万富翁的机会,留下来打大四赛季的。”的确,1996 年如果邓肯进 NBA,会稳稳拿到三年 938 万美元的合同。

\r\n

他是个好球员,与此同时,他还是个好队友。

\r\n

邓肯自己,被问到“大三时你已经是全国第一阵容加 ACC 年度防守球员,为什么不选择早一年进 NBA 呢?那样可以多挣起码 300 万美元”时,如此慢条斯理的回答:

\r\n

“我推荐您看《揠苗助长》(《The Hurried Child》)。那本书教了我许多道理。”

\r\n

他从来不着急。 所以,大四的辉煌赛季,包揽各类全国最佳球员奖项时,邓肯自己也只是平静地看待这一切。

\r\n

“等我到五十岁,我会坐在加勒比海上一艘摩托艇上,想一想今年发生的一切——然后我就继续了。”

\r\n

1997 年春天,命运再度对圣安东尼奥微笑:因为罗宾逊的伤势,马刺常规赛只有 20 胜 62 负,他们有 21.4%的概率得到 1997 年 NBA 状元签——当然,波士顿凯尔特人的概率更高,常规赛 15 胜的他们有高达 36.3%的概率得到状元签。在 1997 年春天,状元签意味着邓肯……然后,马刺抽到了状元签。1987 年,他们得到了状元签,然后拿下了罗宾逊;十年之后,他们又赶上了好运气。

\r\n

有一个多年后已被许多人遗忘的细节:

\r\n

拿到状元签后,圣安东尼奥人民开始讨论,要不要选邓肯呢?在其他城市,这自然不算是问题,但圣安东尼奥人民考虑得很远:

\r\n

我们已经有了罗宾逊了,还需要一个据说跟他很类似的巨人吗?当地的一个报纸上,有 30%的市民表示,他们想要的不是邓肯,而是凯斯 - 范霍恩。那是犹他大学的大前锋,208 公分的白人,唱诗班少年一般的脸,袜子总是束到膝盖,从踏进大学第一年就是超级得分手,大四的时候场均 22 分 10 篮板 1 助攻,射程远到三分线外,号称“拉里 - 伯德二世”——实际上,范霍恩可能是第一个被拿来跟 NBA 史上最伟大白人球员伯德做接班人的家伙。在一部分圣安东尼奥人民看来,他和罗宾逊更般配些。

\r\n

当然,最后,圣安东尼奥马刺平静地做了选择:1997 年 NBA 选秀大会,他们用手持的状元签摘下了蒂姆 - 邓肯。在掌声中,穿着米色西装的邓肯羞涩的微笑着,站起身来;然后,现场直播的镜头转到了做出这一决定的马刺主教练波波维奇身上——那天他穿着件蓝色 T 恤,正绷着脸;发现镜头对着他时,波波维奇才尴尬的笑了笑。那个样子,仿佛他并不为此太高兴似的。屏幕下方打出了以下字样:

\r\n

1997 年状元蒂姆 - 邓肯。

\r\n

威克森林大学 21 号球员。

\r\n

211 公分,113 公斤。

\r\n

优点:出色的内线技术;全面的球员。

\r\n

弱点:罚球。

\r\n

大部分圣安东尼奥人民欢乐地接受了这个事实,还有小部分球迷则略带叹惋地看着新泽西网摘走了范霍恩。他们当然都不知道,时代的脉搏,开始悄然启动了。

\r\n

而且至今没有停止。

\r\n

本文来自新书《蒂姆 - 邓肯:永不退场》(暂时是这个名字)的第三章。

\r\n

嗯,就是我以前提过的马刺史那本书。

\r\n

全书三十三章。此刻正在配插图。

\r\n

正常的话,八月出。

\n\n

———————————————

\n

发自知乎专栏「张佳玮写字的地方

\n\n
\n
\n
\n\n\n
\n
", 3 | "title": "如果你不是每晚都看他,就无法欣赏他的美妙所在,这就是邓肯", 4 | "image": "http://pic4.zhimg.com/eaef9d00f8ebaba036f0a22679f36f83.jpg", 5 | "share_url": "http://daily.zhihu.com/story/4859444", 6 | "js": [ ], 7 | "ga_prefix": "071209", 8 | "type": 0, 9 | "id": 4859444, 10 | "css": [ 11 | "http://news.at.zhihu.com/css/news_qa.auto.css?v=811bb" 12 | ] 13 | } -------------------------------------------------------------------------------- /SwiftDailyAPITests/JSON/news_extra.json: -------------------------------------------------------------------------------- 1 | { 2 | "popularity": 100, 3 | "short_comments": 200, 4 | "long_comments": 300, 5 | "comments": 500 6 | } -------------------------------------------------------------------------------- /SwiftDailyAPITests/JSON/news_extra_4770416.json: -------------------------------------------------------------------------------- 1 | { 2 | "long_comments": 0, 3 | "popularity": 697, 4 | "short_comments": 10, 5 | "comments": 10 6 | } -------------------------------------------------------------------------------- /SwiftDailyAPITests/JSON/news_meta.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": 12345, 3 | "title": "Title of the News", 4 | "images": [ 5 | "http://httpbin.org/image/jpeg" 6 | ], 7 | "type": 0, 8 | "ga_prefix": "67890" 9 | } 10 | -------------------------------------------------------------------------------- /SwiftDailyAPITests/JSON/news_meta_with_a_theme.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": 12345, 3 | "title": "The Title of the News", 4 | "images": [ 5 | "http://httpbin.org/image/jpeg" 6 | ], 7 | "theme": { 8 | "id": 1, 9 | "name": "The Name of the Theme" 10 | "subscribed": false, 11 | }, 12 | "type": 2, 13 | "ga_prefix": "67890" 14 | }, 15 | -------------------------------------------------------------------------------- /SwiftDailyAPITests/JSON/objectFromFile.swift: -------------------------------------------------------------------------------- 1 | // 2 | // objectFromFile.swift 3 | // SwiftDailyAPI 4 | // 5 | // Created by Nicholas Tian on 12/01/2016. 6 | // Copyright © 2016 nickTD. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import Argo 11 | 12 | func objectFromFile(filename: String) -> T? { 13 | let value = JSON.parse(JSONFileReader.JSON(fromFile: filename)!) 14 | 15 | return T.decode(value).value 16 | } 17 | -------------------------------------------------------------------------------- /SwiftDailyAPITests/JSON/short_comments_4772308.json: -------------------------------------------------------------------------------- 1 | { 2 | "comments": [ 3 | { 4 | "author": "JustEnjoy", 5 | "content": "白水煮,毫无疑问。越简单的做法越健康。", 6 | "avatar": "http://pic3.zhimg.com/968f149d8b75c49aa6a67516bc809ec6_im.jpg", 7 | "time": 1433132865, 8 | "reply_to": { 9 | "content": "那么问题来了?鸡蛋怎么吃最营养?换句话说鸡蛋怎么做,身体吸收最好?生吃?煮?煎?请答主回答", 10 | "status": 0, 11 | "id": 1137335, 12 | "author": "文天宏" 13 | }, 14 | "id": 1137466, 15 | "likes": 0 16 | }, 17 | { 18 | "author": "文天宏", 19 | "content": "那么问题来了?鸡蛋怎么吃最营养?换句话说鸡蛋怎么做,身体吸收最好?生吃?煮?煎?请答主回答", 20 | "avatar": "http://pic4.zhimg.com/17c67db07_im.jpg", 21 | "time": 1433127620, 22 | "id": 1137335, 23 | "likes": 0 24 | }, 25 | { 26 | "author": "她的嘴唇有点甜", 27 | "content": "同健身,刚开始还吃鸡蛋,吃了一个月实在是腻了,现在就一周一个蛋了,平常喝牛奶", 28 | "avatar": "http://pic1.zhimg.com/bf5fea3cdfbb068acd39c29ab8aa5964_im.jpg", 29 | "time": 1433127102, 30 | "reply_to": { 31 | "content": "在健身,每次练完12个蛋白,2个蛋黄,隔天吃感觉还好……其实小时候一个蛋白也吃不进去,不过为了肌肉我也是蛮拼的,现在觉得蛋白挺好吃的。另外我研究过一个蛋白大概也就3~4g蛋白质,所以10个也不多,而且考虑到蛋黄的热量太高,所以我觉得对于健身者来说,蛋白的价值大于蛋黄,以上仅是个人观点。", 32 | "status": 0, 33 | "id": 1136041, 34 | "author": "AIR卡比" 35 | }, 36 | "id": 1137322, 37 | "likes": 0 38 | }, 39 | { 40 | "author": "南瓜酱ww", 41 | "content": "我能整个蛋黄吞进去😳基本上入口即化😉唾液比较犀利哈哈", 42 | "avatar": "http://pic1.zhimg.com/a866d9e427233656033d9da301500fa4_im.jpg", 43 | "time": 1433126366, 44 | "reply_to": { 45 | "content": "小时候讨厌吃蛋黄 感觉好粉好噎 现在勉强能吃一个………然而 这基因遗传给我儿子了 他现在也不吃蛋黄😓😓", 46 | "status": 0, 47 | "id": 1136141, 48 | "author": "1341941650" 49 | }, 50 | "id": 1137303, 51 | "likes": 0 52 | }, 53 | { 54 | "author": "南瓜酱ww", 55 | "content": "白煮蛋蘸酱油,谁吃谁知道!高中的时候被同学打开了新世界的大门 不过依然喜欢白煮蛋", 56 | "avatar": "http://pic1.zhimg.com/a866d9e427233656033d9da301500fa4_im.jpg", 57 | "time": 1433126168, 58 | "reply_to": { 59 | "content": "为什么会有人不吃蛋黄或蛋白 水煮蛋沾酱油不是挺好吃么", 60 | "status": 0, 61 | "id": 1136796, 62 | "author": "RED-MOMO" 63 | }, 64 | "id": 1137298, 65 | "likes": 0 66 | }, 67 | { 68 | "author": "南瓜酱ww", 69 | "content": "看评论才知道大家这么能吃鸡蛋👍", 70 | "avatar": "http://pic1.zhimg.com/a866d9e427233656033d9da301500fa4_im.jpg", 71 | "time": 1433126031, 72 | "id": 1137294, 73 | "likes": 0 74 | }, 75 | { 76 | "author": "Tumbleweed-", 77 | "content": "4年前为了营养,每天的蛋炒饭里还配两个整蛋。吃了3个月。在次年的体检中发现身体有很小的胆囊息肉,被告知是胆固醇过高。本人183cm,体重较轻,只有130。现在吃全蛋都不敢吃蛋黄。", 78 | "avatar": "http://pic3.zhimg.com/d1cabff65a5d02b34e97df430139abaa_im.jpg", 79 | "time": 1433123337, 80 | "id": 1137227, 81 | "likes": 0 82 | }, 83 | { 84 | "author": "AIR卡比", 85 | "content": "呃……羞愧……扔掉……", 86 | "avatar": "http://pic4.zhimg.com/6bfe457b7_im.jpg", 87 | "time": 1433122794, 88 | "reply_to": { 89 | "content": "剩下的十个蛋黄怎么处理的", 90 | "status": 0, 91 | "id": 1137071, 92 | "author": "楠楠酱0919" 93 | }, 94 | "id": 1137215, 95 | "likes": 0 96 | }, 97 | { 98 | "author": "大碗米饭", 99 | "content": "黄鼠狼是吃鸡吧,蛋也吃?", 100 | "avatar": "http://pic1.zhimg.com/90217e674d74e53f934def4c036516f0_im.jpg", 101 | "time": 1433121219, 102 | "reply_to": { 103 | "content": "谁天天吃那么多鸡蛋干嘛啊,黄鼠狼附身了?", 104 | "status": 0, 105 | "id": 1136787, 106 | "author": "指尖上的芭蕾_" 107 | }, 108 | "id": 1137169, 109 | "likes": 0 110 | }, 111 | { 112 | "author": "中药草", 113 | "content": "长时间下去你会吃腻的", 114 | "avatar": "http://pic1.zhimg.com/da8e974dc_im.jpg", 115 | "time": 1433119679, 116 | "id": 1137119, 117 | "likes": 0 118 | }, 119 | { 120 | "author": "中药草", 121 | "content": "麦丽素!", 122 | "avatar": "http://pic1.zhimg.com/da8e974dc_im.jpg", 123 | "time": 1433119627, 124 | "id": 1137115, 125 | "likes": 0 126 | }, 127 | { 128 | "author": "扎古的左眼", 129 | "content": "胆固醇不是分为两种吗?一种是高密度胆固醇,一种是低密度的。而高密度是对人体有益的。那么鸡蛋里的胆固醇是哪种呢?另外,外国有人亲自做了实验,每天吃好多鸡蛋,吃一个礼拜。然后检测发现胆固醇水平并无多大差异", 130 | "avatar": "http://pic4.zhimg.com/01d9e29ae2ff6c4f973a5a7c7b93a73b_im.jpg", 131 | "time": 1433119229, 132 | "id": 1137103, 133 | "likes": 0 134 | }, 135 | { 136 | "author": "中药草", 137 | "content": "完全没有问题", 138 | "avatar": "http://pic1.zhimg.com/da8e974dc_im.jpg", 139 | "time": 1433119120, 140 | "reply_to": { 141 | "content": "据说鸡蛋是发物,癌症病人不可以吃。楼主怎么看?", 142 | "status": 0, 143 | "id": 1136154, 144 | "author": "蓬蓬家家" 145 | }, 146 | "id": 1137097, 147 | "likes": 0 148 | }, 149 | { 150 | "author": "中药草", 151 | "content": "你应该用其它方法", 152 | "avatar": "http://pic1.zhimg.com/da8e974dc_im.jpg", 153 | "time": 1433118994, 154 | "reply_to": { 155 | "content": "为什么我吃了那么多蛋,鱼蛋,鱿鱼等等,胆固醇值却还是偏低?我该怎么办?", 156 | "status": 0, 157 | "id": 1136282, 158 | "author": "MR阿璐哥哥" 159 | }, 160 | "id": 1137091, 161 | "likes": 0 162 | }, 163 | { 164 | "author": "楠楠酱0919", 165 | "content": "剩下的十个蛋黄怎么处理的", 166 | "avatar": "http://pic1.zhimg.com/6a2199deedcf79f0206d06b597211770_im.jpg", 167 | "time": 1433118506, 168 | "reply_to": { 169 | "content": "在健身,每次练完12个蛋白,2个蛋黄,隔天吃感觉还好……其实小时候一个蛋白也吃不进去,不过为了肌肉我也是蛮拼的,现在觉得蛋白挺好吃的。另外我研究过一个蛋白大概也就3~4g蛋白质,所以10个也不多,而且考虑到蛋黄的热量太高,所以我觉得对于健身者来说,蛋白的价值大于蛋黄,以上仅是个人观点。", 170 | "status": 0, 171 | "id": 1136041, 172 | "author": "AIR卡比" 173 | }, 174 | "id": 1137071, 175 | "likes": 0 176 | }, 177 | { 178 | "author": "小戒_sin", 179 | "content": "好的,谢谢", 180 | "avatar": "http://pic3.zhimg.com/294482cc6_im.jpg", 181 | "time": 1433117250, 182 | "reply_to": { 183 | "content": "你该去知乎原文下问,或者私信作者,在日报可能看不到。", 184 | "status": 0, 185 | "id": 1136374, 186 | "author": "sai" 187 | }, 188 | "id": 1137007, 189 | "likes": 0 190 | }, 191 | { 192 | "author": "阿土", 193 | "content": "活到现在真是不容易啊╭(°A°`)╮", 194 | "avatar": "http://pic3.zhimg.com/9d88a438e_im.jpg", 195 | "time": 1433114871, 196 | "reply_to": { 197 | "content": "终于有一个我能回答的。我从小极度挑食,上大学之前的很长一段时间,主食就是鸡蛋,只吃鸡蛋、红烧肉和豆制品。注意,是红烧肉,排骨汤之类的都不吃。其他都不吃,包括所有的蔬菜、鸡鸭牛虾海鲜等等。每天大概12个鸡蛋最少,最多22个鸡蛋,现在食谱拓宽许多,但鸡蛋还是占重要位置,平均每天5个,体检一切ok。", 198 | "status": 0, 199 | "id": 1135990, 200 | "author": "冒凯" 201 | }, 202 | "id": 1136907, 203 | "likes": 0 204 | }, 205 | { 206 | "author": "洛金金", 207 | "content": "他们总是会说那都不如煮鸡蛋😵", 208 | "avatar": "http://pic4.zhimg.com/ba4132acb_im.jpg", 209 | "time": 1433114524, 210 | "reply_to": { 211 | "content": "吃摊鸡蛋炒鸡蛋鸡蛋羹鸡蛋汤呀!", 212 | "status": 0, 213 | "id": 1135800, 214 | "author": "春兮散人" 215 | }, 216 | "id": 1136887, 217 | "likes": 0 218 | }, 219 | { 220 | "author": "蓬蓬家家", 221 | "content": "可是营养不好又不能产生抢抵抗力抵御癌细胞呀", 222 | "avatar": "http://pic4.zhimg.com/2e9bae25b_im.jpg", 223 | "time": 1433114033, 224 | "reply_to": { 225 | "content": "发的食物我一直认为是营养太好,所以对癌症也营养太好……", 226 | "status": 0, 227 | "id": 1136555, 228 | "author": "任我慢慢行" 229 | }, 230 | "id": 1136863, 231 | "likes": 0 232 | }, 233 | { 234 | "author": "AIR卡比", 235 | "content": "呃……原谅我没说清楚……我是一天鸡蛋一天蛋白粉交换着吃😁", 236 | "avatar": "http://pic4.zhimg.com/6bfe457b7_im.jpg", 237 | "time": 1433109383, 238 | "reply_to": { 239 | "content": "我觉得这种情况可以直接吃乳清蛋白粉了", 240 | "status": 0, 241 | "id": 1136772, 242 | "author": "Enschede" 243 | }, 244 | "id": 1136809, 245 | "likes": 0 246 | } 247 | ] 248 | } 249 | -------------------------------------------------------------------------------- /SwiftDailyAPITests/JSON/top_news_meta.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": 12345, 3 | "title": "Title of the News", 4 | "image": "http://httpbin.org/image/jpeg", 5 | "type": 0, 6 | "ga_prefix": "67890" 7 | } 8 | -------------------------------------------------------------------------------- /SwiftDailyAPITests/Specs/DailyAPISpecs.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DailyAPISpecs.swift 3 | // SwiftDailyAPI 4 | // 5 | // Created by Nicholas Tian on 27/05/2015. 6 | // Copyright (c) 2015 nickTD. All rights reserved. 7 | // 8 | 9 | import Quick 10 | import Nimble 11 | import SwiftDailyAPI 12 | 13 | class DailyAPISpecs: QuickSpec { 14 | override func spec() { 15 | let timeout: NSTimeInterval = 20 16 | let api = DailyAPI(userAgent: "SwiftDailySpec") 17 | 18 | it("loads latest daily") { 19 | var latestDaily: LatestDaily? = nil 20 | 21 | api.latestDaily { latestDailyFromAPI in 22 | latestDaily = latestDailyFromAPI 23 | } 24 | 25 | expect(latestDaily).toEventuallyNot(beNil(), timeout: timeout) 26 | expect(latestDaily!.date).toEventuallyNot(beNil(), timeout: timeout) 27 | expect(latestDaily!.news).toEventuallyNot(beEmpty(), timeout: timeout) 28 | expect(latestDaily!.topNews).toEventuallyNot(beEmpty(), timeout: timeout) 29 | } 30 | 31 | it("loads daily news for a date") { 32 | var daily: Daily? = nil 33 | let date = NSDate.dateFromString("20150525", format: "yyyyMMdd")! 34 | 35 | api.daily(forDate: date) { dailyFromAPI in 36 | daily = dailyFromAPI 37 | } 38 | 39 | expect(daily).toEventuallyNot(beNil(), timeout: timeout) 40 | expect(daily!.date).toEventually(equal(date), timeout: timeout) 41 | expect(daily!.news).toEventuallyNot(beEmpty(), timeout: timeout) 42 | } 43 | 44 | it("loads news for a newsId") { 45 | var news: News? = nil 46 | let newsId = 4770416 47 | 48 | api.news(newsId) { newsFromAPI in 49 | news = newsFromAPI 50 | } 51 | 52 | expect(news).toEventuallyNot(beNil(), timeout: timeout) 53 | expect(news!.newsId).toEventually(equal(newsId), timeout: timeout) 54 | expect(news!.title).toEventuallyNot(beNil(), timeout: timeout) 55 | expect(news!.body).toEventuallyNot(beNil(), timeout: timeout) 56 | } 57 | 58 | it("loads news extra for a newsId") { 59 | var newsExtra: NewsExtra? = nil 60 | let newsId = 4770416 61 | 62 | api.newsExtra(newsId) { newsExtraFromAPI in 63 | newsExtra = newsExtraFromAPI 64 | } 65 | 66 | expect(newsExtra).toEventuallyNot(beNil(), timeout: timeout) 67 | expect(newsExtra!.popularity).toEventually(beGreaterThanOrEqualTo(0), timeout: timeout) 68 | expect(newsExtra!.shortComments).toEventually(beGreaterThanOrEqualTo(0), timeout: timeout) 69 | expect(newsExtra!.longComments).toEventually(beGreaterThanOrEqualTo(0), timeout: timeout) 70 | expect(newsExtra!.comments).toEventually(beGreaterThanOrEqualTo(0), timeout: timeout) 71 | } 72 | 73 | it("loads short comments") { 74 | var comments: Comments? = nil 75 | let newsId = 4772308 // `Comments.comments` won't be empty 76 | // http://news.at.zhihu.com/api/4/news/4772308 77 | 78 | let request = api.shortComments(newsId) { commentsFromAPI in 79 | comments = commentsFromAPI 80 | } 81 | 82 | expect(request.request!.URLString).to(contain("short")) 83 | expect(comments).toEventuallyNot(beNil(), timeout: timeout) 84 | expect(comments!.comments).toEventuallyNot(beEmpty(), timeout: timeout) 85 | } 86 | 87 | it("loads more short comments") { 88 | var comments: Comments? = nil 89 | let newsId = 4772308 // `Comments.comments` won't be empty 90 | let commentId = 1137597 // Last comment in `/short-comments` 91 | // http://news.at.zhihu.com/api/4/news/4772308/short-comments/before/1137597 92 | 93 | let request = api.shortComments(newsId, beforeCommentId: commentId) { commentsFromAPI in 94 | comments = commentsFromAPI 95 | } 96 | 97 | expect(request.request!.URLString).to(contain("short")) 98 | expect(comments).toEventuallyNot(beNil(), timeout: timeout) 99 | expect(comments!.comments).toEventuallyNot(beEmpty(), timeout: timeout) 100 | } 101 | 102 | it("loads long comments") { 103 | var comments: Comments? = nil 104 | let newsId = 4772308 // `Comments.comments` won't be empty 105 | 106 | let request = api.longComments(newsId) { commentsFromAPI in 107 | comments = commentsFromAPI 108 | } 109 | 110 | expect(request.request!.URLString).to(contain("long")) 111 | expect(comments).toEventuallyNot(beNil(), timeout: timeout) 112 | expect(comments!.comments).toEventuallyNot(beEmpty(), timeout: timeout) 113 | } 114 | 115 | it("loads all comments") { 116 | var shortComments: Comments? = nil 117 | var longComments: Comments? = nil 118 | let newsId = 4772308 // `Comments.comments` won't be empty 119 | 120 | let (shortCommentsRequest, longCommentsRequest) = api.comments(newsId, shortCommentsHandler: { shortCommentsFromAPI in 121 | shortComments = shortCommentsFromAPI 122 | }, longCommentsHandler: { longCommentsFromAPI in 123 | longComments = longCommentsFromAPI 124 | }) 125 | 126 | expect(shortCommentsRequest.request!.URLString).to(contain("short")) 127 | expect(longCommentsRequest.request!.URLString).to(contain("long")) 128 | expect(shortComments).toEventuallyNot(beNil(), timeout: timeout) 129 | expect(longComments).toEventuallyNot(beNil(), timeout: timeout) 130 | } 131 | } 132 | } 133 | -------------------------------------------------------------------------------- /SwiftDailyAPITests/Specs/DateIndexSpec.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DateIndexSpec.swift 3 | // SwiftDailyAPI 4 | // 5 | // Created by Nicholas Tian on 14/01/2016. 6 | // Copyright © 2016 nickTD. All rights reserved. 7 | // 8 | 9 | import Quick 10 | import Nimble 11 | import SwiftDailyAPI 12 | 13 | class DateIndexSpec: QuickSpec { 14 | override func spec() { 15 | let dateFormatter = NSDateFormatter() 16 | dateFormatter.dateFormat = DailyConstants.dateFormat 17 | 18 | let todaysDate = NSDate() 19 | let dateBeforeToday = NSDate().dayBefore() 20 | 21 | let today = DateIndex(todaysDate) 22 | let tomorrow = today.successor() 23 | let yesterday = today.predecessor() 24 | 25 | describe("DateIndex") { 26 | it("has the correct date") { 27 | expect(dateFormatter.stringFromDate(todaysDate)) 28 | .to(equal(dateFormatter.stringFromDate(today.date))) 29 | } 30 | 31 | it("yesterday is not today") { 32 | expect(today == yesterday).toNot(beTrue()) 33 | expect(today.hashValue == yesterday.hashValue).toNot(beTrue()) 34 | } 35 | 36 | it("yesterday is in the past, tomorrow is in the future") { 37 | expect(yesterday.date) < todaysDate 38 | expect(tomorrow.date) > todaysDate 39 | } 40 | 41 | it("tomorrow is one day later") { 42 | expect(today.distanceTo(tomorrow)).to(equal(1)) 43 | } 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /SwiftDailyAPITests/Specs/ExtensionSpecs.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ExtensionSpecs.swift 3 | // SwiftDailyAPI 4 | // 5 | // Created by Nicholas Tian on 16/06/2015. 6 | // Copyright © 2015 nickTD. All rights reserved. 7 | // 8 | 9 | import Quick 10 | import Nimble 11 | import SwiftDailyAPI 12 | 13 | class ExtensionSpecs: QuickSpec { 14 | override func spec() { 15 | describe("NSDate.init(_ year:month:day:)") { 16 | it("returns the correct date") { 17 | let date = NSDate.dateAt(year: 2015, month: 5, day: 25)! 18 | 19 | let components = NSDateComponents() 20 | components.year = 2015 21 | components.month = 5 22 | components.day = 25 23 | let theDate = NSCalendar.currentCalendar().dateFromComponents(components)! 24 | 25 | expect(date.compare(theDate)).to(equal(NSComparisonResult.OrderedSame)) 26 | 27 | let dateFormatter = NSDateFormatter() 28 | dateFormatter.dateFormat = "yyyyMMdd" 29 | expect(dateFormatter.stringFromDate(date)).to(equal("20150525")) 30 | } 31 | } 32 | 33 | describe("NSDate.daysBefore") { 34 | it("returns date before the date") { 35 | let today = NSDate() 36 | let dayBeforeToday = today.daysBefore(1) 37 | 38 | expect(dayBeforeToday.compare(today)).to(equal(NSComparisonResult.OrderedAscending)) 39 | } 40 | } 41 | 42 | describe("NSDate.dayslater") { 43 | it("returns date after the date") { 44 | let today = NSDate() 45 | let dayAfterToday = today.daysAfter(1) 46 | 47 | expect(dayAfterToday.compare(today)).to(equal(NSComparisonResult.OrderedDescending)) 48 | } 49 | } 50 | 51 | it("is comparable") { 52 | let today = NSDate() 53 | expect(today) < today.dayAfter() 54 | expect(today) > today.dayBefore() 55 | } 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /SwiftDailyAPITests/Specs/ProofOfConceptSpecs.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ProofOfConceptSpecs.swift 3 | // SwiftDailyAPI 4 | // 5 | // Created by Nicholas Tian on 10/06/2015. 6 | // Copyright © 2015 nickTD. All rights reserved. 7 | // 8 | 9 | import Quick 10 | import Nimble 11 | 12 | class TestClass { init() { } } 13 | class SubTestClass : TestClass { } 14 | class OtherClass { init() {} } 15 | 16 | class ProofOfConceptSpecs: QuickSpec { 17 | override func spec() { 18 | describe("array") { 19 | it("can contain super class and sub class") { 20 | var array = [TestClass]() 21 | array.append(TestClass()) 22 | array.append(SubTestClass()) 23 | 24 | // Swift 2.0, Xcode 7.0 beta 25 | // Cannot invoke 'append' with an argument list of type '(OtherClass)' 26 | // array.append(OtherClass()) 27 | } 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /SwiftDailyAPITests/Specs/ReadmeCodeSpecs.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ReadmeCodeSpecs.swift 3 | // SwiftDailyAPI 4 | // 5 | // Created by Nicholas Tian on 4/06/2015. 6 | // Copyright (c) 2015 nickTD. All rights reserved. 7 | // 8 | 9 | import Quick 10 | import Nimble 11 | import SwiftDailyAPI 12 | 13 | class ReadmeCodeSpecs: QuickSpec { 14 | override func spec() { 15 | describe("Code in README.md") { 16 | it("runs") { 17 | // Setup 18 | var latestDaily: LatestDaily? 19 | var daily: Daily? 20 | var news: News? 21 | var newsExtra: NewsExtra? 22 | var shortComments, longComments: Comments? 23 | 24 | // Given 25 | let newsId = 4772308 26 | let date = NSDate.dateFromString("20150525", format: DailyConstants.dateFormat)! 27 | let api = DailyAPI(userAgent: "SwiftDailyAPI_ReadMe") 28 | 29 | // When 30 | api.latestDaily { latestDailyFromAPI in 31 | latestDaily = latestDailyFromAPI 32 | print(latestDaily?.news) 33 | print(latestDaily?.topNews) 34 | } 35 | 36 | api.daily(forDate: date) { dailyFromAPI in 37 | daily = dailyFromAPI 38 | print(daily?.news) 39 | } 40 | 41 | api.news(newsId) { newsFromAPI in 42 | news = newsFromAPI 43 | print(news?.newsId) 44 | print(news?.title) 45 | } 46 | 47 | api.newsExtra(newsId) { newsExtraFromAPI in 48 | newsExtra = newsExtraFromAPI 49 | print(newsExtra?.popularity) 50 | print(newsExtra?.comments) 51 | } 52 | 53 | api.comments(newsId, shortCommentsHandler: { comments in 54 | shortComments = comments 55 | print(shortComments?.comments) 56 | }, longCommentsHandler: { comments in 57 | longComments = comments 58 | print(longComments?.comments) 59 | }) 60 | 61 | // Then 62 | expect(latestDaily).toEventuallyNot(beNil(), timeout: 10) 63 | expect(daily).toEventuallyNot(beNil(), timeout: 10) 64 | expect(news).toEventuallyNot(beNil(), timeout: 10) 65 | expect(newsExtra).toEventuallyNot(beNil(), timeout: 10) 66 | expect(shortComments).toEventuallyNot(beNil(), timeout: 10) 67 | expect(longComments).toEventuallyNot(beNil(), timeout: 10) 68 | } 69 | } 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /SwiftDailyAPITests/Specs/RealDataModelDecodingSpecs.swift: -------------------------------------------------------------------------------- 1 | // 2 | // RealDataModelDecodingSpecs.swift 3 | // SwiftDailyAPI 4 | // 5 | // Created by Nicholas Tian on 1/06/2015. 6 | // Copyright (c) 2015 nickTD. All rights reserved. 7 | // 8 | 9 | import Quick 10 | import Nimble 11 | import SwiftDailyAPI 12 | import Argo 13 | 14 | class RealDataModelDecodeSpecs: QuickSpec { 15 | 16 | 17 | override func spec() { 18 | it("decodes Daily") { 19 | let daily: Daily? = objectFromFile("daily_news_20150525") 20 | 21 | expect(daily).toNot(beNil()) 22 | expect(daily!.date).to(equal(NSDate.dateFromString("20150525", format: "yyyyMMdd"))) 23 | expect(daily!.news).toNot(beEmpty()) 24 | } 25 | 26 | it("decodes LatestDaily") { 27 | let latestDaily: LatestDaily? = objectFromFile("latest_daily_news_20150527") 28 | 29 | expect(latestDaily).toNot(beNil()) 30 | expect(latestDaily!.date).to(equal(NSDate.dateFromString("20150527", format: "yyyyMMdd"))) 31 | expect(latestDaily!.news).toNot(beEmpty()) 32 | expect(latestDaily!.topNews).toNot(beEmpty()) 33 | } 34 | 35 | it("decodes LatestDaily with a themed NewsMeta") { 36 | let latestDaily: LatestDaily? = objectFromFile("latest_daily_news_20150802") 37 | 38 | expect(latestDaily).toNot(beNil()) 39 | expect(latestDaily!.date).toNot(beNil()) 40 | expect(latestDaily!.news).toNot(beEmpty()) 41 | expect(latestDaily!.topNews).toNot(beEmpty()) 42 | } 43 | 44 | let decodesNews: (News?) -> Void = { (news: News?) in 45 | expect(news).toNot(beNil()) 46 | 47 | expect(news!.newsId).toNot(beNil()) 48 | expect(news!.body).toNot(beNil()) 49 | 50 | expect(news!.title).toNot(beNil()) 51 | expect(news!.cssURLs).toNot(beEmpty()) 52 | expect(news!.shareURL).toNot(beNil()) 53 | } 54 | 55 | it("decodes News") { 56 | let news: News? = objectFromFile("news_4770416") 57 | 58 | decodesNews(news) 59 | expect(news!.imageURL).toNot(beNil()) 60 | expect(news!.imageSourceText).toNot(beNil()) 61 | } 62 | 63 | it("decodes News without image_source") { 64 | let news: News? = objectFromFile("news_4859444") 65 | 66 | decodesNews(news) 67 | } 68 | 69 | it("decodes News without image and image_source") { 70 | let news: News? = objectFromFile("news_4820022") 71 | 72 | decodesNews(news) 73 | } 74 | 75 | it("decodes NewsExtra") { 76 | let newsExtra: NewsExtra? = objectFromFile("news_extra_4770416") 77 | 78 | expect(newsExtra).toNot(beNil()) 79 | expect(newsExtra!.popularity).to(equal(697)) 80 | expect(newsExtra!.shortComments).to(equal(10)) 81 | expect(newsExtra!.longComments).to(equal(0)) 82 | expect(newsExtra!.comments).to(equal(10)) 83 | } 84 | 85 | it("decodes Comment - short") { 86 | let comments: Comments? = objectFromFile("short_comments_4772308") 87 | 88 | expect(comments!.comments).toNot(beEmpty()) 89 | } 90 | 91 | it("decodes Comment - long") { 92 | let comments: Comments? = objectFromFile("long_comments_4772308") 93 | 94 | expect(comments!.comments).toNot(beEmpty()) 95 | } 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /SwiftDailyAPITests/Specs/TestDataModelDecodingSpecs.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ModelTests.swift 3 | // SwiftDailyAPI 4 | // 5 | // Created by Nicholas Tian on 25/05/2015. 6 | // Copyright (c) 2015 nickTD. All rights reserved. 7 | // 8 | 9 | import Quick 10 | import Nimble 11 | import SwiftDailyAPI 12 | import Argo 13 | 14 | class TestDataModelDecodeSpecs: QuickSpec { 15 | override func spec() { 16 | let newsId = 12345 17 | let title = "Title of the News" 18 | let imageURLString = "http://httpbin.org/image/jpeg" 19 | let gaPrefix = 67890 20 | let dateString = "20150525" 21 | 22 | it("decodes NewsMeta") { 23 | let newsMeta: NewsMeta? = objectFromFile("news_meta") 24 | 25 | expect(newsMeta).toNot(beNil()) 26 | expect(newsMeta!.newsId).to(equal(newsId)) 27 | expect(newsMeta!.title).to(equal(title)) 28 | 29 | expect(newsMeta!.imageURLs).to(equal([NSURL(string: imageURLString)!])) 30 | expect(newsMeta!.gaPrefix).to(equal(gaPrefix)) 31 | } 32 | 33 | it("decodes TopNewsMeta") { 34 | let topNewsMeta: TopNewsMeta? = objectFromFile("top_news_meta") 35 | 36 | expect(topNewsMeta).toNot(beNil()) 37 | expect(topNewsMeta!.newsId).to(equal(newsId)) 38 | expect(topNewsMeta!.title).to(equal(title)) 39 | 40 | expect(topNewsMeta!.imageURL).to(equal(NSURL(string: imageURLString)!)) 41 | } 42 | 43 | it("decodes Daily") { 44 | let daily: Daily? = objectFromFile("daily_news") 45 | 46 | expect(daily).toNot(beNil()) 47 | expect(daily!.date).to(equal(NSDate.dateFromString("20150525", format: "yyyyMMdd"))) 48 | expect(daily!.news).toNot(beEmpty()) 49 | } 50 | 51 | it("decodes Latestdaily") { 52 | let latestDaily: LatestDaily? = objectFromFile("latest_daily_news") 53 | 54 | expect(latestDaily).toNot(beNil()) 55 | expect(latestDaily!.date).to(equal(NSDate.dateFromString("20150525", format: "yyyyMMdd"))) 56 | expect(latestDaily!.news).toNot(beEmpty()) 57 | expect(latestDaily!.topNews).toNot(beEmpty()) 58 | } 59 | 60 | it("decodes News") { 61 | let news: News? = objectFromFile("news") 62 | 63 | expect(news).toNot(beNil()) 64 | expect(news!.newsId).to(equal(newsId)) 65 | expect(news!.title).to(equal(title)) 66 | expect(news!.body).to(equal("HTML body")) 67 | expect(news!.cssURLs).toNot(beEmpty()) 68 | expect(news!.imageURL).to(equal(NSURL(string: imageURLString)!)) 69 | expect(news!.imageSourceText).to(equal("Image Source")) 70 | expect(news!.shareURL).to(equal(NSURL(string: "http://daily.zhihu.com/story/12345"))) 71 | } 72 | 73 | it("decodes NewsExtra") { 74 | let newsExtra: NewsExtra? = objectFromFile("news_extra") 75 | 76 | expect(newsExtra).toNot(beNil()) 77 | expect(newsExtra!.popularity).to(equal(100)) 78 | expect(newsExtra!.shortComments).to(equal(200)) 79 | expect(newsExtra!.longComments).to(equal(300)) 80 | expect(newsExtra!.comments).to(equal(500)) 81 | } 82 | 83 | it("decodes Comment") { 84 | let comment: Comment? = objectFromFile("comment") 85 | 86 | expect(comment).toNot(beNil()) 87 | expect(comment!.commentId).to(equal(12345)) 88 | expect(comment!.authorName).to(equal("The Master")) 89 | expect(comment!.content).to(equal("How about that? I win.")) 90 | expect(comment!.likes).to(equal(1200)) 91 | expect(comment!.repliedAt).to(equal(NSDate(timeIntervalSince1970: 1234567890))) 92 | expect(comment!.avatarURL).to(equal(NSURL(string: imageURLString)!)) 93 | } 94 | 95 | it("decodes Comment with ReplyToComment") { 96 | let comment: Comment? = objectFromFile("comment_with_reply_to") 97 | 98 | expect(comment).toNot(beNil()) 99 | expect(comment!.replyToComment).toNot(beNil()) 100 | expect(comment!.replyToComment!.authorName).to(equal("Doctor Who")) 101 | expect(comment!.replyToComment!.content).to(equal("Just regenerate! Regenerate!")) 102 | } 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /SwiftDailyAPITests/Specs/Xcode7PlusSwift2.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Xcode7PlusSwift2.swift 3 | // SwiftDailyAPI 4 | // 5 | // Created by Nicholas Tian on 9/06/2015. 6 | // Copyright © 2015 nickTD. All rights reserved. 7 | // 8 | 9 | import Quick 10 | import Nimble 11 | 12 | @testable 13 | import SwiftDailyAPI 14 | 15 | class Xcode7PlusSwift2: QuickSpec { 16 | override func spec() { 17 | describe("Xcode7 + Swift 2") { 18 | it("is AWESOME!") { 19 | Daily(date: NSDate(), news: []) 20 | } 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /bin/bump: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | SHORT_VERSION=`/usr/libexec/PlistBuddy -c "Print CFBundleShortVersionString" ./SwiftDailyAPI/Info.plist` 4 | 5 | git commit -v -e -m "Bump version number $SHORT_VERSION" 6 | -------------------------------------------------------------------------------- /bin/merge: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # Merge but keep files in Carthage/Checkouts/* as is in this branch 3 | 4 | git merge --no-commit $* 5 | git checkout ./Carthage/Checkouts/* 6 | echo "Remember to commit the changes. :]" 7 | -------------------------------------------------------------------------------- /bin/new_branch: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # Create branches whose base if the merge base of develop and release branch. 3 | # To minimize changes to git's commit graph, when merge new changes into both branch. 4 | 5 | git fetch --all 6 | git checkout -b $* `git merge-base develop remotes/origin/release/Xcode-6.3.2-Swift-1.2` 7 | -------------------------------------------------------------------------------- /bin/setup: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | bundle install 4 | carthage bootstrap --no-use-binaries --platform iOS 5 | -------------------------------------------------------------------------------- /bin/update: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | carthage update --no-use-binaries --platform iOS 4 | --------------------------------------------------------------------------------