Small knowledge, big challenge! This paper is participating in theEssentials for programmers”Creative activities.
preface
The jSON-to-Model approach in Swift is now dominated by Codable protocol, which is native and simple, making jSON-to-Model a CV application.
But this does not affect us to learn the essence of the previous code, this time to share my previous reading SwiftyJSON source code a little experience.
The SwiftJSON source code adds up to less than 1500 lines. I’ve gone through it a few times, but I’m just listing what I think I can use.
CustomNSError Protocol usage
In fact, this protocol inherits from Error. It should be noted that this protocol CustomNSError is more convenient to convert Error to NSError and use as.
Let’s first look at how the CustomNSError protocol is defined:
public protocol CustomNSError : Error {
/// The domain of the error.
static var errorDomain: String { get }
/// The error code within the given domain.
var errorCode: Int { get }
/// The user-info dictionary.
var errorUserInfo: [String : Any] { get }
}
Copy the code
SwiftJSON source code is as follows:
public enum SwiftyJSONError: Int, Swift.Error { case unsupportedType = 999 case indexOutOfBounds = 900 case elementTooDeep = 902 case wrongType = 901 case notExist = 500 case invalidJSON = 490 } extension SwiftyJSONError: CustomNSError { /// return the error domain of SwiftyJSONError public static var errorDomain: String { return "com.swiftyjson.SwiftyJSON" } /// return the error code of SwiftyJSONError public var errorCode: Int { return self.rawValue } /// return the userInfo of SwiftyJSONError public var errorUserInfo: [String: Any] { switch self { case .unsupportedType: return [NSLocalizedDescriptionKey: "It is an unsupported type."] case .indexOutOfBounds: return [NSLocalizedDescriptionKey: "Array Index is out of bounds."] case .wrongType: return [NSLocalizedDescriptionKey: "Couldn't merge, because the JSONs differ in type on top level."] case .notExist: return [NSLocalizedDescriptionKey: "Dictionary key does not exist."] case .invalidJSON: return [NSLocalizedDescriptionKey: "JSON is invalid."] case .elementTooDeep: return [NSLocalizedDescriptionKey: "Element too deep. Increase maxObjectDepth and make sure there is no reference loop."] } } }Copy the code
Enum SwiftyJSONError: Int, swif.error
The thing that defines SwiftyJSONError is that this enumeration inherits an Int, which is exactly what defines the rawValue of the enumeration as an Int.
Why?
Because of the CustomNSError protocol, you must return the errorCode property, which can be used seamlessly if the enumeration rawValue is of type Int.
Here’s a quick tip for writing SwiftyJSON.
Replace as usage with switch
In general, when we have an object and we need to convert the use of the type this is how I use it
func toNSURL(url: Any) -> NSURL? {if url is NSURL {return url as! NSURL } if url is URL { return (url as! URL) as NSURL } if url is String { return NSURL(string: (url as! String)) } return nil }Copy the code
In fact, this is completely handled by the switch
func asNSURL(any: Any) -> NSURL? {
switch any {
case let nsURL as NSURL:
return nsURL
case let url as URL:
return url as NSURL
case let string as String:
return NSURL(string: string)
default:
return nil
}
}
Copy the code
Less forced unpacking, less insecurity, less annoyance.
Source code source, which also contains a recursive call in the map function, and SwiftJSON is used in many places:
private func unwrap(_ object: Any) -> Any {
switch object {
case let json as JSON:
return unwrap(json.object)
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
default:
return object
}
}
Copy the code
NSNumber comparison processing
SwiftJSON: SwiftJSON: SwiftJSON: SwiftJSON: SwiftJSON: SwiftJSON: SwiftJSON: SwiftJSON: SwiftJSON
private let trueNumber = NSNumber(value: true) private let falseNumber = NSNumber(value: false) private let trueObjCType = String(cString: trueNumber.objCType) private let falseObjCType = String(cString: falseNumber.objCType) // MARK: - NSNumber: Comparable extension NSNumber { fileprivate var isBool: Bool { let objCType = String(cString: self.objCType) if (self.compare(trueNumber) == .orderedSame && objCType == trueObjCType) || (self.compare(falseNumber) == .orderedSame && objCType == falseObjCType) { return true } else { return false } } } 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 } } func ! = (lhs: NSNumber, rhs: NSNumber) -> Bool { return ! (lhs == rhs) } 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 } } 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 } } 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 } } 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 } }Copy the code
This code is more clever through the extension of NSNumber, by writing operators to represent two NSNumber objects are equal, unequal, greater than, less than, greater than or equal to, less than or equal to several cases.
In addition, the usage of switch is shown incisively and vividly, and the comparison of NSNumber is divided into two cases: comparison of bool value of NSNumber and comparison of size of NSNumber value.
conclusion
Reading the source code is very difficult, and sometimes is the whole process do not understand do not understand, as from a point of departure, can understand a point is harvest, record, there is a sense of achievement.
We’ll see you next time.