diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 00000000..a3816d45 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,23 @@ +name: CI + +on: + push: + branches: [ main, master ] + pull_request: + branches: [ main, master ] + +jobs: + build-and-test: + runs-on: macos-latest + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Select Xcode + run: sudo xcode-select -s /Applications/Xcode_16.4.app + + - name: Build + run: xcrun swift build --build-tests + + - name: Run tests + run: xcrun swift test \ No newline at end of file diff --git a/.swiftlint.yml b/.swiftlint.yml index 03003d1d..36ee05ac 100644 --- a/.swiftlint.yml +++ b/.swiftlint.yml @@ -1,7 +1,7 @@ disabled_rules: - force_cast - force_try - - variable_name + - identifier_name - type_name - file_length - line_length diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 34acdea7..00000000 --- a/.travis.yml +++ /dev/null @@ -1,8 +0,0 @@ -language: objective-c -osx_image: xcode10 -xcode_sdk: iphonesimulator12.0 -script: -- set -o pipefail -- travis_retry xcodebuild -workspace SwiftyJSON.xcworkspace -scheme "SwiftyJSON iOS" -destination "platform=iOS Simulator,name=iPhone 6" build-for-testing test | xcpretty -- travis_retry xcodebuild -workspace SwiftyJSON.xcworkspace -scheme "SwiftyJSON macOS" build-for-testing test | xcpretty -- travis_retry xcodebuild -workspace SwiftyJSON.xcworkspace -scheme "SwiftyJSON tvOS" -destination "platform=tvOS Simulator,name=Apple TV" build-for-testing test | xcpretty diff --git a/CHANGELOG.md b/CHANGELOG.md index 6a0935d3..082b0247 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,15 @@ [Full Changelog](https://github.com/SwiftyJSON/SwiftyJSON/compare/2.2.0...HEAD) +### Added +- Swift 6 support with full Sendable conformance ([#1163](https://github.com/SwiftyJSON/SwiftyJSON/issues/1163)) +- Comprehensive concurrency tests for actor boundary validation + +### Changed +- `JSON` struct conforms to `@unchecked Sendable` +- `Type`, `SwiftyJSONError`, `JSONKey` enums conform to `Sendable` +- Minimum Swift tools version updated to 6.0 + **Closed issues:** - 156 compiler errors Mavericks + Xcode 6.2 [\#220](https://github.com/SwiftyJSON/SwiftyJSON/issues/220) diff --git a/Example/Example.xcodeproj/project.pbxproj b/Example/Example.xcodeproj/project.pbxproj index 54e81356..e0a5e55e 100644 --- a/Example/Example.xcodeproj/project.pbxproj +++ b/Example/Example.xcodeproj/project.pbxproj @@ -32,7 +32,7 @@ /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ - 04294C501BE5A9DE00D0397E /* Playground.playground */ = {isa = PBXFileReference; lastKnownFileType = file.playground; path = Playground.playground; sourceTree = ""; }; + 04294C501BE5A9DE00D0397E /* Playground.playground */ = {isa = PBXFileReference; lastKnownFileType = file.playground; path = Playground.playground; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.swift; }; 04733F511D92E6ED002E3A99 /* SwiftyJSON.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = SwiftyJSON.framework; sourceTree = BUILT_PRODUCTS_DIR; }; A82A1C1919D926B8009A653D /* Example.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Example.app; sourceTree = BUILT_PRODUCTS_DIR; }; A82A1C1D19D926B8009A653D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; @@ -124,19 +124,19 @@ isa = PBXProject; attributes = { LastSwiftUpdateCheck = 0700; - LastUpgradeCheck = 0930; + LastUpgradeCheck = 1020; ORGANIZATIONNAME = swiftyjson; TargetAttributes = { A82A1C1819D926B8009A653D = { CreatedOnToolsVersion = 6.0.1; - LastSwiftMigration = 0930; + LastSwiftMigration = 1020; ProvisioningStyle = Manual; }; }; }; buildConfigurationList = A82A1C1419D926B8009A653D /* Build configuration list for PBXProject "Example" */; compatibilityVersion = "Xcode 3.2"; - developmentRegion = English; + developmentRegion = en; hasScannedForEncodings = 0; knownRegions = ( en, @@ -313,8 +313,7 @@ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = "com.swiftyjson.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_SWIFT3_OBJC_INFERENCE = Default; - SWIFT_VERSION = 4.0; + SWIFT_VERSION = 5.0; }; name = Debug; }; @@ -329,8 +328,7 @@ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = "com.swiftyjson.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_SWIFT3_OBJC_INFERENCE = Default; - SWIFT_VERSION = 4.0; + SWIFT_VERSION = 5.0; }; name = Release; }; diff --git a/Example/Example/AppDelegate.swift b/Example/Example/AppDelegate.swift index e2af9aa6..c4236b1d 100644 --- a/Example/Example/AppDelegate.swift +++ b/Example/Example/AppDelegate.swift @@ -28,7 +28,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate { var window: UIWindow? - func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool { + func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { let navigationController = self.window?.rootViewController as! UINavigationController let viewController = navigationController.topViewController as! ViewController diff --git a/Example/Playground.playground/Contents.swift b/Example/Playground.playground/Contents.swift index 9306d850..7542d181 100644 --- a/Example/Playground.playground/Contents.swift +++ b/Example/Playground.playground/Contents.swift @@ -29,7 +29,6 @@ let jsonString = String(data: jsonData!, encoding: .utf8) ### Initialization */ -import SwiftyJSON let json1 = try? JSON(data: jsonData!) /*: diff --git a/Package.swift b/Package.swift index 801f1d5d..fb026e55 100644 --- a/Package.swift +++ b/Package.swift @@ -1,4 +1,24 @@ +// swift-tools-version:6.0 import PackageDescription let package = Package( - name: "SwiftyJSON") + name: "SwiftyJSON", + products: [ + .library(name: "SwiftyJSON", targets: ["SwiftyJSON"]) + ], + targets: [ + .target(name: "SwiftyJSON", + dependencies: [], + resources: [ + .copy("PrivacyInfo.xcprivacy") + ] + ), + .testTarget( + name: "SwiftJSONTests", + dependencies: ["SwiftyJSON"], + resources: [ + .copy("Tests.json") + ] + ) + ] +) diff --git a/README.md b/README.md index 9cf5a68d..a6f3037a 100644 --- a/README.md +++ b/README.md @@ -1,14 +1,10 @@ # SwiftyJSON -[![Carthage compatible](https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat)](https://github.com/Carthage/Carthage) ![CocoaPods](https://img.shields.io/cocoapods/v/SwiftyJSON.svg) ![Platform](https://img.shields.io/badge/platforms-iOS%208.0%20%7C%20macOS%2010.10%20%7C%20tvOS%209.0%20%7C%20watchOS%203.0-F28D00.svg) +[![CI](https://github.com/SwiftyJSON/SwiftyJSON/actions/workflows/ci.yml/badge.svg)](https://github.com/SwiftyJSON/SwiftyJSON/actions/workflows/ci.yml) -SwiftyJSON makes it easy to deal with JSON data in Swift. - -Platform | Build Status ----------| --------------| -*OS | [![Travis CI](https://travis-ci.org/SwiftyJSON/SwiftyJSON.svg?branch=master)](https://travis-ci.org/SwiftyJSON/SwiftyJSON) | -[Linux](https://github.com/IBM-Swift/SwiftyJSON) | [![Build Status](https://travis-ci.org/IBM-Swift/SwiftyJSON.svg?branch=master)](https://travis-ci.org/IBM-Swift/SwiftyJSON) | +[![Carthage compatible](https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat)](https://github.com/Carthage/Carthage) ![CocoaPods](https://img.shields.io/cocoapods/v/SwiftyJSON.svg) ![Platform](https://img.shields.io/badge/platforms-iOS%208.0%20%7C%20macOS%2010.10%20%7C%20tvOS%209.0%20%7C%20watchOS%203.0-F28D00.svg) [![Reviewed by Hound](https://img.shields.io/badge/Reviewed_by-Hound-8E64B0.svg)](https://houndci.com) +SwiftyJSON makes it easy to deal with JSON data in Swift. 1. [Why is the typical JSON handling in Swift NOT good](#why-is-the-typical-json-handling-in-swift-not-good) 2. [Requirements](#requirements) @@ -24,12 +20,11 @@ Platform | Build Status - [Raw object](#raw-object) - [Literal convertibles](#literal-convertibles) - [Merging](#merging) + - [Removing elements](#removing-elements) 5. [Work with Alamofire](#work-with-alamofire) 6. [Work with Moya](#work-with-moya) 7. [SwiftyJSON Model Generator](#swiftyjson-model-generator) -> [中文介绍](http://tangplin.github.io/swiftyjson/) - ## Why is the typical JSON handling in Swift NOT good? @@ -63,7 +58,7 @@ An unreadable mess--for something that should really be simple! With SwiftyJSON all you have to do is: ```swift -let json = JSON(data: dataFromNetworking) +let json = try? JSON(data: dataFromNetworking) if let userName = json[0]["user"]["name"].string { //Now you got your value } @@ -72,19 +67,21 @@ if let userName = json[0]["user"]["name"].string { And don't worry about the Optional Wrapping thing. It's done for you automatically. ```swift -let json = JSON(data: dataFromNetworking) -if let userName = json[999999]["wrong_key"]["wrong_name"].string { +let json = try? JSON(data: dataFromNetworking) +let result = json[999999]["wrong_key"]["wrong_name"] +if let userName = result.string { //Calm down, take it easy, the ".string" property still produces the correct Optional String type with safety } else { //Print the error - print(json[999999]["wrong_key"]["wrong_name"]) + print(result.error) } ``` ## Requirements - iOS 8.0+ | macOS 10.10+ | tvOS 9.0+ | watchOS 2.0+ -- Xcode 8 +- Xcode 16+ +- Swift 6.0+ ## Integration @@ -144,7 +141,7 @@ import SwiftyJSON ``` ```swift -let json = JSON(data: dataFromNetworking) +let json = try? JSON(data: dataFromNetworking) ``` Or @@ -168,7 +165,7 @@ let name = json[0].double ```swift // Getting an array of string from a JSON Array -let arrayNames = json["users"].arrayValue.map({$0["name"].stringValue}) +let arrayNames = json["users"].arrayValue.map {$0["name"].stringValue} ``` ```swift @@ -397,7 +394,7 @@ let json: JSON = "I'm a json" ``` ```swift -/ /IntegerLiteralConvertible +// IntegerLiteralConvertible let json: JSON = 12345 ``` @@ -465,7 +462,7 @@ If both JSONs contain a value for the same key, _mostly_ this value gets overwri - In case of both values being a `JSON.Type.array` the values form the array found in the `other` JSON getting appended to the original JSON's array value. - In case of both values being a `JSON.Type.dictionary` both JSON-values are getting merged the same way the encapsulating JSON is merged. -In case, where two fields in a JSON have a different types, the value will get always overwritten. +In a case where two fields in a JSON have different types, the value will get always overwritten. There are two different fashions for merging: `merge` modifies the original JSON, whereas `merged` works non-destructively on a copy. @@ -504,6 +501,69 @@ let updated = original.merge(with: update) // ] ``` + +#### Removing elements + +If you are storing dictionaries, you can remove elements using `dictionaryObject.removeValue(forKey:)`. This mutates the JSON object in place. + +For example: + +```swift +var object = JSON([ + "one": ["color": "blue"], + "two": ["city": "tokyo", + "country": "japan", + "foods": [ + "breakfast": "tea", + "lunch": "sushi" + ] + ] +]) +``` + +Lets remove the `country` key: + +```swift +object["two"].dictionaryObject?.removeValue(forKey: "country") +``` + +If you `print(object)`, you'll see that the `country` key no longer exists. + +```json +{ + "one" : { + "color" : "blue" + }, + "two" : { + "city" : "tokyo", + "foods" : { + "breakfast" : "tea", + "lunch" : "sushi" + } + } +} +``` + +This also works for nested dictionaries: + +```swift +object["two"]["foods"].dictionaryObject?.removeValue(forKey: "breakfast") +``` + +```json +{ + "one" : { + "color" : "blue" + }, + "two" : { + "city" : "tokyo", + "foods" : { + "lunch" : "sushi" + } + } +} +``` + ## String representation There are two options available: - use the default Swift one @@ -557,5 +617,4 @@ provider.request(.showProducts) { result in ## SwiftyJSON Model Generator Tools to generate SwiftyJSON Models -* [JSON Cafe](http://www.jsoncafe.com/) * [JSON Export](https://github.com/Ahmed-Ali/JSONExport) diff --git a/Source/SwiftyJSON/PrivacyInfo.xcprivacy b/Source/SwiftyJSON/PrivacyInfo.xcprivacy new file mode 100644 index 00000000..d37d6275 --- /dev/null +++ b/Source/SwiftyJSON/PrivacyInfo.xcprivacy @@ -0,0 +1,14 @@ + + + + + NSPrivacyCollectedDataTypes + + NSPrivacyAccessedAPITypes + + NSPrivacyTrackingDomains + + NSPrivacyTracking + + + diff --git a/Source/SwiftyJSON.h b/Source/SwiftyJSON/SwiftyJSON.h similarity index 100% rename from Source/SwiftyJSON.h rename to Source/SwiftyJSON/SwiftyJSON.h diff --git a/Source/SwiftyJSON.swift b/Source/SwiftyJSON/SwiftyJSON.swift similarity index 68% rename from Source/SwiftyJSON.swift rename to Source/SwiftyJSON/SwiftyJSON.swift index a6c1f3a6..d2f39ef2 100644 --- a/Source/SwiftyJSON.swift +++ b/Source/SwiftyJSON/SwiftyJSON.swift @@ -24,7 +24,7 @@ import Foundation // MARK: - Error // swiftlint:disable line_length -public enum SwiftyJSONError: Int, Swift.Error { +public enum SwiftyJSONError: Int, Swift.Error, Sendable { case unsupportedType = 999 case indexOutOfBounds = 900 case elementTooDeep = 902 @@ -67,7 +67,7 @@ JSON's type definitions. See http://www.json.org */ -public enum Type: Int { +public enum Type: Int, Sendable { case number case string case bool @@ -79,7 +79,7 @@ public enum Type: Int { // MARK: - JSON Base -public struct JSON { +public struct JSON: @unchecked Sendable { /** Creates a JSON using the data. @@ -138,7 +138,7 @@ public struct JSON { - returns: The created JSON */ fileprivate init(jsonObject: Any) { - self.object = jsonObject + object = jsonObject } /** @@ -174,14 +174,14 @@ public struct JSON { Typecheck is set to true for the first recursion level to prevent total override of the source JSON */ fileprivate mutating func merge(with other: JSON, typecheck: Bool) throws { - if self.type == other.type { - switch self.type { + if type == other.type { + switch type { case .dictionary: for (key, _) in other { try self[key].merge(with: other[key], typecheck: false) } case .array: - self = JSON(self.arrayValue + other.arrayValue) + self = JSON(arrayValue + other.arrayValue) default: self = other } @@ -211,19 +211,13 @@ public struct JSON { /// Object in JSON public var object: Any { get { - switch self.type { - case .array: - return self.rawArray - case .dictionary: - return self.rawDictionary - case .string: - return self.rawString - case .number: - return self.rawNumber - case .bool: - return self.rawBool - default: - return self.rawNull + switch type { + case .array: return rawArray + case .dictionary: return rawDictionary + case .string: return rawString + case .number: return rawNumber + case .bool: return rawBool + default: return rawNull } } set { @@ -232,24 +226,24 @@ public struct JSON { case let number as NSNumber: if number.isBool { type = .bool - self.rawBool = number.boolValue + rawBool = number.boolValue } else { type = .number - self.rawNumber = number + rawNumber = number } case let string as String: type = .string - self.rawString = string + rawString = string case _ as NSNull: type = .null - case nil: + case Optional.none: type = .null case let array as [Any]: type = .array - self.rawArray = array + rawArray = array case let dictionary as [String: Any]: type = .dictionary - self.rawDictionary = dictionary + rawDictionary = dictionary default: type = .unknown error = SwiftyJSONError.unsupportedType @@ -271,11 +265,7 @@ private func unwrap(_ object: Any) -> Any { case let array as [Any]: return array.map(unwrap) case let dictionary as [String: Any]: - var unwrappedDic = dictionary - for (k, v) in dictionary { - unwrappedDic[k] = unwrap(v) - } - return unwrappedDic + return dictionary.mapValues(unwrap) default: return object } @@ -288,24 +278,18 @@ public enum Index: Comparable { static public func == (lhs: Index, rhs: Index) -> Bool { switch (lhs, rhs) { - case (.array(let left), .array(let right)): - return left == right - case (.dictionary(let left), .dictionary(let right)): - return left == right - case (.null, .null): return true - default: - return false + case (.array(let left), .array(let right)): return left == right + case (.dictionary(let left), .dictionary(let right)): return left == right + case (.null, .null): return true + default: return false } } static public func < (lhs: Index, rhs: Index) -> Bool { switch (lhs, rhs) { - case (.array(let left), .array(let right)): - return left < right - case (.dictionary(let left), .dictionary(let right)): - return left < right - default: - return false + case (.array(let left), .array(let right)): return left < right + case (.dictionary(let left), .dictionary(let right)): return left < right + default: return false } } } @@ -319,46 +303,33 @@ extension JSON: Swift.Collection { public var startIndex: Index { switch type { - case .array: - return .array(rawArray.startIndex) - case .dictionary: - return .dictionary(rawDictionary.startIndex) - default: - return .null + case .array: return .array(rawArray.startIndex) + case .dictionary: return .dictionary(rawDictionary.startIndex) + default: return .null } } public var endIndex: Index { switch type { - case .array: - return .array(rawArray.endIndex) - case .dictionary: - return .dictionary(rawDictionary.endIndex) - default: - return .null + case .array: return .array(rawArray.endIndex) + case .dictionary: return .dictionary(rawDictionary.endIndex) + default: return .null } } public func index(after i: Index) -> Index { switch i { - case .array(let idx): - return .array(rawArray.index(after: idx)) - case .dictionary(let idx): - return .dictionary(rawDictionary.index(after: idx)) - default: - return .null + case .array(let idx): return .array(rawArray.index(after: idx)) + case .dictionary(let idx): return .dictionary(rawDictionary.index(after: idx)) + default: return .null } } public subscript (position: Index) -> (String, JSON) { switch position { - case .array(let idx): - return (String(idx), JSON(self.rawArray[idx])) - case .dictionary(let idx): - let (key, value) = self.rawDictionary[idx] - return (key, JSON(value)) - default: - return ("", JSON.null) + case .array(let idx): return (String(idx), JSON(rawArray[idx])) + case .dictionary(let idx): return (rawDictionary[idx].key, JSON(rawDictionary[idx].value)) + default: return ("", JSON.null) } } } @@ -368,7 +339,7 @@ extension JSON: Swift.Collection { /** * To mark both String and Int can be used in subscript. */ -public enum JSONKey { +public enum JSONKey: Sendable { case index(Int) case key(String) } @@ -394,12 +365,12 @@ extension JSON { /// If `type` is `.array`, return json whose object is `array[index]`, otherwise return null json with error. fileprivate subscript(index index: Int) -> JSON { get { - if self.type != .array { + if type != .array { var r = JSON.null r.error = self.error ?? SwiftyJSONError.wrongType return r - } else if self.rawArray.indices.contains(index) { - return JSON(self.rawArray[index]) + } else if rawArray.indices.contains(index) { + return JSON(rawArray[index]) } else { var r = JSON.null r.error = SwiftyJSONError.indexOutOfBounds @@ -407,10 +378,10 @@ extension JSON { } } set { - if self.type == .array && - self.rawArray.indices.contains(index) && + if type == .array && + rawArray.indices.contains(index) && newValue.error == nil { - self.rawArray[index] = newValue.object + rawArray[index] = newValue.object } } } @@ -419,8 +390,8 @@ extension JSON { fileprivate subscript(key key: String) -> JSON { get { var r = JSON.null - if self.type == .dictionary { - if let o = self.rawDictionary[key] { + if type == .dictionary { + if let o = rawDictionary[key] { r = JSON(o) } else { r.error = SwiftyJSONError.notExist @@ -431,8 +402,8 @@ extension JSON { return r } set { - if self.type == .dictionary && newValue.error == nil { - self.rawDictionary[key] = newValue.object + if type == .dictionary && newValue.error == nil { + rawDictionary[key] = newValue.object } } } @@ -442,13 +413,13 @@ extension JSON { get { switch sub.jsonKey { case .index(let index): return self[index: index] - case .key(let key): return self[key: key] + case .key(let key): return self[key: key] } } set { switch sub.jsonKey { case .index(let index): self[index: index] = newValue - case .key(let key): self[key: key] = newValue + case .key(let key): self[key: key] = newValue } } } @@ -458,7 +429,7 @@ extension JSON { Example: - ``` + ```swift let json = JSON[data] let path = [9,"list","person","name"] let name = json[path] @@ -476,10 +447,8 @@ extension JSON { } set { switch path.count { - case 0: - return - case 1: - self[sub:path[0]].object = newValue.object + case 0: return + case 1: self[sub:path[0]].object = newValue.object default: var aPath = path aPath.remove(at: 0) @@ -494,10 +463,14 @@ extension JSON { Find a json in the complex data structures by using array of Int and/or String as path. - parameter path: The target json's path. Example: - + ```swift let name = json[9,"list","person","name"] - - The same as: let name = json[9]["list"]["person"]["name"] + ``` + + The same as: + ```swift + let name = json[9]["list"]["person"]["name"] + ``` - returns: Return a json found by the path or a null json with error */ @@ -551,7 +524,7 @@ extension JSON: Swift.ExpressibleByFloatLiteral { extension JSON: Swift.ExpressibleByDictionaryLiteral { public init(dictionaryLiteral elements: (String, Any)...) { - let dictionary = elements.reduce(into: [String: Any](), { $0[$1.0] = $1.1}) + let dictionary = Dictionary(elements, uniquingKeysWith: { $1 }) self.init(dictionary) } } @@ -576,15 +549,15 @@ extension JSON: Swift.RawRepresentable { } public var rawValue: Any { - return self.object + return object } public func rawData(options opt: JSONSerialization.WritingOptions = JSONSerialization.WritingOptions(rawValue: 0)) throws -> Data { - guard JSONSerialization.isValidJSONObject(self.object) else { + guard JSONSerialization.isValidJSONObject(object) else { throw SwiftyJSONError.invalidJSON } - return try JSONSerialization.data(withJSONObject: self.object, options: opt) + return try JSONSerialization.data(withJSONObject: object, options: opt) } public func rawString(_ encoding: String.Encoding = .utf8, options opt: JSONSerialization.WritingOptions = .prettyPrinted) -> String? { @@ -609,16 +582,16 @@ extension JSON: Swift.RawRepresentable { fileprivate func _rawString(_ encoding: String.Encoding = .utf8, options: [writingOptionsKeys: Any], maxObjectDepth: Int = 10) throws -> String? { guard maxObjectDepth > 0 else { throw SwiftyJSONError.invalidJSON } - switch self.type { + switch type { case .dictionary: do { if !(options[.castNilToNSNull] as? Bool ?? false) { let jsonOption = options[.jsonSerialization] as? JSONSerialization.WritingOptions ?? JSONSerialization.WritingOptions.prettyPrinted - let data = try self.rawData(options: jsonOption) + let data = try rawData(options: jsonOption) return String(data: data, encoding: encoding) } - guard let dict = self.object as? [String: Any?] else { + guard let dict = object as? [String: Any?] else { return nil } let body = try dict.keys.map { key throws -> String in @@ -648,11 +621,11 @@ extension JSON: Swift.RawRepresentable { do { if !(options[.castNilToNSNull] as? Bool ?? false) { let jsonOption = options[.jsonSerialization] as? JSONSerialization.WritingOptions ?? JSONSerialization.WritingOptions.prettyPrinted - let data = try self.rawData(options: jsonOption) + let data = try rawData(options: jsonOption) return String(data: data, encoding: encoding) } - guard let array = self.object as? [Any?] else { + guard let array = object as? [Any?] else { return nil } let body = try array.map { value throws -> String in @@ -675,16 +648,11 @@ extension JSON: Swift.RawRepresentable { } catch _ { return nil } - case .string: - return self.rawString - case .number: - return self.rawNumber.stringValue - case .bool: - return self.rawBool.description - case .null: - return "null" - default: - return nil + case .string: return rawString + case .number: return rawNumber.stringValue + case .bool: return rawBool.description + case .null: return "null" + default: return nil } } } @@ -694,11 +662,7 @@ extension JSON: Swift.RawRepresentable { extension JSON: Swift.CustomStringConvertible, Swift.CustomDebugStringConvertible { public var description: String { - if let string = self.rawString(options: .prettyPrinted) { - return string - } else { - return "unknown" - } + return rawString(options: .prettyPrinted) ?? "unknown" } public var debugDescription: String { @@ -712,11 +676,7 @@ extension JSON { //Optional [JSON] public var array: [JSON]? { - if self.type == .array { - return self.rawArray.map { JSON($0) } - } else { - return nil - } + return type == .array ? rawArray.map(JSON.init(_:)) : nil } //Non-optional [JSON] @@ -727,19 +687,13 @@ extension JSON { //Optional [Any] public var arrayObject: [Any]? { get { - switch self.type { - case .array: - return self.rawArray - default: - return nil + switch type { + case .array: return rawArray + default: return nil } } set { - if let array = newValue { - self.object = array - } else { - self.object = NSNull() - } + self.object = newValue ?? NSNull() } } } @@ -750,12 +704,8 @@ extension JSON { //Optional [String : JSON] public var dictionary: [String: JSON]? { - if self.type == .dictionary { - var d = [String: JSON](minimumCapacity: rawDictionary.count) - for (key, value) in rawDictionary { - d[key] = JSON(value) - } - return d + if type == .dictionary { + return rawDictionary.mapValues(JSON.init(_:)) } else { return nil } @@ -763,26 +713,20 @@ extension JSON { //Non-optional [String : JSON] public var dictionaryValue: [String: JSON] { - return self.dictionary ?? [:] + return dictionary ?? [:] } //Optional [String : Any] public var dictionaryObject: [String: Any]? { get { - switch self.type { - case .dictionary: - return self.rawDictionary - default: - return nil + switch type { + case .dictionary: return rawDictionary + default: return nil } } set { - if let v = newValue { - self.object = v - } else { - self.object = NSNull() - } + object = newValue ?? NSNull() } } } @@ -794,38 +738,28 @@ extension JSON { // : Swift.Bool //Optional bool public var bool: Bool? { get { - switch self.type { - case .bool: - return self.rawBool - default: - return nil + switch type { + case .bool: return rawBool + default: return nil } } set { - if let newValue = newValue { - self.object = newValue as Bool - } else { - self.object = NSNull() - } + object = newValue ?? NSNull() } } //Non-optional bool public var boolValue: Bool { get { - switch self.type { - case .bool: - return self.rawBool - case .number: - return self.rawNumber.boolValue - case .string: - return ["true", "y", "t", "yes", "1"].contains { self.rawString.caseInsensitiveCompare($0) == .orderedSame } - default: - return false + switch type { + case .bool: return rawBool + case .number: return rawNumber.boolValue + case .string: return ["true", "y", "t", "yes", "1"].contains { rawString.caseInsensitiveCompare($0) == .orderedSame } + default: return false } } set { - self.object = newValue + object = newValue } } } @@ -837,38 +771,28 @@ extension JSON { //Optional string public var string: String? { get { - switch self.type { - case .string: - return self.object as? String - default: - return nil + switch type { + case .string: return object as? String + default: return nil } } set { - if let newValue = newValue { - self.object = NSString(string: newValue) - } else { - self.object = NSNull() - } + object = newValue ?? NSNull() } } //Non-optional string public var stringValue: String { get { - switch self.type { - case .string: - return self.object as? String ?? "" - case .number: - return self.rawNumber.stringValue - case .bool: - return (self.object as? Bool).map { String($0) } ?? "" - default: - return "" + switch type { + case .string: return object as? String ?? "" + case .number: return rawNumber.stringValue + case .bool: return (object as? Bool).map(String.init) ?? "" + default: return "" } } set { - self.object = NSString(string: newValue) + object = newValue } } } @@ -880,40 +804,31 @@ extension JSON { //Optional number public var number: NSNumber? { get { - switch self.type { - case .number: - return self.rawNumber - case .bool: - return NSNumber(value: self.rawBool ? 1 : 0) - default: - return nil + switch type { + case .number: return rawNumber + case .bool: return NSNumber(value: rawBool ? 1 : 0) + default: return nil } } set { - self.object = newValue ?? NSNull() + object = newValue ?? NSNull() } } //Non-optional number public var numberValue: NSNumber { get { - switch self.type { + switch type { case .string: - let decimal = NSDecimalNumber(string: self.object as? String) - if decimal == NSDecimalNumber.notANumber { // indicates parse error - return NSDecimalNumber.zero - } - return decimal - case .number: - return self.object as? NSNumber ?? NSNumber(value: 0) - case .bool: - return NSNumber(value: self.rawBool ? 1 : 0) - default: - return NSNumber(value: 0.0) + let decimal = NSDecimalNumber(string: object as? String) + return decimal == .notANumber ? .zero : decimal + case .number: return object as? NSNumber ?? NSNumber(value: 0) + case .bool: return NSNumber(value: rawBool ? 1 : 0) + default: return NSNumber(value: 0.0) } } set { - self.object = newValue + object = newValue } } } @@ -923,17 +838,15 @@ extension JSON { extension JSON { public var null: NSNull? { + set { + object = NSNull() + } get { - switch self.type { - case .null: - return self.rawNull - default: - return nil + switch type { + case .null: return rawNull + default: return nil } } - set { - self.object = NSNull() - } } public func exists() -> Bool { if let errorValue = error, (400...1000).contains(errorValue.errorCode) { @@ -950,12 +863,12 @@ extension JSON { //Optional URL public var url: URL? { get { - switch self.type { + switch type { case .string: // Check for existing percent escapes first to prevent double-escaping of % character - if self.rawString.range(of: "%[0-9A-Fa-f]{2}", options: .regularExpression, range: nil, locale: nil) != nil { - return Foundation.URL(string: self.rawString) - } else if let encodedString_ = self.rawString.addingPercentEncoding(withAllowedCharacters: CharacterSet.urlQueryAllowed) { + if rawString.range(of: "%[0-9A-Fa-f]{2}", options: .regularExpression, range: nil, locale: nil) != nil { + return Foundation.URL(string: rawString) + } else if let encodedString_ = rawString.addingPercentEncoding(withAllowedCharacters: CharacterSet.urlQueryAllowed) { // We have to use `Foundation.URL` otherwise it conflicts with the variable name. return Foundation.URL(string: encodedString_) } else { @@ -966,7 +879,7 @@ extension JSON { } } set { - self.object = newValue?.absoluteString ?? NSNull() + object = newValue?.absoluteString ?? NSNull() } } } @@ -977,265 +890,265 @@ extension JSON { public var double: Double? { get { - return self.number?.doubleValue + return number?.doubleValue } set { if let newValue = newValue { - self.object = NSNumber(value: newValue) + object = NSNumber(value: newValue) } else { - self.object = NSNull() + object = NSNull() } } } public var doubleValue: Double { get { - return self.numberValue.doubleValue + return numberValue.doubleValue } set { - self.object = NSNumber(value: newValue) + object = NSNumber(value: newValue) } } public var float: Float? { get { - return self.number?.floatValue + return number?.floatValue } set { if let newValue = newValue { - self.object = NSNumber(value: newValue) + object = NSNumber(value: newValue) } else { - self.object = NSNull() + object = NSNull() } } } public var floatValue: Float { get { - return self.numberValue.floatValue + return numberValue.floatValue } set { - self.object = NSNumber(value: newValue) + object = NSNumber(value: newValue) } } public var int: Int? { get { - return self.number?.intValue + return number?.intValue } set { if let newValue = newValue { - self.object = NSNumber(value: newValue) + object = NSNumber(value: newValue) } else { - self.object = NSNull() + object = NSNull() } } } public var intValue: Int { get { - return self.numberValue.intValue + return numberValue.intValue } set { - self.object = NSNumber(value: newValue) + object = NSNumber(value: newValue) } } public var uInt: UInt? { get { - return self.number?.uintValue + return number?.uintValue } set { if let newValue = newValue { - self.object = NSNumber(value: newValue) + object = NSNumber(value: newValue) } else { - self.object = NSNull() + object = NSNull() } } } public var uIntValue: UInt { get { - return self.numberValue.uintValue + return numberValue.uintValue } set { - self.object = NSNumber(value: newValue) + object = NSNumber(value: newValue) } } public var int8: Int8? { get { - return self.number?.int8Value + return number?.int8Value } set { if let newValue = newValue { - self.object = NSNumber(value: Int(newValue)) + object = NSNumber(value: Int(newValue)) } else { - self.object = NSNull() + object = NSNull() } } } public var int8Value: Int8 { get { - return self.numberValue.int8Value + return numberValue.int8Value } set { - self.object = NSNumber(value: Int(newValue)) + object = NSNumber(value: Int(newValue)) } } public var uInt8: UInt8? { get { - return self.number?.uint8Value + return number?.uint8Value } set { if let newValue = newValue { - self.object = NSNumber(value: newValue) + object = NSNumber(value: newValue) } else { - self.object = NSNull() + object = NSNull() } } } public var uInt8Value: UInt8 { get { - return self.numberValue.uint8Value + return numberValue.uint8Value } set { - self.object = NSNumber(value: newValue) + object = NSNumber(value: newValue) } } public var int16: Int16? { get { - return self.number?.int16Value + return number?.int16Value } set { if let newValue = newValue { - self.object = NSNumber(value: newValue) + object = NSNumber(value: newValue) } else { - self.object = NSNull() + object = NSNull() } } } public var int16Value: Int16 { get { - return self.numberValue.int16Value + return numberValue.int16Value } set { - self.object = NSNumber(value: newValue) + object = NSNumber(value: newValue) } } public var uInt16: UInt16? { get { - return self.number?.uint16Value + return number?.uint16Value } set { if let newValue = newValue { - self.object = NSNumber(value: newValue) + object = NSNumber(value: newValue) } else { - self.object = NSNull() + object = NSNull() } } } public var uInt16Value: UInt16 { get { - return self.numberValue.uint16Value + return numberValue.uint16Value } set { - self.object = NSNumber(value: newValue) + object = NSNumber(value: newValue) } } public var int32: Int32? { get { - return self.number?.int32Value + return number?.int32Value } set { if let newValue = newValue { - self.object = NSNumber(value: newValue) + object = NSNumber(value: newValue) } else { - self.object = NSNull() + object = NSNull() } } } public var int32Value: Int32 { get { - return self.numberValue.int32Value + return numberValue.int32Value } set { - self.object = NSNumber(value: newValue) + object = NSNumber(value: newValue) } } public var uInt32: UInt32? { get { - return self.number?.uint32Value + return number?.uint32Value } set { if let newValue = newValue { - self.object = NSNumber(value: newValue) + object = NSNumber(value: newValue) } else { - self.object = NSNull() + object = NSNull() } } } public var uInt32Value: UInt32 { get { - return self.numberValue.uint32Value + return numberValue.uint32Value } set { - self.object = NSNumber(value: newValue) + object = NSNumber(value: newValue) } } public var int64: Int64? { get { - return self.number?.int64Value + return number?.int64Value } set { if let newValue = newValue { - self.object = NSNumber(value: newValue) + object = NSNumber(value: newValue) } else { - self.object = NSNull() + object = NSNull() } } } public var int64Value: Int64 { get { - return self.numberValue.int64Value + return numberValue.int64Value } set { - self.object = NSNumber(value: newValue) + object = NSNumber(value: newValue) } } public var uInt64: UInt64? { get { - return self.number?.uint64Value + return number?.uint64Value } set { if let newValue = newValue { - self.object = NSNumber(value: newValue) + object = NSNumber(value: newValue) } else { - self.object = NSNull() + object = NSNull() } } } public var uInt64Value: UInt64 { get { - return self.numberValue.uint64Value + return numberValue.uint64Value } set { - self.object = NSNumber(value: newValue) + object = NSNumber(value: newValue) } } } @@ -1247,84 +1160,57 @@ extension JSON: Swift.Comparable {} public func == (lhs: JSON, rhs: JSON) -> Bool { switch (lhs.type, rhs.type) { - case (.number, .number): - return lhs.rawNumber == rhs.rawNumber - case (.string, .string): - return lhs.rawString == rhs.rawString - case (.bool, .bool): - return lhs.rawBool == rhs.rawBool - case (.array, .array): - return lhs.rawArray as NSArray == rhs.rawArray as NSArray - case (.dictionary, .dictionary): - return lhs.rawDictionary as NSDictionary == rhs.rawDictionary as NSDictionary - case (.null, .null): - return true - default: - return false + case (.number, .number): return lhs.rawNumber == rhs.rawNumber + case (.string, .string): return lhs.rawString == rhs.rawString + case (.bool, .bool): return lhs.rawBool == rhs.rawBool + case (.array, .array): return lhs.rawArray as NSArray == rhs.rawArray as NSArray + case (.dictionary, .dictionary): return lhs.rawDictionary as NSDictionary == rhs.rawDictionary as NSDictionary + case (.null, .null): return true + default: return false } } public func <= (lhs: JSON, rhs: JSON) -> Bool { switch (lhs.type, rhs.type) { - case (.number, .number): - return lhs.rawNumber <= rhs.rawNumber - case (.string, .string): - return lhs.rawString <= rhs.rawString - case (.bool, .bool): - return lhs.rawBool == rhs.rawBool - case (.array, .array): - return lhs.rawArray as NSArray == rhs.rawArray as NSArray - case (.dictionary, .dictionary): - return lhs.rawDictionary as NSDictionary == rhs.rawDictionary as NSDictionary - case (.null, .null): - return true - default: - return false + case (.number, .number): return lhs.rawNumber <= rhs.rawNumber + case (.string, .string): return lhs.rawString <= rhs.rawString + case (.bool, .bool): return lhs.rawBool == rhs.rawBool + case (.array, .array): return lhs.rawArray as NSArray == rhs.rawArray as NSArray + case (.dictionary, .dictionary): return lhs.rawDictionary as NSDictionary == rhs.rawDictionary as NSDictionary + case (.null, .null): return true + default: return false } } public func >= (lhs: JSON, rhs: JSON) -> Bool { switch (lhs.type, rhs.type) { - case (.number, .number): - return lhs.rawNumber >= rhs.rawNumber - case (.string, .string): - return lhs.rawString >= rhs.rawString - case (.bool, .bool): - return lhs.rawBool == rhs.rawBool - case (.array, .array): - return lhs.rawArray as NSArray == rhs.rawArray as NSArray - case (.dictionary, .dictionary): - return lhs.rawDictionary as NSDictionary == rhs.rawDictionary as NSDictionary - case (.null, .null): - return true - default: - return false + case (.number, .number): return lhs.rawNumber >= rhs.rawNumber + case (.string, .string): return lhs.rawString >= rhs.rawString + case (.bool, .bool): return lhs.rawBool == rhs.rawBool + case (.array, .array): return lhs.rawArray as NSArray == rhs.rawArray as NSArray + case (.dictionary, .dictionary): return lhs.rawDictionary as NSDictionary == rhs.rawDictionary as NSDictionary + case (.null, .null): return true + default: return false } } public func > (lhs: JSON, rhs: JSON) -> Bool { switch (lhs.type, rhs.type) { - case (.number, .number): - return lhs.rawNumber > rhs.rawNumber - case (.string, .string): - return lhs.rawString > rhs.rawString - default: - return false + case (.number, .number): return lhs.rawNumber > rhs.rawNumber + case (.string, .string): return lhs.rawString > rhs.rawString + default: return false } } public func < (lhs: JSON, rhs: JSON) -> Bool { switch (lhs.type, rhs.type) { - case (.number, .number): - return lhs.rawNumber < rhs.rawNumber - case (.string, .string): - return lhs.rawString < rhs.rawString - default: - return false + case (.number, .number): return lhs.rawNumber < rhs.rawNumber + case (.string, .string): return lhs.rawString < rhs.rawString + default: return false } } @@ -1348,12 +1234,9 @@ extension NSNumber { func == (lhs: NSNumber, rhs: NSNumber) -> Bool { switch (lhs.isBool, rhs.isBool) { - case (false, true): - return false - case (true, false): - return false - default: - return lhs.compare(rhs) == .orderedSame + case (false, true): return false + case (true, false): return false + default: return lhs.compare(rhs) == .orderedSame } } @@ -1364,48 +1247,36 @@ func != (lhs: NSNumber, rhs: NSNumber) -> Bool { func < (lhs: NSNumber, rhs: NSNumber) -> Bool { switch (lhs.isBool, rhs.isBool) { - case (false, true): - return false - case (true, false): - return false - default: - return lhs.compare(rhs) == .orderedAscending + case (false, true): return false + case (true, false): return false + default: return lhs.compare(rhs) == .orderedAscending } } func > (lhs: NSNumber, rhs: NSNumber) -> Bool { switch (lhs.isBool, rhs.isBool) { - case (false, true): - return false - case (true, false): - return false - default: - return lhs.compare(rhs) == ComparisonResult.orderedDescending + case (false, true): return false + case (true, false): return false + default: return lhs.compare(rhs) == ComparisonResult.orderedDescending } } func <= (lhs: NSNumber, rhs: NSNumber) -> Bool { switch (lhs.isBool, rhs.isBool) { - case (false, true): - return false - case (true, false): - return false - default: - return lhs.compare(rhs) != .orderedDescending + case (false, true): return false + case (true, false): return false + default: return lhs.compare(rhs) != .orderedDescending } } func >= (lhs: NSNumber, rhs: NSNumber) -> Bool { switch (lhs.isBool, rhs.isBool) { - case (false, true): - return false - case (true, false): - return false - default: - return lhs.compare(rhs) != .orderedAscending + case (false, true): return false + case (true, false): return false + default: return lhs.compare(rhs) != .orderedAscending } } diff --git a/SwiftyJSON.podspec b/SwiftyJSON.podspec index d5fbc3d1..dd091231 100644 --- a/SwiftyJSON.podspec +++ b/SwiftyJSON.podspec @@ -1,17 +1,18 @@ Pod::Spec.new do |s| s.name = "SwiftyJSON" - s.version = "4.2.0" + s.version = "5.0.2" s.summary = "SwiftyJSON makes it easy to deal with JSON data in Swift" s.homepage = "https://github.com/SwiftyJSON/SwiftyJSON" s.license = { :type => "MIT" } s.authors = { "lingoer" => "lingoerer@gmail.com", "tangplin" => "tangplin@gmail.com" } s.requires_arc = true - s.swift_version = "4.2" + s.swift_version = "5.0" s.osx.deployment_target = "10.9" - s.ios.deployment_target = "8.0" + s.ios.deployment_target = "9.0" s.watchos.deployment_target = "3.0" s.tvos.deployment_target = "9.0" s.source = { :git => "https://github.com/SwiftyJSON/SwiftyJSON.git", :tag => s.version } - s.source_files = "Source/*.swift" + s.source_files = "Source/SwiftyJSON/*.swift" + s.resource_bundles = {'SwiftyJSON' => ['Source/SwiftyJSON/PrivacyInfo.xcprivacy']} end diff --git a/SwiftyJSON.xcodeproj/project.pbxproj b/SwiftyJSON.xcodeproj/project.pbxproj index be176003..3c325ac2 100644 --- a/SwiftyJSON.xcodeproj/project.pbxproj +++ b/SwiftyJSON.xcodeproj/project.pbxproj @@ -51,6 +51,10 @@ 9C459F041A9103C1008C9A41 /* DictionaryTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = A8B66C8B19E51D6500540692 /* DictionaryTests.swift */; }; 9C459F051A9103C1008C9A41 /* ArrayTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = A8B66C8D19E52F4200540692 /* ArrayTests.swift */; }; 9C7DFC661A9102BD005AA3F7 /* SwiftyJSON.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9C7DFC5B1A9102BD005AA3F7 /* SwiftyJSON.framework */; }; + A1DE64C62BC7D95C0097BCE6 /* PrivacyInfo.xcprivacy in Resources */ = {isa = PBXBuildFile; fileRef = A1DE64C52BC7D95C0097BCE6 /* PrivacyInfo.xcprivacy */; }; + A1DE64C72BC7D95C0097BCE6 /* PrivacyInfo.xcprivacy in Resources */ = {isa = PBXBuildFile; fileRef = A1DE64C52BC7D95C0097BCE6 /* PrivacyInfo.xcprivacy */; }; + A1DE64C82BC7D95C0097BCE6 /* PrivacyInfo.xcprivacy in Resources */ = {isa = PBXBuildFile; fileRef = A1DE64C52BC7D95C0097BCE6 /* PrivacyInfo.xcprivacy */; }; + A1DE64C92BC7D95C0097BCE6 /* PrivacyInfo.xcprivacy in Resources */ = {isa = PBXBuildFile; fileRef = A1DE64C52BC7D95C0097BCE6 /* PrivacyInfo.xcprivacy */; }; A819C49719E1A7DD00ADCC3D /* LiteralConvertibleTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = A819C49619E1A7DD00ADCC3D /* LiteralConvertibleTests.swift */; }; A819C49919E1B10300ADCC3D /* RawRepresentableTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = A819C49819E1B10300ADCC3D /* RawRepresentableTests.swift */; }; A819C49F19E2EE5B00ADCC3D /* SubscriptTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = A819C49E19E2EE5B00ADCC3D /* SubscriptTests.swift */; }; @@ -114,37 +118,38 @@ /* Begin PBXFileReference section */ 030B6CDC1A6E171D00C2D4F1 /* Info-macOS.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "Info-macOS.plist"; sourceTree = ""; }; - 1B587CC41DDE04360012D8DB /* MergeTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = MergeTests.swift; path = ../MergeTests.swift; sourceTree = ""; }; + 1B587CC41DDE04360012D8DB /* MergeTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = MergeTests.swift; path = ../SwiftJSONTests/MergeTests.swift; sourceTree = ""; }; 2E4FEFDB19575BE100351305 /* SwiftyJSON.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SwiftyJSON.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 2E4FEFDF19575BE100351305 /* Info-iOS.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "Info-iOS.plist"; sourceTree = ""; }; - 2E4FEFE019575BE100351305 /* SwiftyJSON.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SwiftyJSON.h; sourceTree = ""; }; + 2E4FEFE019575BE100351305 /* SwiftyJSON.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = SwiftyJSON.h; path = SwiftyJSON/SwiftyJSON.h; sourceTree = ""; }; 2E4FEFE619575BE100351305 /* SwiftyJSON iOS Tests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "SwiftyJSON iOS Tests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; - 5DD502901D9B21810004C112 /* NestedJSONTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = NestedJSONTests.swift; path = ../NestedJSONTests.swift; sourceTree = ""; }; - 712921EE2004E4EB00DA6340 /* CodableTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = CodableTests.swift; path = ../CodableTests.swift; sourceTree = ""; }; + 5DD502901D9B21810004C112 /* NestedJSONTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = NestedJSONTests.swift; path = ../SwiftJSONTests/NestedJSONTests.swift; sourceTree = ""; }; + 712921EE2004E4EB00DA6340 /* CodableTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = CodableTests.swift; path = ../SwiftJSONTests/CodableTests.swift; sourceTree = ""; }; 7236B4F61BAC14150020529B /* SwiftyJSON.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SwiftyJSON.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 7236B4F71BAC14150020529B /* Info-tvOS.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "Info-tvOS.plist"; sourceTree = ""; }; 9C459EF61A9103B1008C9A41 /* Info-macOS.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = "Info-macOS.plist"; path = "../Info-macOS.plist"; sourceTree = ""; }; 9C7DFC5B1A9102BD005AA3F7 /* SwiftyJSON.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SwiftyJSON.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 9C7DFC651A9102BD005AA3F7 /* SwiftyJSON macOS Tests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "SwiftyJSON macOS Tests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; - A819C49619E1A7DD00ADCC3D /* LiteralConvertibleTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = LiteralConvertibleTests.swift; path = ../LiteralConvertibleTests.swift; sourceTree = ""; }; - A819C49819E1B10300ADCC3D /* RawRepresentableTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = RawRepresentableTests.swift; path = ../RawRepresentableTests.swift; sourceTree = ""; }; - A819C49E19E2EE5B00ADCC3D /* SubscriptTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = SubscriptTests.swift; path = ../SubscriptTests.swift; sourceTree = ""; }; - A819C4A019E37FC600ADCC3D /* PrintableTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = PrintableTests.swift; path = ../PrintableTests.swift; sourceTree = ""; }; + A1DE64C52BC7D95C0097BCE6 /* PrivacyInfo.xcprivacy */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; name = PrivacyInfo.xcprivacy; path = SwiftyJSON/PrivacyInfo.xcprivacy; sourceTree = ""; }; + A819C49619E1A7DD00ADCC3D /* LiteralConvertibleTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = LiteralConvertibleTests.swift; path = ../SwiftJSONTests/LiteralConvertibleTests.swift; sourceTree = ""; }; + A819C49819E1B10300ADCC3D /* RawRepresentableTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = RawRepresentableTests.swift; path = ../SwiftJSONTests/RawRepresentableTests.swift; sourceTree = ""; }; + A819C49E19E2EE5B00ADCC3D /* SubscriptTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = SubscriptTests.swift; path = ../SwiftJSONTests/SubscriptTests.swift; sourceTree = ""; }; + A819C4A019E37FC600ADCC3D /* PrintableTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = PrintableTests.swift; path = ../SwiftJSONTests/PrintableTests.swift; sourceTree = ""; }; A82A1C0D19D922DC009A653D /* Info-iOS.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = "Info-iOS.plist"; path = "../Info-iOS.plist"; sourceTree = ""; }; - A830A6941E5B2DD8001D7F6D /* MutabilityTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = MutabilityTests.swift; path = ../MutabilityTests.swift; sourceTree = ""; }; - A8491E1D19CD6DAE00CCFAE6 /* SwiftyJSON.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SwiftyJSON.swift; sourceTree = ""; }; + A830A6941E5B2DD8001D7F6D /* MutabilityTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = MutabilityTests.swift; path = ../SwiftJSONTests/MutabilityTests.swift; sourceTree = ""; }; + A8491E1D19CD6DAE00CCFAE6 /* SwiftyJSON.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = SwiftyJSON.swift; path = SwiftyJSON/SwiftyJSON.swift; sourceTree = ""; }; A8580F741BCF5C5B00DA927B /* SwiftyJSON tvOS Tests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "SwiftyJSON tvOS Tests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; A8580F781BCF5C5B00DA927B /* Info-tvOS.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = "Info-tvOS.plist"; path = "../Info-tvOS.plist"; sourceTree = ""; }; - A863BE2719EED46F0092A41F /* RawTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = RawTests.swift; path = ../RawTests.swift; sourceTree = ""; }; - A86BAA0D19EBC32B009EAAEB /* PerformanceTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = PerformanceTests.swift; path = ../PerformanceTests.swift; sourceTree = ""; }; - A87080E319E3C2A600CDE086 /* SequenceTypeTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = SequenceTypeTests.swift; path = ../SequenceTypeTests.swift; sourceTree = ""; }; - A87080E519E3DF7800CDE086 /* ComparableTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ComparableTests.swift; path = ../ComparableTests.swift; sourceTree = ""; }; - A87080E719E439DA00CDE086 /* NumberTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = NumberTests.swift; path = ../NumberTests.swift; sourceTree = ""; }; - A87080E919E43C0700CDE086 /* StringTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = StringTests.swift; path = ../StringTests.swift; sourceTree = ""; }; - A885D1D119CF1EE6002FD4C3 /* BaseTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = BaseTests.swift; path = ../BaseTests.swift; sourceTree = ""; }; + A863BE2719EED46F0092A41F /* RawTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = RawTests.swift; path = ../SwiftJSONTests/RawTests.swift; sourceTree = ""; }; + A86BAA0D19EBC32B009EAAEB /* PerformanceTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = PerformanceTests.swift; path = ../SwiftJSONTests/PerformanceTests.swift; sourceTree = ""; }; + A87080E319E3C2A600CDE086 /* SequenceTypeTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = SequenceTypeTests.swift; path = ../SwiftJSONTests/SequenceTypeTests.swift; sourceTree = ""; }; + A87080E519E3DF7800CDE086 /* ComparableTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ComparableTests.swift; path = ../SwiftJSONTests/ComparableTests.swift; sourceTree = ""; }; + A87080E719E439DA00CDE086 /* NumberTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = NumberTests.swift; path = ../SwiftJSONTests/NumberTests.swift; sourceTree = ""; }; + A87080E919E43C0700CDE086 /* StringTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = StringTests.swift; path = ../SwiftJSONTests/StringTests.swift; sourceTree = ""; }; + A885D1D119CF1EE6002FD4C3 /* BaseTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = BaseTests.swift; path = ../SwiftJSONTests/BaseTests.swift; sourceTree = ""; }; A885D1DA19CFCFF0002FD4C3 /* Tests.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = Tests.json; sourceTree = ""; }; - A8B66C8B19E51D6500540692 /* DictionaryTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = DictionaryTests.swift; path = ../DictionaryTests.swift; sourceTree = ""; }; - A8B66C8D19E52F4200540692 /* ArrayTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ArrayTests.swift; path = ../ArrayTests.swift; sourceTree = ""; }; + A8B66C8B19E51D6500540692 /* DictionaryTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = DictionaryTests.swift; path = ../SwiftJSONTests/DictionaryTests.swift; sourceTree = ""; }; + A8B66C8D19E52F4200540692 /* ArrayTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ArrayTests.swift; path = ../SwiftJSONTests/ArrayTests.swift; sourceTree = ""; }; E4D7CCE81B9465A700EE7221 /* SwiftyJSON.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SwiftyJSON.framework; sourceTree = BUILT_PRODUCTS_DIR; }; E4D7CCE91B9465A800EE7221 /* Info-watchOS.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "Info-watchOS.plist"; sourceTree = ""; }; /* End PBXFileReference section */ @@ -241,6 +246,7 @@ 2E4FEFDE19575BE100351305 /* Supporting Files */ = { isa = PBXGroup; children = ( + A1DE64C52BC7D95C0097BCE6 /* PrivacyInfo.xcprivacy */, 2E4FEFDF19575BE100351305 /* Info-iOS.plist */, 030B6CDC1A6E171D00C2D4F1 /* Info-macOS.plist */, E4D7CCE91B9465A800EE7221 /* Info-watchOS.plist */, @@ -272,7 +278,7 @@ 2E4FEFEB19575BE100351305 /* Supporting Files */, ); name = Tests; - path = Tests/Tes; + path = Tests/SwiftJSONTests; sourceTree = ""; }; 2E4FEFEB19575BE100351305 /* Supporting Files */ = { @@ -328,9 +334,9 @@ isa = PBXNativeTarget; buildConfigurationList = 2E4FEFF119575BE100351305 /* Build configuration list for PBXNativeTarget "SwiftyJSON iOS" */; buildPhases = ( + 2E4FEFD819575BE100351305 /* Headers */, 2E4FEFD619575BE100351305 /* Sources */, 2E4FEFD719575BE100351305 /* Frameworks */, - 2E4FEFD819575BE100351305 /* Headers */, 2E4FEFD919575BE100351305 /* Resources */, ); buildRules = ( @@ -364,9 +370,9 @@ isa = PBXNativeTarget; buildConfigurationList = 7236B4F31BAC14150020529B /* Build configuration list for PBXNativeTarget "SwiftyJSON tvOS" */; buildPhases = ( + 7236B4F01BAC14150020529B /* Headers */, 7236B4ED1BAC14150020529B /* Sources */, 7236B4EF1BAC14150020529B /* Frameworks */, - 7236B4F01BAC14150020529B /* Headers */, 7236B4F21BAC14150020529B /* Resources */, ); buildRules = ( @@ -382,9 +388,9 @@ isa = PBXNativeTarget; buildConfigurationList = 9C7DFC6E1A9102BD005AA3F7 /* Build configuration list for PBXNativeTarget "SwiftyJSON macOS" */; buildPhases = ( + 9C7DFC581A9102BD005AA3F7 /* Headers */, 9C7DFC561A9102BD005AA3F7 /* Sources */, 9C7DFC571A9102BD005AA3F7 /* Frameworks */, - 9C7DFC581A9102BD005AA3F7 /* Headers */, 9C7DFC591A9102BD005AA3F7 /* Resources */, ); buildRules = ( @@ -436,9 +442,9 @@ isa = PBXNativeTarget; buildConfigurationList = E4D7CCE51B9465A700EE7221 /* Build configuration list for PBXNativeTarget "SwiftyJSON watchOS" */; buildPhases = ( + E4D7CCE21B9465A700EE7221 /* Headers */, E4D7CCDF1B9465A700EE7221 /* Sources */, E4D7CCE11B9465A700EE7221 /* Frameworks */, - E4D7CCE21B9465A700EE7221 /* Headers */, E4D7CCE41B9465A700EE7221 /* Resources */, ); buildRules = ( @@ -457,7 +463,7 @@ isa = PBXProject; attributes = { LastSwiftUpdateCheck = 0710; - LastUpgradeCheck = 0930; + LastUpgradeCheck = 1020; TargetAttributes = { 2E4FEFDA19575BE100351305 = { CreatedOnToolsVersion = 6.0; @@ -499,10 +505,11 @@ }; buildConfigurationList = 2E4FEFD519575BE100351305 /* Build configuration list for PBXProject "SwiftyJSON" */; compatibilityVersion = "Xcode 3.2"; - developmentRegion = English; + developmentRegion = en; hasScannedForEncodings = 0; knownRegions = ( en, + Base, ); mainGroup = 2E4FEFD119575BE100351305; productRefGroup = 2E4FEFDC19575BE100351305 /* Products */; @@ -526,6 +533,7 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( + A1DE64C62BC7D95C0097BCE6 /* PrivacyInfo.xcprivacy in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -541,6 +549,7 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( + A1DE64C92BC7D95C0097BCE6 /* PrivacyInfo.xcprivacy in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -548,6 +557,7 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( + A1DE64C72BC7D95C0097BCE6 /* PrivacyInfo.xcprivacy in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -571,6 +581,7 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( + A1DE64C82BC7D95C0097BCE6 /* PrivacyInfo.xcprivacy in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -722,6 +733,7 @@ isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; @@ -765,7 +777,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 8.0; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; MACOSX_DEPLOYMENT_TARGET = 10.9; METAL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; @@ -782,6 +794,7 @@ isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; @@ -819,7 +832,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 8.0; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; MACOSX_DEPLOYMENT_TARGET = 10.9; METAL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; @@ -846,14 +859,14 @@ GCC_OPTIMIZATION_LEVEL = 0; INFOPLIST_FILE = "Source/Info-iOS.plist"; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - IPHONEOS_DEPLOYMENT_TARGET = 8.0; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = "com.swiftyjson.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = SwiftyJSON; SKIP_INSTALL = YES; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_SWIFT3_OBJC_INFERENCE = Default; - SWIFT_VERSION = 4.0; + SWIFT_VERSION = 5.0; }; name = Debug; }; @@ -871,13 +884,13 @@ GCC_OPTIMIZATION_LEVEL = s; INFOPLIST_FILE = "Source/Info-iOS.plist"; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - IPHONEOS_DEPLOYMENT_TARGET = 8.0; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = "com.swiftyjson.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = SwiftyJSON; SKIP_INSTALL = YES; SWIFT_SWIFT3_OBJC_INFERENCE = Default; - SWIFT_VERSION = 4.0; + SWIFT_VERSION = 5.0; }; name = Release; }; @@ -899,7 +912,7 @@ PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_SWIFT3_OBJC_INFERENCE = Default; - SWIFT_VERSION = 4.0; + SWIFT_VERSION = 5.0; }; name = Debug; }; @@ -916,7 +929,7 @@ PRODUCT_BUNDLE_IDENTIFIER = "com.swiftyjson.${PRODUCT_NAME:rfc1034identifier}"; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_SWIFT3_OBJC_INFERENCE = Default; - SWIFT_VERSION = 4.0; + SWIFT_VERSION = 5.0; }; name = Release; }; @@ -934,14 +947,13 @@ GCC_OPTIMIZATION_LEVEL = 0; INFOPLIST_FILE = "Source/Info-tvOS.plist"; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - IPHONEOS_DEPLOYMENT_TARGET = 8.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = "com.swiftyjson.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = SwiftyJSON; SDKROOT = appletvos; SKIP_INSTALL = YES; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - SWIFT_VERSION = 4.2; + SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = 3; TVOS_DEPLOYMENT_TARGET = 9.0; }; @@ -961,13 +973,12 @@ GCC_OPTIMIZATION_LEVEL = s; INFOPLIST_FILE = "Source/Info-tvOS.plist"; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - IPHONEOS_DEPLOYMENT_TARGET = 8.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = "com.swiftyjson.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = SwiftyJSON; SDKROOT = appletvos; SKIP_INSTALL = YES; - SWIFT_VERSION = 4.2; + SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = 3; TVOS_DEPLOYMENT_TARGET = 9.0; }; @@ -1000,7 +1011,7 @@ SDKROOT = macosx; SKIP_INSTALL = YES; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - SWIFT_VERSION = 4.2; + SWIFT_VERSION = 5.0; }; name = Debug; }; @@ -1027,7 +1038,7 @@ PRODUCT_NAME = "$(PROJECT_NAME)"; SDKROOT = macosx; SKIP_INSTALL = YES; - SWIFT_VERSION = 4.2; + SWIFT_VERSION = 5.0; }; name = Release; }; @@ -1050,7 +1061,7 @@ PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = macosx; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - SWIFT_VERSION = 4.2; + SWIFT_VERSION = 5.0; }; name = Debug; }; @@ -1069,7 +1080,7 @@ PRODUCT_BUNDLE_IDENTIFIER = "com.swiftyjson.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = macosx; - SWIFT_VERSION = 4.2; + SWIFT_VERSION = 5.0; }; name = Release; }; @@ -1103,7 +1114,7 @@ PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = appletvos; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - SWIFT_VERSION = 4.2; + SWIFT_VERSION = 5.0; TVOS_DEPLOYMENT_TARGET = 9.0; }; name = Debug; @@ -1122,7 +1133,7 @@ PRODUCT_BUNDLE_IDENTIFIER = "com.tangplin.SwiftyJSON-tvOS-Tests"; PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = appletvos; - SWIFT_VERSION = 4.2; + SWIFT_VERSION = 5.0; TVOS_DEPLOYMENT_TARGET = 9.0; }; name = Release; @@ -1149,7 +1160,7 @@ SKIP_INSTALL = YES; SUPPORTED_PLATFORMS = "watchsimulator watchos"; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - SWIFT_VERSION = 4.2; + SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = 4; WATCHOS_DEPLOYMENT_TARGET = 3.0; }; @@ -1176,7 +1187,7 @@ SDKROOT = watchos; SKIP_INSTALL = YES; SUPPORTED_PLATFORMS = "watchsimulator watchos"; - SWIFT_VERSION = 4.2; + SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = 4; WATCHOS_DEPLOYMENT_TARGET = 3.0; }; diff --git a/SwiftyJSON.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/SwiftyJSON.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 00000000..18d98100 --- /dev/null +++ b/SwiftyJSON.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/SwiftyJSON.xcodeproj/xcshareddata/xcschemes/SwiftyJSON iOS.xcscheme b/SwiftyJSON.xcodeproj/xcshareddata/xcschemes/SwiftyJSON iOS.xcscheme index 98076542..f4d10cb9 100644 --- a/SwiftyJSON.xcodeproj/xcshareddata/xcschemes/SwiftyJSON iOS.xcscheme +++ b/SwiftyJSON.xcodeproj/xcshareddata/xcschemes/SwiftyJSON iOS.xcscheme @@ -1,6 +1,6 @@ String { + json["name"].stringValue + } + + func extractType(_ json: JSON) -> Type { + json["value"].type + } + + func requireField(_ json: JSON) throws -> String { + guard json["required"].exists() else { + throw SwiftyJSONError.notExist + } + return json["required"].stringValue + } + } + + /// Verifies JSON conforms to Sendable (can cross actor boundary) + func testJSONSendable() async { + let json = JSON(["name": "test", "count": 42]) + let processor = Processor() + + let result = await processor.extract(json) + + XCTAssertEqual(result, "test") + } + + /// Verifies Type enum conforms to Sendable (can be returned across actor boundary) + func testTypeSendable() async { + let processor = Processor() + + let stringType = await processor.extractType(JSON(["value": "hello"])) + let numberType = await processor.extractType(JSON(["value": 123])) + let boolType = await processor.extractType(JSON(["value": true])) + let nullType = await processor.extractType(JSON(["value": NSNull()])) + let arrayType = await processor.extractType(JSON(["value": [1, 2, 3]])) + let dictType = await processor.extractType(JSON(["value": ["nested": "object"]])) + + XCTAssertEqual(stringType, .string) + XCTAssertEqual(numberType, .number) + XCTAssertEqual(boolType, .bool) + XCTAssertEqual(nullType, .null) + XCTAssertEqual(arrayType, .array) + XCTAssertEqual(dictType, .dictionary) + } + + /// Verifies SwiftyJSONError conforms to Sendable (can be thrown across actor boundary) + func testSwiftyJSONErrorSendable() async { + let processor = Processor() + + do { + _ = try await processor.requireField(JSON(["other": "value"])) + XCTFail("Should have thrown") + } catch SwiftyJSONError.notExist { + // Error successfully crossed actor boundary + } catch { + XCTFail("Unexpected error: \(error)") + } + } +} diff --git a/Tests/DictionaryTests.swift b/Tests/SwiftJSONTests/DictionaryTests.swift similarity index 100% rename from Tests/DictionaryTests.swift rename to Tests/SwiftJSONTests/DictionaryTests.swift diff --git a/Tests/LiteralConvertibleTests.swift b/Tests/SwiftJSONTests/LiteralConvertibleTests.swift similarity index 100% rename from Tests/LiteralConvertibleTests.swift rename to Tests/SwiftJSONTests/LiteralConvertibleTests.swift diff --git a/Tests/MergeTests.swift b/Tests/SwiftJSONTests/MergeTests.swift similarity index 100% rename from Tests/MergeTests.swift rename to Tests/SwiftJSONTests/MergeTests.swift diff --git a/Tests/MutabilityTests.swift b/Tests/SwiftJSONTests/MutabilityTests.swift similarity index 100% rename from Tests/MutabilityTests.swift rename to Tests/SwiftJSONTests/MutabilityTests.swift diff --git a/Tests/NestedJSONTests.swift b/Tests/SwiftJSONTests/NestedJSONTests.swift similarity index 100% rename from Tests/NestedJSONTests.swift rename to Tests/SwiftJSONTests/NestedJSONTests.swift diff --git a/Tests/NumberTests.swift b/Tests/SwiftJSONTests/NumberTests.swift similarity index 100% rename from Tests/NumberTests.swift rename to Tests/SwiftJSONTests/NumberTests.swift diff --git a/Tests/PerformanceTests.swift b/Tests/SwiftJSONTests/PerformanceTests.swift similarity index 93% rename from Tests/PerformanceTests.swift rename to Tests/SwiftJSONTests/PerformanceTests.swift index 7535f7d8..c0e6cc0b 100644 --- a/Tests/PerformanceTests.swift +++ b/Tests/SwiftJSONTests/PerformanceTests.swift @@ -30,8 +30,13 @@ class PerformanceTests: XCTestCase { override func setUp() { super.setUp() - if let file = Bundle(for: PerformanceTests.self).path(forResource: "Tests", ofType: "json") { - self.testData = try? Data(contentsOf: URL(fileURLWithPath: file)) + #if SWIFT_PACKAGE + let testBundle = Bundle.module + #else + let testBundle = Bundle(for: PerformanceTests.self) + #endif + if let file = testBundle.url(forResource: "Tests", withExtension: "json") { + self.testData = try? Data(contentsOf: file) } else { XCTFail("Can't find the test JSON file") } diff --git a/Tests/PrintableTests.swift b/Tests/SwiftJSONTests/PrintableTests.swift similarity index 100% rename from Tests/PrintableTests.swift rename to Tests/SwiftJSONTests/PrintableTests.swift diff --git a/Tests/RawRepresentableTests.swift b/Tests/SwiftJSONTests/RawRepresentableTests.swift similarity index 96% rename from Tests/RawRepresentableTests.swift rename to Tests/SwiftJSONTests/RawRepresentableTests.swift index 9c628a05..88a70de8 100644 --- a/Tests/RawRepresentableTests.swift +++ b/Tests/SwiftJSONTests/RawRepresentableTests.swift @@ -84,6 +84,12 @@ class RawRepresentableTests: XCTestCase { if JSON(rawValue: NSObject()) != nil { XCTFail("Should not run into here") } + + do { + let n: Int? = nil + let json = JSON(n as Any) + XCTAssertEqual(json.type, .null) + } } func testArray() { diff --git a/Tests/RawTests.swift b/Tests/SwiftJSONTests/RawTests.swift similarity index 100% rename from Tests/RawTests.swift rename to Tests/SwiftJSONTests/RawTests.swift diff --git a/Tests/SequenceTypeTests.swift b/Tests/SwiftJSONTests/SequenceTypeTests.swift similarity index 95% rename from Tests/SequenceTypeTests.swift rename to Tests/SwiftJSONTests/SequenceTypeTests.swift index d0d8cadd..a039453f 100644 --- a/Tests/SequenceTypeTests.swift +++ b/Tests/SwiftJSONTests/SequenceTypeTests.swift @@ -25,10 +25,17 @@ import SwiftyJSON class SequenceTypeTests: XCTestCase { + var testData: Data? + func testJSONFile() { - if let file = Bundle(for: BaseTests.self).path(forResource: "Tests", ofType: "json") { - let testData = try? Data(contentsOf: URL(fileURLWithPath: file)) - guard let json = try? JSON(data: testData!) else { + #if SWIFT_PACKAGE + let testBundle = Bundle.module + #else + let testBundle = Bundle(for: SequenceTypeTests.self) + #endif + if let file = testBundle.url(forResource: "Tests", withExtension: "json") { + self.testData = try? Data(contentsOf: file) + guard let json = try? JSON(data: self.testData!) else { XCTFail("Unable to parse the data") return } diff --git a/Tests/StringTests.swift b/Tests/SwiftJSONTests/StringTests.swift similarity index 100% rename from Tests/StringTests.swift rename to Tests/SwiftJSONTests/StringTests.swift diff --git a/Tests/SubscriptTests.swift b/Tests/SwiftJSONTests/SubscriptTests.swift similarity index 100% rename from Tests/SubscriptTests.swift rename to Tests/SwiftJSONTests/SubscriptTests.swift diff --git a/Tests/Tes/Tests.json b/Tests/SwiftJSONTests/Tests.json similarity index 100% rename from Tests/Tes/Tests.json rename to Tests/SwiftJSONTests/Tests.json