Suppose you have a struct in your Swift app like this:
structPerson{letfirstName:StringletlastName:Stringletbirthday:DateletinchesTall:Int}In order to allow Person instances to be compared for equality, using the == operator, the struct must adopt Swift's Equatable protocol.
// This doesn't work unless Person adopts the Equatable protocol.
letareSamePerson=(person1 == person2)Writing code to check if two things are the same is boring, so make your computer do it!
// This prints Equatable protocol code for the Person struct.
adoptEquatable(person)The adoptEquatable function prints this to the console in Xcode…
extensionPerson:Equatable{publicstaticfunc==(lhs:Person, rhs:Person)->Bool{guard lhs.firstName == rhs.firstName else{returnfalse}guard lhs.lastName == rhs.lastName else{returnfalse}guard lhs.birthday == rhs.birthday else{returnfalse}guard lhs.inchesTall == rhs.inchesTall else{returnfalse}returntrue}}Simply copy that code, paste it into your project, and you're done. 🙌
Once you've added adoptEquatable to your project you can also call it while debugging, via the po command.
That's handy!
Feel free to copy this function into your project and start using it.
import Foundation
// Generates code for a class or struct instance to conform to the Equatable protocol.
publicfunc adoptEquatable(_ subject:Any){letmirror=Mirror(reflecting: subject)lettypeName:String={letfullTypeName=String(reflecting: mirror.subjectType)lettypeNameParts= fullTypeName.components(separatedBy:".")lethasModulePrefix= typeNameParts.count >1return hasModulePrefix
? typeNameParts.dropFirst().joined(separator:"."): fullTypeName
}()letpropertyNames= mirror.children.map{ $0.label ??""}
// Associate an indentation level with each snippet of code.
typealiasTemplateGroup=[(Int,String)]lettemplateGroups:[TemplateGroup]=[[(0,"extension \(typeName): Equatable {")],[(1,"public static func ==(lhs: \(typeName), rhs: \(typeName)) -> Bool {")],
propertyNames.map{(2,"guard lhs.\($0) == rhs.\($0) else { return false }")},[(2,"return true")],[(1,"}")],[(0,"}")]]
// Apply indentation to each line of code while flattening the list.
letindent=""letlinesOfCode= templateGroups.flatMap{ templateGroup ->[String]inreturn templateGroup.map{(indentLevel:Int, code:String)->Stringinletindentation=String(repeating: indent, count: indentLevel)return"\(indentation)\(code)"}}letsourceCode= linesOfCode.joined(separator:"\n")print(sourceCode)}This repository also includes an Xcode playground if you want to experiment.
