HandyJSON reading notes

HandyJSON repository : https://github.com/alibaba/HandyJSON

HandyJSON

It took me a day and a half to read and learn about Alibaba's open source HandyJSONlibraries. It can only be said that I have a brief understanding of the Swift Runtimerelevant code. However, the harvest is still full. I have always wanted to learn more about protocol-oriented development. Idea, HandyJSON has done a good job in this regard. HandyJSON is a completely protocol-oriented library. The main logic functions are encapsulated in different layers of protocols, and the defined protocols basically provide default implementations.

1. Hierarchy of HandyJSON

First look at the directory structure of HandyJSON as shown below.

TransformsThe folder mainly contains methods for converting between swift types and json supported types, such as URL type to json supported String type, urlString to URL type. The protocol hierarchy is shown in the following figure:

ReflectionFolder, mainly contains the specific implementation process of the mapping (not read carefully at present).

The rest of the files mainly include some configuration files, tool classes, specific classification and forwarding recursive mapping of json to model, etc. As shown in the following figure:

2. The main files in HandyJSON and their functions

2.1 Export.swift

The Export file throws out several protocols:

  • HandyJSON: implements serialization, deserialization, etc.;
  • HandyJSONEnum: serialization and deserialization of enum;
  • HandyJSONCustomTransformable: Implement the protocol to customize the conversion method;

2.2 Configuration.swift

  • DeserializeOptions: Define deserialization options, including caseInsensitivetwo defaultOptionsvalues.
  • HandyJSONConfiguration: HandyJSON configuration options. Including debug mode and deserialization settings. Variables are all static types.

2.3 Logger.swift

According to the setting of HandyJSONConfiguration, print logo, Error or Debug or Verbose.

2.4 Serializer.swift

Extend the HandyJSON protocol and convert the HandyJSON type to JSON type. You can convert the type that complies with the HandyJSON protocol to JSONType or JSONString. The process of converting jsonStirng calls the toJSON() method. That is to say, convert it to a json type object first, and then convert it into a json type string.

In addition Collection, the code is as follows. The advantage of the code below is that it contains recursive calls. This way, no matter how many levels of json are, all the values ​​can be easily retrieved.

public extension Collection where Iterator.Element: HandyJSON {

    public func toJSON() -> [[String: Any]?] {
        return self.map{ $0.toJSON() }
    }

    public func toJSONString(prettyPrint: Bool = false) -> String? {

        let anyArray = self.toJSON()
        if JSONSerialization.isValidJSONObject(anyArray) {
            do {
                let jsonData: Data
                if prettyPrint {
                    jsonData = try JSONSerialization.data(withJSONObject: anyArray, options: [.prettyPrinted])
                } else {
                    jsonData = try JSONSerialization.data(withJSONObject: anyArray, options: [])
                }
                return String(data: jsonData, encoding: .utf8)
            } catch let error {
                InternalLogger.logError(error)
            }
        } else {
            InternalLogger.logDebug("\(self.toJSON()) is not a valid JSON Object")
        }
        return nil
    }
}

2.5 Deserializer.swift

Extends the SwiftJSON type to serialize a json string or json object into a class object.

There are many methods provided in the extension. deserializeThe methods here do some basic judgment processing, and then the specific mapping process is put in the _ExtendCustomModelTypeprotocol.

2.6 TransformType.swift

Defines the data types supported by json and the conversion of data types in swift.

2.7 Measuable.swift

_MeasurableProtocol, which defines the basic methods that support manipulating memory.

2.8 Transformable.swift

_TransformableInherited from _Measurable, the main function is to distribute different types of conversion processes to different implementations.

learning and advancement

1. associatedtype和typealias

When defining a protocol, it is very useful to associatedtypedeclare one or more associated types as part of the protocol definition through keywords, and then typealiasassign values ​​to the associated types in the implementation of the protocol. This can delay the declaration of the specific types of method parameters in the protocol until The specific method is implemented.

2. URL transcoding

Sometimes if the url contains a man, it will cause troubles such as not being able to open the web page, unable to find the URL, etc. You can use the following method addingPercentEncodingto transcode the String, so that the man will become a symbol with a % sign, so that you can access it normally. .

guard let escapedURLString = URLString.addingPercentEncoding(withAllowedCharacters: CharacterSet.urlQueryAllowed) else {
			return nil
		}

3. About the usage of the agreement

The following code is RawRepresentablethe definition and partial implementation of Apple API. This code is good to define the RawValuetype in the protocol, and delay the definition of the specific type of RawValue to the specific implementation. When implementing the protocol, you can use wherekeywords to judge the type of RawValue and do different implementations.

public protocol RawRepresentable {
    associatedtype RawValue
    public init?(rawValue: Self.RawValue)
    public var rawValue: Self.RawValue { get }
}

extension RawRepresentable where Self.RawValue == Bool {
    public func encode(to encoder: Encoder) throws
}

4. SelfKeywords

'Self' is only available in a protocol or as the result of a method in a class

  1. Self can be used to restrict related types in a protocol
  2. Self can be used in a class (Class) to act as the return type of a method
//第一种用法
protocol Copyable {
    func copy() -> Self
    func clamp(intervalToClamp: Self) -> Self
}

//第二种用法
class A: Copyable {
    class func calssFunc() -> Self {
        let type = self
        print(type)
        let result = type.init()
        return result
    }
    
}

SelfRepresenting an instance of this type in a protocol Self.selfcan represent a type itself.

5.RawRepresentable protocol

A type that can be used to represent another type. enum implements the RawRepresentable protocol, so it class EnumTransform<T: RawRepresentable>can Tbe seen as an enum type (of course, it can be any type that implements the RawRepresentable protocol).

//RawRepresentable协议的声明
public protocol RawRepresentable {
    associatedtype RawValue
    public init?(rawValue: Self.RawValue)
    public var rawValue: Self.RawValue { get }
}

6. swift precompile settings

As shown in the following code, it can be passed in swift #if, , #elseand #endifthis method can judge different systems, mobile phone models, etc.

#if os(iOS) || os(tvOS) || os(watchOS)
import UIKit
#else
import Cocoa
#endif

7. Declare Protocol Standards

As shown below, if a protocol has a default implementation, in general, we can put all the definitions and implementations of the protocol methods in the extension, so that we do not need to implement any methods when complying with the protocol (the methods in the protocol in pure swift must be fully implemented. ). I have seen that the swift language API and many third-party libraries do this.

protocol _TestProtocol {}
extension _TestProtocol {
    func testRun() {
        print("run")
    }
}
extension UIView: _TestProtocol {
    func testRun() {
        print("UIView run")
    }
}

8. associatedtype and typealias keywords

8.1 Rename

typealiasKeywords always redefine names for existing types. By naming, you can make the code more clear. The main function is to increase the readability of the code.

typealias与泛型, typealias is single, that is to say, you must assign a specific type to a new name through typealias, instead of renaming the entire generic type.

//如下代码是不能编译通过的
class Person<T> {}  
typealias Woker = Person  
typealias Worker = Person<T>  

//如下, 如果我们在别名中也引入泛型, 则是可以编译通过的
class Person<T> {}  
typealias Woker = Person  
typealias Worker<T> = Person<T>  

8.2 Combination Protocol Types

As shown below, multiple protocols can be grouped together and renamed via &operators.

protocol Cat {}  
protocol Dog {}  
typealias Pat = Cat & Dog  

8.3 associatedtype

When defining a protocol, it is sometimes useful to declare one or more associated types as part of the protocol. An associated type provides a placeholder name (or alias) for a type in the protocol, which represents the actual type in the protocol Specified only when adopted. You can associatedtypespecify the associated type by keyword.

//模型  
struct Model {  
    let age: Int  
}  
  
//协议,使用关联类型  
protocol TableViewCell {  
    associatedtype T  
    func updateCell(_ data: T)  
}  
  
//遵守TableViewCell  
class MyTableViewCell: UITableViewCell, TableViewCell {  
    typealias T = Model  
    func updateCell(_ data: Model) {  
        // do something ...  
    }  
}  

doubt

func transformFromJSON(_ value: Any?) -> Object?1. Why doesn't the value in the TransformType protocol need to JSONbe declared? JSONAfter using the declaration, isn't it necessary to convert the type when following the protocol?

public protocol TransformType {
	associatedtype Object
	associatedtype JSON

	func transformFromJSON(_ value: Any?) -> Object?
	func transformToJSON(_ value: Object?) -> JSON?
}

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325062769&siteId=291194637