-
Notifications
You must be signed in to change notification settings - Fork 2
4.Sourcery AutoJSONDeserializable
We'll now use another template to make Sourcery generate the code for JSON parsing
- Go to Liquidsoul/Sourcery-AutoJSONSerializable on GitHub
- Open the Sources/AutoJSONSerialization.swift file in that repo, and copy its content at the end of
CodeGenDemo/Sources/Protocols/SourceryProtocols.swift:
public protocol JSONDeserializable {
init?(JSONObject: Any)
}(💡 We could also of course instead create a separate file to put that protocol declaration into for clarity)
- Create a new file
AutoJSONDeserializable.stencilinCodeGenDemo/CodeGen/Templatesand copy the content of Templates/AutoJSONDeserializable.stencil in it
See how the template will only consider types annotated with the AutoJSONDeserializable Sourcery annotation.
Sourcery is able to detect special comments in the form of // sourcery: AnyThing so that you can annotate your code (akin to how SwiftLint does).
So here instead of using a phantom protocol like with AutoCases, this template expect to use annotations to opt-in for JSON code generation.
- Search for
// FIXME: sourcery: AutoJSONDeserializablein the source code - Remove the
FIXME:text to only keep the// sourcery: AutoJSONDeserializablecomment/annotation on the line just above each model struct declaration:
// sourcery: AutoJSONDeserializable
struct Address {
…- Start a Build to make Sourcery generate the code for that new template we added
- Add the
AutoJSONDeserializable.generated.swiftfile to yourCodeGenDemo/CodeGen/Generatedgroup in your Xcode project - Build again. 🛑 You'll notice a compiler error when trying to
import Sourcery_AutoJSONSerializableinAutoJSONDeserializable.generated.swift - Look at the
AutoJSONDeserializable.stenciltemplate and notice the top of the code inserting that line. From there you have two solutions:- Remove lines 4-6 of the stencil template to never do that import
- Or understand the logic of that template which only do that import if
argument.removePodImportis not set.
Sourcery allows you to specify custom arguments to pass to templates, so we can do that by editing the .sourcery.yml file to add that argument:
# .sourcery.yml
sources:
- CodeGenDemo
templates:
- CodeGenDemo/CodeGen/Templates
output: CodeGenDemo/CodeGen/Generated
args:
removePodImport: true- Start another Build. The import has disappeared from the generated code and the code should now compile 🎉
- Edit the
PersonListViewController.swiftto replace lines 21-38 (from// FIXME: Sourcery AutoJSONDeserializabletodataSource = [p1, p2].map { Ref(object: $0) }with code parsing thedata.jsonfile (already embedded in the project):
override func viewDidLoad() {
super.viewDidLoad()
do {
let data = try Data(contentsOf: Bundle.main.url(forResource: "data", withExtension: "json")!)
let json = try JSONSerialization.jsonObject(with: data, options: []) as! [Any]
dataSource = json.map({ personJSON in
let p = Person(JSONObject: personJSON)!
return Ref(object: p)
})
} catch let e {
print("Error: ", e)
}
let dupes = UIBarButtonItem(barButtonSystemItem: .action, target: self, action: #selector(findDupes))
self.navigationItem.rightBarButtonItem = dupes
}😱 I discourage the use of force-unwrap in your code (like
as!or!) in general, but for the purpose of this classroom as we want to focus on Code Generation, we'll let it slip 😉 Be sure to do proper error handling in your real code instead.