├── .gitignore ├── CodeGen-Classroom-Slides.key ├── CodeGenDemo.xcodeproj ├── project.pbxproj └── project.xcworkspace │ └── contents.xcworkspacedata ├── CodeGenDemo ├── AppDelegate.swift ├── Resources │ ├── Assets.xcassets │ │ ├── AppIcon.appiconset │ │ │ ├── AppIcon@2x.png │ │ │ ├── AppIconPro~ipad@2x.png │ │ │ ├── AppIcon~ipad.png │ │ │ ├── AppIcon~ipad@2x.png │ │ │ └── Contents.json │ │ ├── Colors │ │ │ ├── Contents.json │ │ │ ├── Primary.colorset │ │ │ │ └── Contents.json │ │ │ └── Tint.colorset │ │ │ │ └── Contents.json │ │ └── Fruits │ │ │ ├── Contents.json │ │ │ ├── Exotic │ │ │ ├── Banana.imageset │ │ │ │ ├── Banana-icon.png │ │ │ │ └── Contents.json │ │ │ ├── Contents.json │ │ │ └── Mango.imageset │ │ │ │ ├── Contents.json │ │ │ │ └── Mango.png │ │ │ └── Round │ │ │ ├── Apricot.imageset │ │ │ ├── Apricot.png │ │ │ └── Contents.json │ │ │ ├── Contents.json │ │ │ └── Red │ │ │ ├── Apple.imageset │ │ │ ├── Apple-icon.png │ │ │ └── Contents.json │ │ │ ├── Contents.json │ │ │ ├── Double │ │ │ ├── Cherry.imageset │ │ │ │ ├── Cherry.png │ │ │ │ └── Contents.json │ │ │ └── Contents.json │ │ │ └── Tomato.imageset │ │ │ ├── Contents.json │ │ │ └── Tomato.png │ ├── Avenir.ttc │ ├── Base.lproj │ │ ├── LaunchScreen.storyboard │ │ └── Localizable.strings │ ├── Info.plist │ ├── colors.json │ ├── colors.xml │ ├── data.json │ └── fr.lproj │ │ └── Localizable.strings └── Sources │ ├── Model │ ├── Address.swift │ ├── Person.swift │ ├── Phone.swift │ ├── PhoneModel.swift │ └── Ref.swift │ └── ViewControllers │ ├── Base.lproj │ └── PersonList.storyboard │ ├── PersonListCell.swift │ ├── PersonListViewController.swift │ ├── PersonRecord.storyboard │ ├── PersonRecordCell.swift │ ├── PersonRecordViewController.swift │ └── PhoneEditorViewController.swift ├── CodeGenDemoTests ├── CodeGenDemoTests.swift ├── Info.plist └── fixtures │ ├── Phone1.json │ └── Phone2.json └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | ## Build generated 2 | build/ 3 | DerivedData/ 4 | 5 | ## Various settings 6 | *.pbxuser 7 | !default.pbxuser 8 | *.mode1v3 9 | !default.mode1v3 10 | *.mode2v3 11 | !default.mode2v3 12 | *.perspectivev3 13 | !default.perspectivev3 14 | xcuserdata/ 15 | 16 | ## Other 17 | *.moved-aside 18 | *.xcuserstate 19 | *.xcscmblueprint 20 | 21 | ## Obj-C/Swift specific 22 | *.hmap 23 | *.ipa 24 | *.dSYM.zip 25 | *.dSYM 26 | 27 | ## Playgrounds 28 | timeline.xctimeline 29 | playground.xcworkspace 30 | 31 | # Swift Package Manager 32 | # 33 | # Add this line if you want to avoid checking in source code from Swift Package Manager dependencies. 34 | Packages/ 35 | .build/ 36 | 37 | # CocoaPods 38 | # 39 | # We recommend against adding the Pods directory to your .gitignore. However 40 | # you should judge for yourself, the pros and cons are mentioned at: 41 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control 42 | # 43 | # Pods/ 44 | 45 | # Carthage 46 | # 47 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 48 | Carthage/Checkouts 49 | Carthage/Build 50 | 51 | # fastlane 52 | # 53 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the 54 | # screenshots whenever they are needed. 55 | # For more information about the recommended setup visit: 56 | # https://github.com/fastlane/fastlane/blob/master/fastlane/docs/Gitignore.md 57 | 58 | fastlane/report.xml 59 | fastlane/Preview.html 60 | fastlane/screenshots 61 | fastlane/test_output 62 | 63 | # Other stuff 64 | .apitoken 65 | .DS_Store 66 | .idea/ 67 | -------------------------------------------------------------------------------- /CodeGen-Classroom-Slides.key: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FrenchKit/Mastering-code-generation-Classroom/f786004d3babdf464d4f09f6b706e3421b8800f5/CodeGen-Classroom-Slides.key -------------------------------------------------------------------------------- /CodeGenDemo.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 48; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 09031FA01F6ECA7600FBAB7A /* CodeGenDemoTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09031F9F1F6ECA7600FBAB7A /* CodeGenDemoTests.swift */; }; 11 | 09031FA91F6ECBC700FBAB7A /* Phone1.json in Resources */ = {isa = PBXBuildFile; fileRef = 09031FA81F6ECBC700FBAB7A /* Phone1.json */; }; 12 | 092C6D091F6EEB5200856FE3 /* PhoneEditorViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 092C6D081F6EEB5200856FE3 /* PhoneEditorViewController.swift */; }; 13 | 092C6D0B1F6EF31400856FE3 /* Ref.swift in Sources */ = {isa = PBXBuildFile; fileRef = 092C6D0A1F6EF31400856FE3 /* Ref.swift */; }; 14 | 092C6D101F6F31FB00856FE3 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 092C6D0E1F6F31FB00856FE3 /* Localizable.strings */; }; 15 | 092C6D131F6F365700856FE3 /* Avenir.ttc in Resources */ = {isa = PBXBuildFile; fileRef = 092C6D121F6F365600856FE3 /* Avenir.ttc */; }; 16 | 09A80B8D1F6ED3D400FAF99B /* Phone2.json in Resources */ = {isa = PBXBuildFile; fileRef = 09A80B8C1F6ED3D400FAF99B /* Phone2.json */; }; 17 | 09A80B8F1F6ED46400FAF99B /* PersonRecord.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 09A80B8E1F6ED46400FAF99B /* PersonRecord.storyboard */; }; 18 | 09A80B911F6EDABD00FAF99B /* PersonListCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09A80B901F6EDABD00FAF99B /* PersonListCell.swift */; }; 19 | 09A80B971F6EDFD800FAF99B /* PersonRecordViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09A80B961F6EDFD800FAF99B /* PersonRecordViewController.swift */; }; 20 | 09A80B991F6EE1BF00FAF99B /* PersonRecordCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09A80B981F6EE1BF00FAF99B /* PersonRecordCell.swift */; }; 21 | 09A80B9B1F6EE54300FAF99B /* data.json in Resources */ = {isa = PBXBuildFile; fileRef = 09A80B9A1F6EE54300FAF99B /* data.json */; }; 22 | 370CDA801F585A4A000C7FD1 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 370CDA7F1F585A4A000C7FD1 /* AppDelegate.swift */; }; 23 | 370CDA821F585A4A000C7FD1 /* PersonListViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 370CDA811F585A4A000C7FD1 /* PersonListViewController.swift */; }; 24 | 370CDA851F585A4A000C7FD1 /* PersonList.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 370CDA831F585A4A000C7FD1 /* PersonList.storyboard */; }; 25 | 370CDA871F585A4A000C7FD1 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 370CDA861F585A4A000C7FD1 /* Assets.xcassets */; }; 26 | 370CDA8A1F585A4A000C7FD1 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 370CDA881F585A4A000C7FD1 /* LaunchScreen.storyboard */; }; 27 | 370CDA961F585A91000C7FD1 /* PhoneModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 370CDA951F585A91000C7FD1 /* PhoneModel.swift */; }; 28 | 370CDAA31F585EC4000C7FD1 /* Person.swift in Sources */ = {isa = PBXBuildFile; fileRef = 370CDAA21F585EC4000C7FD1 /* Person.swift */; }; 29 | 370CDAA51F585EF0000C7FD1 /* Address.swift in Sources */ = {isa = PBXBuildFile; fileRef = 370CDAA41F585EF0000C7FD1 /* Address.swift */; }; 30 | 370CDAA81F586051000C7FD1 /* Phone.swift in Sources */ = {isa = PBXBuildFile; fileRef = 370CDAA71F586051000C7FD1 /* Phone.swift */; }; 31 | /* End PBXBuildFile section */ 32 | 33 | /* Begin PBXContainerItemProxy section */ 34 | 09031FA21F6ECA7600FBAB7A /* PBXContainerItemProxy */ = { 35 | isa = PBXContainerItemProxy; 36 | containerPortal = 370CDA741F585A4A000C7FD1 /* Project object */; 37 | proxyType = 1; 38 | remoteGlobalIDString = 370CDA7B1F585A4A000C7FD1; 39 | remoteInfo = CodeGenDemo; 40 | }; 41 | /* End PBXContainerItemProxy section */ 42 | 43 | /* Begin PBXFileReference section */ 44 | 09031F9D1F6ECA7600FBAB7A /* CodeGenDemoTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = CodeGenDemoTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 45 | 09031F9F1F6ECA7600FBAB7A /* CodeGenDemoTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CodeGenDemoTests.swift; sourceTree = ""; }; 46 | 09031FA11F6ECA7600FBAB7A /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 47 | 09031FA81F6ECBC700FBAB7A /* Phone1.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = Phone1.json; sourceTree = ""; }; 48 | 092C6D081F6EEB5200856FE3 /* PhoneEditorViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PhoneEditorViewController.swift; sourceTree = ""; }; 49 | 092C6D0A1F6EF31400856FE3 /* Ref.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Ref.swift; sourceTree = ""; }; 50 | 092C6D0F1F6F31FB00856FE3 /* Base */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = Base; path = Base.lproj/Localizable.strings; sourceTree = ""; }; 51 | 092C6D111F6F356900856FE3 /* fr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fr; path = fr.lproj/Localizable.strings; sourceTree = ""; }; 52 | 092C6D121F6F365600856FE3 /* Avenir.ttc */ = {isa = PBXFileReference; lastKnownFileType = file; path = Avenir.ttc; sourceTree = ""; }; 53 | 092C6D141F6F377100856FE3 /* colors.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = colors.json; sourceTree = ""; }; 54 | 092C6D151F6F377100856FE3 /* colors.xml */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; path = colors.xml; sourceTree = ""; }; 55 | 09A80B8C1F6ED3D400FAF99B /* Phone2.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = Phone2.json; sourceTree = ""; }; 56 | 09A80B8E1F6ED46400FAF99B /* PersonRecord.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = PersonRecord.storyboard; sourceTree = ""; }; 57 | 09A80B901F6EDABD00FAF99B /* PersonListCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PersonListCell.swift; sourceTree = ""; }; 58 | 09A80B961F6EDFD800FAF99B /* PersonRecordViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PersonRecordViewController.swift; sourceTree = ""; }; 59 | 09A80B981F6EE1BF00FAF99B /* PersonRecordCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PersonRecordCell.swift; sourceTree = ""; }; 60 | 09A80B9A1F6EE54300FAF99B /* data.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = data.json; sourceTree = ""; }; 61 | 370CDA7C1F585A4A000C7FD1 /* CodeGenDemo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = CodeGenDemo.app; sourceTree = BUILT_PRODUCTS_DIR; }; 62 | 370CDA7F1F585A4A000C7FD1 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 63 | 370CDA811F585A4A000C7FD1 /* PersonListViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PersonListViewController.swift; sourceTree = ""; }; 64 | 370CDA841F585A4A000C7FD1 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/PersonList.storyboard; sourceTree = ""; }; 65 | 370CDA861F585A4A000C7FD1 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 66 | 370CDA891F585A4A000C7FD1 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 67 | 370CDA8B1F585A4A000C7FD1 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 68 | 370CDA951F585A91000C7FD1 /* PhoneModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PhoneModel.swift; sourceTree = ""; }; 69 | 370CDAA21F585EC4000C7FD1 /* Person.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Person.swift; sourceTree = ""; }; 70 | 370CDAA41F585EF0000C7FD1 /* Address.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Address.swift; sourceTree = ""; }; 71 | 370CDAA71F586051000C7FD1 /* Phone.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Phone.swift; sourceTree = ""; }; 72 | /* End PBXFileReference section */ 73 | 74 | /* Begin PBXFrameworksBuildPhase section */ 75 | 09031F9A1F6ECA7600FBAB7A /* Frameworks */ = { 76 | isa = PBXFrameworksBuildPhase; 77 | buildActionMask = 2147483647; 78 | files = ( 79 | ); 80 | runOnlyForDeploymentPostprocessing = 0; 81 | }; 82 | 370CDA791F585A4A000C7FD1 /* Frameworks */ = { 83 | isa = PBXFrameworksBuildPhase; 84 | buildActionMask = 2147483647; 85 | files = ( 86 | ); 87 | runOnlyForDeploymentPostprocessing = 0; 88 | }; 89 | /* End PBXFrameworksBuildPhase section */ 90 | 91 | /* Begin PBXGroup section */ 92 | 09031F9E1F6ECA7600FBAB7A /* CodeGenDemoTests */ = { 93 | isa = PBXGroup; 94 | children = ( 95 | 09031FA71F6ECB9B00FBAB7A /* fixtures */, 96 | 09031F9F1F6ECA7600FBAB7A /* CodeGenDemoTests.swift */, 97 | 09031FA11F6ECA7600FBAB7A /* Info.plist */, 98 | ); 99 | path = CodeGenDemoTests; 100 | sourceTree = ""; 101 | }; 102 | 09031FA71F6ECB9B00FBAB7A /* fixtures */ = { 103 | isa = PBXGroup; 104 | children = ( 105 | 09031FA81F6ECBC700FBAB7A /* Phone1.json */, 106 | 09A80B8C1F6ED3D400FAF99B /* Phone2.json */, 107 | ); 108 | path = fixtures; 109 | sourceTree = ""; 110 | }; 111 | 09A80B921F6EDDE700FAF99B /* CodeGen */ = { 112 | isa = PBXGroup; 113 | children = ( 114 | 09A80B931F6EDDF900FAF99B /* Constants */, 115 | ); 116 | path = CodeGen; 117 | sourceTree = ""; 118 | }; 119 | 09A80B931F6EDDF900FAF99B /* Constants */ = { 120 | isa = PBXGroup; 121 | children = ( 122 | ); 123 | path = Constants; 124 | sourceTree = ""; 125 | }; 126 | 370CDA731F585A4A000C7FD1 = { 127 | isa = PBXGroup; 128 | children = ( 129 | 370CDA7E1F585A4A000C7FD1 /* CodeGenDemo */, 130 | 09031F9E1F6ECA7600FBAB7A /* CodeGenDemoTests */, 131 | 370CDA7D1F585A4A000C7FD1 /* Products */, 132 | ); 133 | sourceTree = ""; 134 | }; 135 | 370CDA7D1F585A4A000C7FD1 /* Products */ = { 136 | isa = PBXGroup; 137 | children = ( 138 | 370CDA7C1F585A4A000C7FD1 /* CodeGenDemo.app */, 139 | 09031F9D1F6ECA7600FBAB7A /* CodeGenDemoTests.xctest */, 140 | ); 141 | name = Products; 142 | sourceTree = ""; 143 | }; 144 | 370CDA7E1F585A4A000C7FD1 /* CodeGenDemo */ = { 145 | isa = PBXGroup; 146 | children = ( 147 | 370CDA7F1F585A4A000C7FD1 /* AppDelegate.swift */, 148 | 370CDA911F585A54000C7FD1 /* Sources */, 149 | 09A80B921F6EDDE700FAF99B /* CodeGen */, 150 | 370CDAAA1F586129000C7FD1 /* Resources */, 151 | ); 152 | path = CodeGenDemo; 153 | sourceTree = ""; 154 | }; 155 | 370CDA911F585A54000C7FD1 /* Sources */ = { 156 | isa = PBXGroup; 157 | children = ( 158 | 370CDA941F585A7F000C7FD1 /* Model */, 159 | 370CDAAF1F58625B000C7FD1 /* ViewControllers */, 160 | ); 161 | path = Sources; 162 | sourceTree = ""; 163 | }; 164 | 370CDA941F585A7F000C7FD1 /* Model */ = { 165 | isa = PBXGroup; 166 | children = ( 167 | 370CDA951F585A91000C7FD1 /* PhoneModel.swift */, 168 | 370CDAA71F586051000C7FD1 /* Phone.swift */, 169 | 370CDAA41F585EF0000C7FD1 /* Address.swift */, 170 | 370CDAA21F585EC4000C7FD1 /* Person.swift */, 171 | 092C6D0A1F6EF31400856FE3 /* Ref.swift */, 172 | ); 173 | path = Model; 174 | sourceTree = ""; 175 | }; 176 | 370CDAAA1F586129000C7FD1 /* Resources */ = { 177 | isa = PBXGroup; 178 | children = ( 179 | 092C6D141F6F377100856FE3 /* colors.json */, 180 | 092C6D151F6F377100856FE3 /* colors.xml */, 181 | 092C6D121F6F365600856FE3 /* Avenir.ttc */, 182 | 092C6D0E1F6F31FB00856FE3 /* Localizable.strings */, 183 | 09A80B9A1F6EE54300FAF99B /* data.json */, 184 | 370CDA861F585A4A000C7FD1 /* Assets.xcassets */, 185 | 370CDA881F585A4A000C7FD1 /* LaunchScreen.storyboard */, 186 | 370CDA8B1F585A4A000C7FD1 /* Info.plist */, 187 | ); 188 | path = Resources; 189 | sourceTree = ""; 190 | }; 191 | 370CDAAF1F58625B000C7FD1 /* ViewControllers */ = { 192 | isa = PBXGroup; 193 | children = ( 194 | 370CDA831F585A4A000C7FD1 /* PersonList.storyboard */, 195 | 370CDA811F585A4A000C7FD1 /* PersonListViewController.swift */, 196 | 09A80B901F6EDABD00FAF99B /* PersonListCell.swift */, 197 | 09A80B8E1F6ED46400FAF99B /* PersonRecord.storyboard */, 198 | 09A80B961F6EDFD800FAF99B /* PersonRecordViewController.swift */, 199 | 09A80B981F6EE1BF00FAF99B /* PersonRecordCell.swift */, 200 | 092C6D081F6EEB5200856FE3 /* PhoneEditorViewController.swift */, 201 | ); 202 | path = ViewControllers; 203 | sourceTree = ""; 204 | }; 205 | /* End PBXGroup section */ 206 | 207 | /* Begin PBXNativeTarget section */ 208 | 09031F9C1F6ECA7600FBAB7A /* CodeGenDemoTests */ = { 209 | isa = PBXNativeTarget; 210 | buildConfigurationList = 09031FA61F6ECA7600FBAB7A /* Build configuration list for PBXNativeTarget "CodeGenDemoTests" */; 211 | buildPhases = ( 212 | 09031F991F6ECA7600FBAB7A /* Sources */, 213 | 09031F9A1F6ECA7600FBAB7A /* Frameworks */, 214 | 09031F9B1F6ECA7600FBAB7A /* Resources */, 215 | ); 216 | buildRules = ( 217 | ); 218 | dependencies = ( 219 | 09031FA31F6ECA7600FBAB7A /* PBXTargetDependency */, 220 | ); 221 | name = CodeGenDemoTests; 222 | productName = CodeGenDemoTests; 223 | productReference = 09031F9D1F6ECA7600FBAB7A /* CodeGenDemoTests.xctest */; 224 | productType = "com.apple.product-type.bundle.unit-test"; 225 | }; 226 | 370CDA7B1F585A4A000C7FD1 /* CodeGenDemo */ = { 227 | isa = PBXNativeTarget; 228 | buildConfigurationList = 370CDA8E1F585A4A000C7FD1 /* Build configuration list for PBXNativeTarget "CodeGenDemo" */; 229 | buildPhases = ( 230 | 370CDA781F585A4A000C7FD1 /* Sources */, 231 | 370CDA791F585A4A000C7FD1 /* Frameworks */, 232 | 370CDA7A1F585A4A000C7FD1 /* Resources */, 233 | ); 234 | buildRules = ( 235 | ); 236 | dependencies = ( 237 | ); 238 | name = CodeGenDemo; 239 | productName = CodeGenDemo; 240 | productReference = 370CDA7C1F585A4A000C7FD1 /* CodeGenDemo.app */; 241 | productType = "com.apple.product-type.application"; 242 | }; 243 | /* End PBXNativeTarget section */ 244 | 245 | /* Begin PBXProject section */ 246 | 370CDA741F585A4A000C7FD1 /* Project object */ = { 247 | isa = PBXProject; 248 | attributes = { 249 | LastSwiftUpdateCheck = 0830; 250 | LastUpgradeCheck = 0900; 251 | ORGANIZATIONNAME = AliSoftware; 252 | TargetAttributes = { 253 | 09031F9C1F6ECA7600FBAB7A = { 254 | CreatedOnToolsVersion = 8.3.3; 255 | ProvisioningStyle = Manual; 256 | TestTargetID = 370CDA7B1F585A4A000C7FD1; 257 | }; 258 | 370CDA7B1F585A4A000C7FD1 = { 259 | CreatedOnToolsVersion = 9.0; 260 | ProvisioningStyle = Automatic; 261 | }; 262 | }; 263 | }; 264 | buildConfigurationList = 370CDA771F585A4A000C7FD1 /* Build configuration list for PBXProject "CodeGenDemo" */; 265 | compatibilityVersion = "Xcode 8.0"; 266 | developmentRegion = en; 267 | hasScannedForEncodings = 0; 268 | knownRegions = ( 269 | en, 270 | Base, 271 | fr, 272 | ); 273 | mainGroup = 370CDA731F585A4A000C7FD1; 274 | productRefGroup = 370CDA7D1F585A4A000C7FD1 /* Products */; 275 | projectDirPath = ""; 276 | projectRoot = ""; 277 | targets = ( 278 | 370CDA7B1F585A4A000C7FD1 /* CodeGenDemo */, 279 | 09031F9C1F6ECA7600FBAB7A /* CodeGenDemoTests */, 280 | ); 281 | }; 282 | /* End PBXProject section */ 283 | 284 | /* Begin PBXResourcesBuildPhase section */ 285 | 09031F9B1F6ECA7600FBAB7A /* Resources */ = { 286 | isa = PBXResourcesBuildPhase; 287 | buildActionMask = 2147483647; 288 | files = ( 289 | 09031FA91F6ECBC700FBAB7A /* Phone1.json in Resources */, 290 | 09A80B8D1F6ED3D400FAF99B /* Phone2.json in Resources */, 291 | ); 292 | runOnlyForDeploymentPostprocessing = 0; 293 | }; 294 | 370CDA7A1F585A4A000C7FD1 /* Resources */ = { 295 | isa = PBXResourcesBuildPhase; 296 | buildActionMask = 2147483647; 297 | files = ( 298 | 09A80B8F1F6ED46400FAF99B /* PersonRecord.storyboard in Resources */, 299 | 092C6D101F6F31FB00856FE3 /* Localizable.strings in Resources */, 300 | 09A80B9B1F6EE54300FAF99B /* data.json in Resources */, 301 | 370CDA8A1F585A4A000C7FD1 /* LaunchScreen.storyboard in Resources */, 302 | 370CDA871F585A4A000C7FD1 /* Assets.xcassets in Resources */, 303 | 092C6D131F6F365700856FE3 /* Avenir.ttc in Resources */, 304 | 370CDA851F585A4A000C7FD1 /* PersonList.storyboard in Resources */, 305 | ); 306 | runOnlyForDeploymentPostprocessing = 0; 307 | }; 308 | /* End PBXResourcesBuildPhase section */ 309 | 310 | /* Begin PBXSourcesBuildPhase section */ 311 | 09031F991F6ECA7600FBAB7A /* Sources */ = { 312 | isa = PBXSourcesBuildPhase; 313 | buildActionMask = 2147483647; 314 | files = ( 315 | 09031FA01F6ECA7600FBAB7A /* CodeGenDemoTests.swift in Sources */, 316 | ); 317 | runOnlyForDeploymentPostprocessing = 0; 318 | }; 319 | 370CDA781F585A4A000C7FD1 /* Sources */ = { 320 | isa = PBXSourcesBuildPhase; 321 | buildActionMask = 2147483647; 322 | files = ( 323 | 370CDAA81F586051000C7FD1 /* Phone.swift in Sources */, 324 | 09A80B911F6EDABD00FAF99B /* PersonListCell.swift in Sources */, 325 | 370CDAA51F585EF0000C7FD1 /* Address.swift in Sources */, 326 | 092C6D091F6EEB5200856FE3 /* PhoneEditorViewController.swift in Sources */, 327 | 370CDA821F585A4A000C7FD1 /* PersonListViewController.swift in Sources */, 328 | 370CDA801F585A4A000C7FD1 /* AppDelegate.swift in Sources */, 329 | 09A80B991F6EE1BF00FAF99B /* PersonRecordCell.swift in Sources */, 330 | 370CDA961F585A91000C7FD1 /* PhoneModel.swift in Sources */, 331 | 092C6D0B1F6EF31400856FE3 /* Ref.swift in Sources */, 332 | 09A80B971F6EDFD800FAF99B /* PersonRecordViewController.swift in Sources */, 333 | 370CDAA31F585EC4000C7FD1 /* Person.swift in Sources */, 334 | ); 335 | runOnlyForDeploymentPostprocessing = 0; 336 | }; 337 | /* End PBXSourcesBuildPhase section */ 338 | 339 | /* Begin PBXTargetDependency section */ 340 | 09031FA31F6ECA7600FBAB7A /* PBXTargetDependency */ = { 341 | isa = PBXTargetDependency; 342 | target = 370CDA7B1F585A4A000C7FD1 /* CodeGenDemo */; 343 | targetProxy = 09031FA21F6ECA7600FBAB7A /* PBXContainerItemProxy */; 344 | }; 345 | /* End PBXTargetDependency section */ 346 | 347 | /* Begin PBXVariantGroup section */ 348 | 092C6D0E1F6F31FB00856FE3 /* Localizable.strings */ = { 349 | isa = PBXVariantGroup; 350 | children = ( 351 | 092C6D0F1F6F31FB00856FE3 /* Base */, 352 | 092C6D111F6F356900856FE3 /* fr */, 353 | ); 354 | name = Localizable.strings; 355 | sourceTree = ""; 356 | }; 357 | 370CDA831F585A4A000C7FD1 /* PersonList.storyboard */ = { 358 | isa = PBXVariantGroup; 359 | children = ( 360 | 370CDA841F585A4A000C7FD1 /* Base */, 361 | ); 362 | name = PersonList.storyboard; 363 | sourceTree = ""; 364 | }; 365 | 370CDA881F585A4A000C7FD1 /* LaunchScreen.storyboard */ = { 366 | isa = PBXVariantGroup; 367 | children = ( 368 | 370CDA891F585A4A000C7FD1 /* Base */, 369 | ); 370 | name = LaunchScreen.storyboard; 371 | sourceTree = ""; 372 | }; 373 | /* End PBXVariantGroup section */ 374 | 375 | /* Begin XCBuildConfiguration section */ 376 | 09031FA41F6ECA7600FBAB7A /* Debug */ = { 377 | isa = XCBuildConfiguration; 378 | buildSettings = { 379 | BUNDLE_LOADER = "$(TEST_HOST)"; 380 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 381 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 382 | DEVELOPMENT_TEAM = ""; 383 | GCC_C_LANGUAGE_STANDARD = gnu99; 384 | INFOPLIST_FILE = CodeGenDemoTests/Info.plist; 385 | IPHONEOS_DEPLOYMENT_TARGET = 10.3; 386 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 387 | PRODUCT_BUNDLE_IDENTIFIER = com.alisoftware.CodeGenDemoTests; 388 | PRODUCT_NAME = "$(TARGET_NAME)"; 389 | PROVISIONING_PROFILE_SPECIFIER = ""; 390 | SWIFT_VERSION = 3.0; 391 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/CodeGenDemo.app/CodeGenDemo"; 392 | }; 393 | name = Debug; 394 | }; 395 | 09031FA51F6ECA7600FBAB7A /* Release */ = { 396 | isa = XCBuildConfiguration; 397 | buildSettings = { 398 | BUNDLE_LOADER = "$(TEST_HOST)"; 399 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 400 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 401 | DEVELOPMENT_TEAM = ""; 402 | GCC_C_LANGUAGE_STANDARD = gnu99; 403 | INFOPLIST_FILE = CodeGenDemoTests/Info.plist; 404 | IPHONEOS_DEPLOYMENT_TARGET = 10.3; 405 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 406 | PRODUCT_BUNDLE_IDENTIFIER = com.alisoftware.CodeGenDemoTests; 407 | PRODUCT_NAME = "$(TARGET_NAME)"; 408 | PROVISIONING_PROFILE_SPECIFIER = ""; 409 | SWIFT_VERSION = 3.0; 410 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/CodeGenDemo.app/CodeGenDemo"; 411 | }; 412 | name = Release; 413 | }; 414 | 370CDA8C1F585A4A000C7FD1 /* Debug */ = { 415 | isa = XCBuildConfiguration; 416 | buildSettings = { 417 | ALWAYS_SEARCH_USER_PATHS = NO; 418 | CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; 419 | CLANG_ANALYZER_NONNULL = YES; 420 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 421 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 422 | CLANG_CXX_LIBRARY = "libc++"; 423 | CLANG_ENABLE_MODULES = YES; 424 | CLANG_ENABLE_OBJC_ARC = YES; 425 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 426 | CLANG_WARN_BOOL_CONVERSION = YES; 427 | CLANG_WARN_COMMA = YES; 428 | CLANG_WARN_CONSTANT_CONVERSION = YES; 429 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 430 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 431 | CLANG_WARN_EMPTY_BODY = YES; 432 | CLANG_WARN_ENUM_CONVERSION = YES; 433 | CLANG_WARN_INFINITE_RECURSION = YES; 434 | CLANG_WARN_INT_CONVERSION = YES; 435 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 436 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 437 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 438 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 439 | CLANG_WARN_STRICT_PROTOTYPES = YES; 440 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 441 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 442 | CLANG_WARN_UNREACHABLE_CODE = YES; 443 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 444 | CODE_SIGN_IDENTITY = "iPhone Developer"; 445 | COPY_PHASE_STRIP = NO; 446 | DEBUG_INFORMATION_FORMAT = dwarf; 447 | ENABLE_STRICT_OBJC_MSGSEND = YES; 448 | ENABLE_TESTABILITY = YES; 449 | GCC_C_LANGUAGE_STANDARD = gnu11; 450 | GCC_DYNAMIC_NO_PIC = NO; 451 | GCC_NO_COMMON_BLOCKS = YES; 452 | GCC_OPTIMIZATION_LEVEL = 0; 453 | GCC_PREPROCESSOR_DEFINITIONS = ( 454 | "DEBUG=1", 455 | "$(inherited)", 456 | ); 457 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 458 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 459 | GCC_WARN_UNDECLARED_SELECTOR = YES; 460 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 461 | GCC_WARN_UNUSED_FUNCTION = YES; 462 | GCC_WARN_UNUSED_VARIABLE = YES; 463 | IPHONEOS_DEPLOYMENT_TARGET = 11.0; 464 | MTL_ENABLE_DEBUG_INFO = YES; 465 | ONLY_ACTIVE_ARCH = YES; 466 | SDKROOT = iphoneos; 467 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; 468 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 469 | }; 470 | name = Debug; 471 | }; 472 | 370CDA8D1F585A4A000C7FD1 /* Release */ = { 473 | isa = XCBuildConfiguration; 474 | buildSettings = { 475 | ALWAYS_SEARCH_USER_PATHS = NO; 476 | CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; 477 | CLANG_ANALYZER_NONNULL = YES; 478 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 479 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 480 | CLANG_CXX_LIBRARY = "libc++"; 481 | CLANG_ENABLE_MODULES = YES; 482 | CLANG_ENABLE_OBJC_ARC = YES; 483 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 484 | CLANG_WARN_BOOL_CONVERSION = YES; 485 | CLANG_WARN_COMMA = YES; 486 | CLANG_WARN_CONSTANT_CONVERSION = YES; 487 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 488 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 489 | CLANG_WARN_EMPTY_BODY = YES; 490 | CLANG_WARN_ENUM_CONVERSION = YES; 491 | CLANG_WARN_INFINITE_RECURSION = YES; 492 | CLANG_WARN_INT_CONVERSION = YES; 493 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 494 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 495 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 496 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 497 | CLANG_WARN_STRICT_PROTOTYPES = YES; 498 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 499 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 500 | CLANG_WARN_UNREACHABLE_CODE = YES; 501 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 502 | CODE_SIGN_IDENTITY = "iPhone Developer"; 503 | COPY_PHASE_STRIP = NO; 504 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 505 | ENABLE_NS_ASSERTIONS = NO; 506 | ENABLE_STRICT_OBJC_MSGSEND = YES; 507 | GCC_C_LANGUAGE_STANDARD = gnu11; 508 | GCC_NO_COMMON_BLOCKS = YES; 509 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 510 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 511 | GCC_WARN_UNDECLARED_SELECTOR = YES; 512 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 513 | GCC_WARN_UNUSED_FUNCTION = YES; 514 | GCC_WARN_UNUSED_VARIABLE = YES; 515 | IPHONEOS_DEPLOYMENT_TARGET = 11.0; 516 | MTL_ENABLE_DEBUG_INFO = NO; 517 | SDKROOT = iphoneos; 518 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; 519 | VALIDATE_PRODUCT = YES; 520 | }; 521 | name = Release; 522 | }; 523 | 370CDA8F1F585A4A000C7FD1 /* Debug */ = { 524 | isa = XCBuildConfiguration; 525 | buildSettings = { 526 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 527 | CODE_SIGN_STYLE = Automatic; 528 | INFOPLIST_FILE = CodeGenDemo/Resources/Info.plist; 529 | IPHONEOS_DEPLOYMENT_TARGET = 9.3; 530 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 531 | PRODUCT_BUNDLE_IDENTIFIER = com.alisoftware.CodeGenDemo; 532 | PRODUCT_NAME = "$(TARGET_NAME)"; 533 | SWIFT_VERSION = 3.0; 534 | TARGETED_DEVICE_FAMILY = "1,2"; 535 | }; 536 | name = Debug; 537 | }; 538 | 370CDA901F585A4A000C7FD1 /* Release */ = { 539 | isa = XCBuildConfiguration; 540 | buildSettings = { 541 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 542 | CODE_SIGN_STYLE = Automatic; 543 | INFOPLIST_FILE = CodeGenDemo/Resources/Info.plist; 544 | IPHONEOS_DEPLOYMENT_TARGET = 9.3; 545 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 546 | PRODUCT_BUNDLE_IDENTIFIER = com.alisoftware.CodeGenDemo; 547 | PRODUCT_NAME = "$(TARGET_NAME)"; 548 | SWIFT_VERSION = 3.0; 549 | TARGETED_DEVICE_FAMILY = "1,2"; 550 | }; 551 | name = Release; 552 | }; 553 | /* End XCBuildConfiguration section */ 554 | 555 | /* Begin XCConfigurationList section */ 556 | 09031FA61F6ECA7600FBAB7A /* Build configuration list for PBXNativeTarget "CodeGenDemoTests" */ = { 557 | isa = XCConfigurationList; 558 | buildConfigurations = ( 559 | 09031FA41F6ECA7600FBAB7A /* Debug */, 560 | 09031FA51F6ECA7600FBAB7A /* Release */, 561 | ); 562 | defaultConfigurationIsVisible = 0; 563 | defaultConfigurationName = Release; 564 | }; 565 | 370CDA771F585A4A000C7FD1 /* Build configuration list for PBXProject "CodeGenDemo" */ = { 566 | isa = XCConfigurationList; 567 | buildConfigurations = ( 568 | 370CDA8C1F585A4A000C7FD1 /* Debug */, 569 | 370CDA8D1F585A4A000C7FD1 /* Release */, 570 | ); 571 | defaultConfigurationIsVisible = 0; 572 | defaultConfigurationName = Release; 573 | }; 574 | 370CDA8E1F585A4A000C7FD1 /* Build configuration list for PBXNativeTarget "CodeGenDemo" */ = { 575 | isa = XCConfigurationList; 576 | buildConfigurations = ( 577 | 370CDA8F1F585A4A000C7FD1 /* Debug */, 578 | 370CDA901F585A4A000C7FD1 /* Release */, 579 | ); 580 | defaultConfigurationIsVisible = 0; 581 | defaultConfigurationName = Release; 582 | }; 583 | /* End XCConfigurationList section */ 584 | }; 585 | rootObject = 370CDA741F585A4A000C7FD1 /* Project object */; 586 | } 587 | -------------------------------------------------------------------------------- /CodeGenDemo.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /CodeGenDemo/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.swift 3 | // CodeGenDemo 4 | // 5 | // Created by Olivier HALLIGON on 31/08/2017. 6 | // Copyright © 2017 AliSoftware. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | @UIApplicationMain 12 | class AppDelegate: UIResponder, UIApplicationDelegate { 13 | var window: UIWindow? 14 | 15 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool { 16 | // Override point for customization after application launch. 17 | return true 18 | } 19 | } 20 | 21 | -------------------------------------------------------------------------------- /CodeGenDemo/Resources/Assets.xcassets/AppIcon.appiconset/AppIcon@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FrenchKit/Mastering-code-generation-Classroom/f786004d3babdf464d4f09f6b706e3421b8800f5/CodeGenDemo/Resources/Assets.xcassets/AppIcon.appiconset/AppIcon@2x.png -------------------------------------------------------------------------------- /CodeGenDemo/Resources/Assets.xcassets/AppIcon.appiconset/AppIconPro~ipad@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FrenchKit/Mastering-code-generation-Classroom/f786004d3babdf464d4f09f6b706e3421b8800f5/CodeGenDemo/Resources/Assets.xcassets/AppIcon.appiconset/AppIconPro~ipad@2x.png -------------------------------------------------------------------------------- /CodeGenDemo/Resources/Assets.xcassets/AppIcon.appiconset/AppIcon~ipad.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FrenchKit/Mastering-code-generation-Classroom/f786004d3babdf464d4f09f6b706e3421b8800f5/CodeGenDemo/Resources/Assets.xcassets/AppIcon.appiconset/AppIcon~ipad.png -------------------------------------------------------------------------------- /CodeGenDemo/Resources/Assets.xcassets/AppIcon.appiconset/AppIcon~ipad@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FrenchKit/Mastering-code-generation-Classroom/f786004d3babdf464d4f09f6b706e3421b8800f5/CodeGenDemo/Resources/Assets.xcassets/AppIcon.appiconset/AppIcon~ipad@2x.png -------------------------------------------------------------------------------- /CodeGenDemo/Resources/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "20x20", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "20x20", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "29x29", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "29x29", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "40x40", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "40x40", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "size" : "60x60", 35 | "idiom" : "iphone", 36 | "filename" : "AppIcon@2x.png", 37 | "scale" : "2x" 38 | }, 39 | { 40 | "idiom" : "iphone", 41 | "size" : "60x60", 42 | "scale" : "3x" 43 | }, 44 | { 45 | "idiom" : "ipad", 46 | "size" : "20x20", 47 | "scale" : "1x" 48 | }, 49 | { 50 | "idiom" : "ipad", 51 | "size" : "20x20", 52 | "scale" : "2x" 53 | }, 54 | { 55 | "idiom" : "ipad", 56 | "size" : "29x29", 57 | "scale" : "1x" 58 | }, 59 | { 60 | "idiom" : "ipad", 61 | "size" : "29x29", 62 | "scale" : "2x" 63 | }, 64 | { 65 | "idiom" : "ipad", 66 | "size" : "40x40", 67 | "scale" : "1x" 68 | }, 69 | { 70 | "idiom" : "ipad", 71 | "size" : "40x40", 72 | "scale" : "2x" 73 | }, 74 | { 75 | "size" : "76x76", 76 | "idiom" : "ipad", 77 | "filename" : "AppIcon~ipad.png", 78 | "scale" : "1x" 79 | }, 80 | { 81 | "size" : "76x76", 82 | "idiom" : "ipad", 83 | "filename" : "AppIcon~ipad@2x.png", 84 | "scale" : "2x" 85 | }, 86 | { 87 | "size" : "83.5x83.5", 88 | "idiom" : "ipad", 89 | "filename" : "AppIconPro~ipad@2x.png", 90 | "scale" : "2x" 91 | } 92 | ], 93 | "info" : { 94 | "version" : 1, 95 | "author" : "xcode" 96 | } 97 | } -------------------------------------------------------------------------------- /CodeGenDemo/Resources/Assets.xcassets/Colors/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | }, 6 | "properties" : { 7 | "provides-namespace" : true 8 | } 9 | } -------------------------------------------------------------------------------- /CodeGenDemo/Resources/Assets.xcassets/Colors/Primary.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | }, 6 | "colors" : [ 7 | { 8 | "idiom" : "universal", 9 | "color" : { 10 | "color-space" : "srgb", 11 | "components" : { 12 | "red" : "0.949", 13 | "alpha" : "1.000", 14 | "blue" : "0.290", 15 | "green" : "0.392" 16 | } 17 | } 18 | } 19 | ] 20 | } -------------------------------------------------------------------------------- /CodeGenDemo/Resources/Assets.xcassets/Colors/Tint.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | }, 6 | "colors" : [ 7 | { 8 | "idiom" : "universal", 9 | "color" : { 10 | "color-space" : "srgb", 11 | "components" : { 12 | "red" : "0.541", 13 | "alpha" : "1.000", 14 | "blue" : "0.671", 15 | "green" : "0.769" 16 | } 17 | } 18 | } 19 | ] 20 | } -------------------------------------------------------------------------------- /CodeGenDemo/Resources/Assets.xcassets/Fruits/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | }, 6 | "properties" : { 7 | "provides-namespace" : true 8 | } 9 | } -------------------------------------------------------------------------------- /CodeGenDemo/Resources/Assets.xcassets/Fruits/Exotic/Banana.imageset/Banana-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FrenchKit/Mastering-code-generation-Classroom/f786004d3babdf464d4f09f6b706e3421b8800f5/CodeGenDemo/Resources/Assets.xcassets/Fruits/Exotic/Banana.imageset/Banana-icon.png -------------------------------------------------------------------------------- /CodeGenDemo/Resources/Assets.xcassets/Fruits/Exotic/Banana.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "scale" : "2x", 10 | "filename" : "Banana-icon.png" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /CodeGenDemo/Resources/Assets.xcassets/Fruits/Exotic/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | }, 6 | "properties" : { 7 | "provides-namespace" : true 8 | } 9 | } -------------------------------------------------------------------------------- /CodeGenDemo/Resources/Assets.xcassets/Fruits/Exotic/Mango.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "filename" : "Mango.png", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /CodeGenDemo/Resources/Assets.xcassets/Fruits/Exotic/Mango.imageset/Mango.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FrenchKit/Mastering-code-generation-Classroom/f786004d3babdf464d4f09f6b706e3421b8800f5/CodeGenDemo/Resources/Assets.xcassets/Fruits/Exotic/Mango.imageset/Mango.png -------------------------------------------------------------------------------- /CodeGenDemo/Resources/Assets.xcassets/Fruits/Round/Apricot.imageset/Apricot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FrenchKit/Mastering-code-generation-Classroom/f786004d3babdf464d4f09f6b706e3421b8800f5/CodeGenDemo/Resources/Assets.xcassets/Fruits/Round/Apricot.imageset/Apricot.png -------------------------------------------------------------------------------- /CodeGenDemo/Resources/Assets.xcassets/Fruits/Round/Apricot.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "filename" : "Apricot.png", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /CodeGenDemo/Resources/Assets.xcassets/Fruits/Round/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | }, 6 | "properties" : { 7 | "provides-namespace" : true 8 | } 9 | } -------------------------------------------------------------------------------- /CodeGenDemo/Resources/Assets.xcassets/Fruits/Round/Red/Apple.imageset/Apple-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FrenchKit/Mastering-code-generation-Classroom/f786004d3babdf464d4f09f6b706e3421b8800f5/CodeGenDemo/Resources/Assets.xcassets/Fruits/Round/Red/Apple.imageset/Apple-icon.png -------------------------------------------------------------------------------- /CodeGenDemo/Resources/Assets.xcassets/Fruits/Round/Red/Apple.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "filename" : "Apple-icon.png", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /CodeGenDemo/Resources/Assets.xcassets/Fruits/Round/Red/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /CodeGenDemo/Resources/Assets.xcassets/Fruits/Round/Red/Double/Cherry.imageset/Cherry.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FrenchKit/Mastering-code-generation-Classroom/f786004d3babdf464d4f09f6b706e3421b8800f5/CodeGenDemo/Resources/Assets.xcassets/Fruits/Round/Red/Double/Cherry.imageset/Cherry.png -------------------------------------------------------------------------------- /CodeGenDemo/Resources/Assets.xcassets/Fruits/Round/Red/Double/Cherry.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "filename" : "Cherry.png", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /CodeGenDemo/Resources/Assets.xcassets/Fruits/Round/Red/Double/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | }, 6 | "properties" : { 7 | "provides-namespace" : true 8 | } 9 | } -------------------------------------------------------------------------------- /CodeGenDemo/Resources/Assets.xcassets/Fruits/Round/Red/Tomato.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "filename" : "Tomato.png", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /CodeGenDemo/Resources/Assets.xcassets/Fruits/Round/Red/Tomato.imageset/Tomato.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FrenchKit/Mastering-code-generation-Classroom/f786004d3babdf464d4f09f6b706e3421b8800f5/CodeGenDemo/Resources/Assets.xcassets/Fruits/Round/Red/Tomato.imageset/Tomato.png -------------------------------------------------------------------------------- /CodeGenDemo/Resources/Avenir.ttc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FrenchKit/Mastering-code-generation-Classroom/f786004d3babdf464d4f09f6b706e3421b8800f5/CodeGenDemo/Resources/Avenir.ttc -------------------------------------------------------------------------------- /CodeGenDemo/Resources/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 32 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | -------------------------------------------------------------------------------- /CodeGenDemo/Resources/Base.lproj/Localizable.strings: -------------------------------------------------------------------------------- 1 | /* 2 | Localizable.strings 3 | CodeGenDemo 4 | 5 | Created by Olivier Halligon on 18/09/2017. 6 | Copyright © 2017 AliSoftware. All rights reserved. 7 | */ 8 | 9 | "PersonList.phones.count" = "%d phones"; 10 | 11 | "PersonList.dupes.title" = "Phones"; 12 | "PersonList.dupes.message" = "There are %1$d distinct phones and %2$d total."; 13 | "PersonList.dupes.button" = "OK"; 14 | 15 | "PersonRecord.section.person" = "Person"; 16 | "PersonRecord.section.address" = "Address"; 17 | "PersonRecord.section.phones" = "Phones"; 18 | "PersonRecord.edit.title" = "New Value"; 19 | "PersonRecord.edit.cancel" = "Cancel"; 20 | "PersonRecord.edit.ok" = "OK"; 21 | 22 | "PhoneEditor.title.model" = "Choisissez un modèle"; 23 | "PhoneEditor.title.name" = "Nom du téléphone"; 24 | "PhoneEditor.random.button" = "Random"; 25 | "PhoneEditor.random.format" = "%1$@ #%2$d"; 26 | "PhoneEditor.random.choice0" = "My Phone"; 27 | "PhoneEditor.random.choice1" = "My Awesome Phone"; 28 | "PhoneEditor.random.choice2" = "iPhone"; 29 | "PhoneEditor.random.choice3" = "Precious"; 30 | 31 | "Person.firstName" = "First name"; 32 | "Person.lastName" = "Last name"; 33 | "Address.street" = "Street"; 34 | "Address.city" = "City"; 35 | "Address.state" = "State"; 36 | -------------------------------------------------------------------------------- /CodeGenDemo/Resources/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | LSRequiresIPhoneOS 22 | 23 | UILaunchStoryboardName 24 | LaunchScreen 25 | UIMainStoryboardFile 26 | PersonList 27 | UIRequiredDeviceCapabilities 28 | 29 | armv7 30 | 31 | UISupportedInterfaceOrientations 32 | 33 | UIInterfaceOrientationPortrait 34 | UIInterfaceOrientationLandscapeLeft 35 | UIInterfaceOrientationLandscapeRight 36 | 37 | UISupportedInterfaceOrientations~ipad 38 | 39 | UIInterfaceOrientationPortrait 40 | UIInterfaceOrientationPortraitUpsideDown 41 | UIInterfaceOrientationLandscapeLeft 42 | UIInterfaceOrientationLandscapeRight 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /CodeGenDemo/Resources/colors.json: -------------------------------------------------------------------------------- 1 | { 2 | "SectionTitle" : "#000080", 3 | "FieldLabel" : "#4C4C4C" 4 | } 5 | -------------------------------------------------------------------------------- /CodeGenDemo/Resources/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #000080 4 | #4C4C4C 5 | 6 | -------------------------------------------------------------------------------- /CodeGenDemo/Resources/data.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "firstName": "John", 4 | "lastName": "Appleseed", 5 | "address": { 6 | "street": "1, Infinite Loop", 7 | "city": "Cupertino", 8 | "state": "California" 9 | }, 10 | "phones": [ 11 | { "name": "My Precious", "model": "iPhone6s" }, 12 | { "name": "Test Phone", "model": "iPhone7Plus" } 13 | ] 14 | }, 15 | { 16 | "firstName": "Tim", 17 | "lastName": "Cook", 18 | "address": { 19 | "street": "1 Apple Park Way", 20 | "city": "Cupertino", 21 | "state": "California" 22 | }, 23 | "phones": [ 24 | { "name": "My Phone", "model": "iPhone7" }, 25 | { "name": "Test Phone", "model": "iPhone7Plus" } 26 | ] 27 | } 28 | ] 29 | -------------------------------------------------------------------------------- /CodeGenDemo/Resources/fr.lproj/Localizable.strings: -------------------------------------------------------------------------------- 1 | /* 2 | Localizable.strings 3 | CodeGenDemo 4 | 5 | Created by Olivier Halligon on 18/09/2017. 6 | Copyright © 2017 AliSoftware. All rights reserved. 7 | */ 8 | 9 | "PersonList.phones.count" = "%d téléphones"; 10 | 11 | "PersonList.dupes.title" = "Téléphones"; 12 | "PersonList.dupes.message" = "Il y a %1$d téléphones distincts sur %2$d téléphones au total."; 13 | "PersonList.dupes.button" = "OK"; 14 | 15 | "PersonRecord.section.person" = "Personne"; 16 | "PersonRecord.section.address" = "Adresse"; 17 | "PersonRecord.section.phones" = "Téléphones"; 18 | "PersonRecord.edit.title" = "Nouvelle valeur"; 19 | "PersonRecord.edit.cancel" = "Annuler"; 20 | "PersonRecord.edit.ok" = "OK"; 21 | 22 | "PhoneEditor.title.model" = "Choisissez un modèle"; 23 | "PhoneEditor.title.name" = "Nom du téléphone"; 24 | "PhoneEditor.random.button" = "Au hasard"; 25 | "PhoneEditor.random.format" = "%1$@ #%2$d"; 26 | "PhoneEditor.random.choice0" = "Mon iPhone"; 27 | "PhoneEditor.random.choice1" = "Mon super iPhone"; 28 | "PhoneEditor.random.choice2" = "iPhone"; 29 | "PhoneEditor.random.choice3" = "Mon Précieux"; 30 | 31 | "Person.firstName" = "Prénom"; 32 | "Person.lastName" = "Nom"; 33 | "Address.street" = "Rue"; 34 | "Address.city" = "Ville"; 35 | "Address.state" = "État"; 36 | -------------------------------------------------------------------------------- /CodeGenDemo/Sources/Model/Address.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Address.swift 3 | // CodeGenDemo 4 | // 5 | // Created by Olivier HALLIGON on 31/08/2017. 6 | // Copyright © 2017 AliSoftware. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | // FIXME: sourcery: AutoJSONDeserializable 12 | struct Address { 13 | var street: String 14 | var city: String 15 | var state: String 16 | } 17 | 18 | 19 | // FIXME: Sourcery (Custom template) 20 | extension Address { 21 | static let stringProperties: [String] = [ 22 | // FIXME: SwiftGen L10n 23 | NSLocalizedString("Address.street", comment: ""), 24 | NSLocalizedString("Address.city", comment: ""), 25 | NSLocalizedString("Address.state", comment: ""), 26 | ] 27 | 28 | subscript(propertyIndex idx: Int) -> String { 29 | get { 30 | switch idx { 31 | case 0: return self.street 32 | case 1: return self.city 33 | case 2: return self.state 34 | default: fatalError("Out of bounds") 35 | } 36 | } 37 | set { 38 | switch idx { 39 | case 0: self.street = newValue 40 | case 1: self.city = newValue 41 | case 2: self.state = newValue 42 | default: fatalError("Out of bounds") 43 | } 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /CodeGenDemo/Sources/Model/Person.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Person.swift 3 | // CodeGenDemo 4 | // 5 | // Created by Olivier HALLIGON on 31/08/2017. 6 | // Copyright © 2017 AliSoftware. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | // FIXME: sourcery: AutoJSONDeserializable 12 | struct Person { 13 | var firstName: String 14 | var lastName: String 15 | var address: Address 16 | var phones: [Phone] 17 | } 18 | 19 | // FIXME: Sourcery (Custom template) 20 | extension Person { 21 | static let stringProperties: [String] = [ 22 | // FIXME: SwiftGen L10n 23 | NSLocalizedString("Person.firstName", comment: ""), 24 | NSLocalizedString("Person.lastName", comment: ""), 25 | ] 26 | 27 | subscript(propertyIndex idx: Int) -> String { 28 | get { 29 | switch idx { 30 | case 0: return self.firstName 31 | case 1: return self.lastName 32 | default: fatalError("Out of bounds") 33 | } 34 | } 35 | set { 36 | switch idx { 37 | case 0: self.firstName = newValue 38 | case 1: self.lastName = newValue 39 | default: fatalError("Out of bounds") 40 | } 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /CodeGenDemo/Sources/Model/Phone.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Phone.swift 3 | // CodeGenDemo 4 | // 5 | // Created by Olivier HALLIGON on 31/08/2017. 6 | // Copyright © 2017 AliSoftware. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | // FIXME: sourcery: AutoJSONDeserializable 12 | struct Phone { 13 | var model: PhoneModel 14 | var name: String 15 | } 16 | -------------------------------------------------------------------------------- /CodeGenDemo/Sources/Model/PhoneModel.swift: -------------------------------------------------------------------------------- 1 | // 2 | // PhoneModel.swift 3 | // CodeGenDemo 4 | // 5 | // Created by Olivier HALLIGON on 31/08/2017. 6 | // Copyright © 2017 AliSoftware. All rights reserved. 7 | // 8 | 9 | enum PhoneModel: String { 10 | case iPhone, iPhone3G, iPhone3GS 11 | case iPhone4, iPhone4s 12 | case iPhone5, iPhone5c, iPhone5s 13 | case iPhoneSE 14 | case iPhone6, iPhone6Plus 15 | case iPhone6s, iPhone6sPlus 16 | case iPhone7, iPhone7Plus 17 | // case iPhone8, iPhone8Plus, iPhoneX 18 | } 19 | 20 | // FIXME: Sourcery: AutoCases 21 | extension PhoneModel { 22 | static let allCases: [PhoneModel] = [ 23 | .iPhone, .iPhone3G, .iPhone3GS, 24 | .iPhone4, .iPhone4s, 25 | .iPhone5, .iPhone5c, .iPhone5s, 26 | .iPhoneSE, 27 | .iPhone6, .iPhone6Plus, 28 | .iPhone6s, .iPhone6sPlus, 29 | .iPhone7, .iPhone7Plus, 30 | ] 31 | } 32 | -------------------------------------------------------------------------------- /CodeGenDemo/Sources/Model/Ref.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Ref.swift 3 | // CodeGenDemo 4 | // 5 | // Created by Olivier Halligon on 17/09/2017. 6 | // Copyright © 2017 AliSoftware. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | class Ref { 12 | var object: T 13 | init(object: T) { 14 | self.object = object 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /CodeGenDemo/Sources/ViewControllers/Base.lproj/PersonList.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 35 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | -------------------------------------------------------------------------------- /CodeGenDemo/Sources/ViewControllers/PersonListCell.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ListCell.swift 3 | // CodeGenDemo 4 | // 5 | // Created by Olivier Halligon on 17/09/2017. 6 | // Copyright © 2017 AliSoftware. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class PersonListCell: UITableViewCell { 12 | static let identifier = "PersonListCell" 13 | 14 | @IBOutlet weak var nameLabel: UILabel! { 15 | didSet { 16 | // nameLabel.font = … // FIXME: SwiftGen fonts 17 | } 18 | } 19 | 20 | @IBOutlet weak var phoneModelLabel: UILabel! { 21 | didSet { 22 | // phoneModelLabel.font = … // FIXME: SwiftGen fonts 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /CodeGenDemo/Sources/ViewControllers/PersonListViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.swift 3 | // CodeGenDemo 4 | // 5 | // Created by Olivier HALLIGON on 31/08/2017. 6 | // Copyright © 2017 AliSoftware. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class PersonListViewController: UITableViewController { 12 | 13 | private var dataSource: [Ref] = [] { 14 | didSet { tableView.reloadData() } 15 | } 16 | 17 | override func viewDidLoad() { 18 | super.viewDidLoad() 19 | // Do any additional setup after loading the view, typically from a nib. 20 | 21 | // FIXME: Sourcery AutoJSONDeserializable 22 | let p1 = Person( 23 | firstName: "John", 24 | lastName: "Appleseed", 25 | address: Address(street: "1, Infinite Loop", city: "Cupertino", state: "California"), 26 | phones: [Phone(model: .iPhone7, name: "My Phone")] 27 | ) 28 | let p2 = Person( 29 | firstName: "Tim", 30 | lastName: "Cook", 31 | address: Address(street: "1, Apple Park", city: "Cupertino", state: "California"), 32 | phones: [ 33 | Phone(model: .iPhone7Plus, name: "My Precious"), 34 | Phone(model: .iPhone5s, name: "Oldie") 35 | ] 36 | ) 37 | 38 | dataSource = [p1, p2].map { Ref(object: $0) } 39 | 40 | let dupes = UIBarButtonItem(barButtonSystemItem: .action, target: self, action: #selector(findDupes)) 41 | self.navigationItem.rightBarButtonItem = dupes 42 | } 43 | 44 | override func viewDidAppear(_ animated: Bool) { 45 | super.viewDidAppear(animated) 46 | self.tableView.reloadData() 47 | } 48 | 49 | // MARK: UITableView 50 | 51 | override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { 52 | return dataSource.count 53 | } 54 | 55 | override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { 56 | let cell = tableView.dequeueReusableCell(withIdentifier: PersonListCell.identifier) as! PersonListCell 57 | let p = dataSource[indexPath.row].object 58 | cell.nameLabel.text = "\(p.firstName) \(p.lastName)" 59 | if p.phones.count == 1, let phone = p.phones.first { 60 | cell.phoneModelLabel.text = phone.name 61 | } else { 62 | let format = NSLocalizedString("PersonList.phones.count", comment: "") // FIXME: SwiftGen L10n 63 | cell.phoneModelLabel.text = String(format: format, p.phones.count) // FIXME: SwiftGen L10n 64 | } 65 | return cell 66 | } 67 | 68 | override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { 69 | // FIXME: SwiftGen storyboards - StoryboardScene.PersonRecord 70 | let vc = UIStoryboard(name: "PersonRecord", bundle: nil).instantiateInitialViewController() as! PersonRecordViewController 71 | vc.personRef = dataSource[indexPath.row] 72 | self.navigationController?.pushViewController(vc, animated: true) 73 | } 74 | 75 | // MARK: Actions 76 | 77 | @objc 78 | func findDupes() { 79 | let allPhones: [Phone] = self.dataSource.reduce([]) { (acc, personRef) -> [Phone] in 80 | return acc + personRef.object.phones 81 | } 82 | // FIXME: Sourcery AutoEquatable+AutoHashable 83 | let set = allPhones // Set(allPhones) 84 | // FIXME: SwiftGen L10n 85 | let format = NSLocalizedString("PersonList.dupes.mesage", comment: "") // here we have a bad hard-coded key! 86 | let alert = UIAlertController(title: NSLocalizedString("PersonList.dupes.title", comment: ""), 87 | message: String(format: format, set.count, allPhones.count), preferredStyle: .alert) 88 | // here we have a bad hard-coded key too! 89 | alert.addAction(UIAlertAction(title: NSLocalizedString("PersonList.dupes.ok", comment: ""), style: .default, handler: nil)) 90 | self.present(alert, animated: true, completion: nil) 91 | } 92 | } 93 | 94 | -------------------------------------------------------------------------------- /CodeGenDemo/Sources/ViewControllers/PersonRecord.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 36 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 93 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 114 | 117 | 120 | 121 | 122 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | -------------------------------------------------------------------------------- /CodeGenDemo/Sources/ViewControllers/PersonRecordCell.swift: -------------------------------------------------------------------------------- 1 | // 2 | // PersonRecordCell.swift 3 | // CodeGenDemo 4 | // 5 | // Created by Olivier Halligon on 17/09/2017. 6 | // Copyright © 2017 AliSoftware. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class PersonRecordCell: UITableViewCell { 12 | static let identifier = "PersonRecordCell" 13 | 14 | @IBOutlet weak var titleLabel: UILabel! { 15 | didSet { 16 | // titleLabel.font = … // FIXME: SwiftGen fonts - FontFamily.… 17 | } 18 | } 19 | 20 | @IBOutlet weak var valueLabel: UILabel! { 21 | didSet { 22 | // valueLabel.font = … // FIXME: SwiftGen fonts - FontFamily.… 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /CodeGenDemo/Sources/ViewControllers/PersonRecordViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // PersonRecordViewController.swift 3 | // CodeGenDemo 4 | // 5 | // Created by Olivier Halligon on 17/09/2017. 6 | // Copyright © 2017 AliSoftware. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class PersonRecordViewController: UITableViewController { 12 | var personRef: Ref! 13 | var person: Person { return personRef.object } 14 | 15 | override func numberOfSections(in tableView: UITableView) -> Int { 16 | return 3 17 | } 18 | 19 | override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { 20 | switch section { 21 | case 0: return Person.stringProperties.count 22 | case 1: return Address.stringProperties.count 23 | case 2: return person.phones.count 24 | default: return 0 25 | } 26 | } 27 | 28 | private static let sectionTitles = ["Person", "Address", "Phones"] // FIXME: SwiftGen L10n 29 | override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? { 30 | return PersonRecordViewController.sectionTitles[section] 31 | } 32 | 33 | override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { 34 | let cell = tableView.dequeueReusableCell(withIdentifier: PersonRecordCell.identifier) as! PersonRecordCell 35 | let row = indexPath.row 36 | 37 | switch indexPath.section { 38 | case 0: 39 | cell.titleLabel.text = Person.stringProperties[row] 40 | cell.valueLabel.text = person[propertyIndex: row] 41 | case 1: 42 | cell.titleLabel.text = Address.stringProperties[row] 43 | cell.valueLabel.text = person.address[propertyIndex: row] 44 | case 2: 45 | cell.titleLabel.text = person.phones[row].name 46 | cell.valueLabel.text = person.phones[row].model.rawValue 47 | default: 48 | fatalError("Unreachable IndexPath") 49 | } 50 | 51 | return cell 52 | } 53 | 54 | override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { 55 | tableView.deselectRow(at: indexPath, animated: true) 56 | let row = indexPath.row 57 | 58 | switch indexPath.section { 59 | case 0: 60 | prompt(person[propertyIndex: row]) { self.personRef.object[propertyIndex: row] = $0 } 61 | case 1: 62 | prompt(person.address[propertyIndex: row]) { self.personRef.object.address[propertyIndex: row] = $0 } 63 | case 2: 64 | // FIXME: SwiftGen storyboards - StoryboardScene.PersonRecord 65 | let phoneEditor = UIStoryboard(name: "PersonRecord", bundle: nil).instantiateViewController(withIdentifier: "PhoneEditor") as! PhoneEditorViewController 66 | phoneEditor.phone = person.phones[row] 67 | phoneEditor.onDismiss = { [weak self] newPhone in 68 | self?.personRef.object.phones[row] = newPhone 69 | self?.tableView.reloadData() 70 | } 71 | self.navigationController?.pushViewController(phoneEditor, animated: true) 72 | default: fatalError("Unreachable IndexPath") 73 | } 74 | } 75 | 76 | // MARK: Prompt 77 | 78 | func prompt(_ initialValue: String, completion: @escaping (String) -> Void) { 79 | // FIXME: SwiftGen L10n 80 | let alert = UIAlertController(title: "New value", message: nil, preferredStyle: .alert) 81 | alert.addTextField { $0.text = initialValue } 82 | alert.addAction(UIAlertAction(title: "Cancel", style: .cancel, handler: nil)) 83 | alert.addAction(UIAlertAction(title: "OK", style: .default) { [weak self] _ in 84 | guard let newText = alert.textFields?.first?.text else { return } 85 | completion(newText) 86 | self?.tableView.reloadData() 87 | }) 88 | 89 | self.present(alert, animated: true, completion: nil) 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /CodeGenDemo/Sources/ViewControllers/PhoneEditorViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // PhoneEditorViewController.swift 3 | // CodeGenDemo 4 | // 5 | // Created by Olivier Halligon on 17/09/2017. 6 | // Copyright © 2017 AliSoftware. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class PhoneEditorViewController: UIViewController { 12 | var phone: Phone! 13 | var onDismiss: (Phone!) -> Void = { _ in } 14 | 15 | @IBOutlet weak var phoneModelTitleLabel: UILabel! 16 | @IBOutlet weak var phoneModelPicker: UIPickerView! 17 | @IBOutlet weak var phoneNameLabel: UILabel! 18 | @IBOutlet weak var phoneNameField: UITextField! 19 | @IBOutlet weak var randomButton: UIButton! 20 | @IBOutlet var rollingImageViews: [UIImageView]! 21 | 22 | override func viewDidLoad() { 23 | super.viewDidLoad() 24 | 25 | let row = PhoneModel.allCases.index(of: phone.model) ?? 0 26 | self.phoneModelPicker.selectRow(row, inComponent: 0, animated: false) 27 | self.phoneNameField.text = phone.name 28 | 29 | self.phoneModelTitleLabel.text = "Pick a Phone Model" // FIXME: SwiftGen L10n 30 | self.phoneModelTitleLabel.font = UIFont(name: "Avenir", size: 12) // FIXME: SwiftGen Fonts - FontFamily.… 31 | self.phoneModelTitleLabel.textColor = UIColor.blue // FIXME: SwiftGen Colors - Color.… 32 | 33 | self.phoneNameLabel.text = "Phone Name" // FIXME: SwiftGen L10n 34 | self.phoneNameLabel.font = UIFont(name: "Avenir", size: 12) // FIXME: SwiftGen Fonts - FontFamily.… 35 | self.phoneNameLabel.textColor = UIColor.blue // FIXME: SwiftGen Colors - Color.… 36 | 37 | self.randomButton.setTitle("Random", for: .normal) // FIXME: SwiftGen L10n 38 | } 39 | 40 | @IBAction func randomAction(_ sender: UIButton) { 41 | rollingImageViews.forEach { iv in 42 | // FIXME: SwiftGen xcassets - Asset.… 43 | iv.animationImages = [ 44 | UIImage(named: "Fruits/Exotic/Banana")!, 45 | UIImage(named: "Fruits/Exotic/Mango")!, 46 | UIImage(named: "Fruits/Round/Apple")!, 47 | UIImage(named: "Fruits/Round/Apricot")!, 48 | UIImage(named: "Fruits/Round/Double/Cherry")!, 49 | ] 50 | iv.animationDuration = 0.05 + Double(arc4random_uniform(UInt32(20))) / 20.0 51 | iv.isHidden = false 52 | self.phoneNameField.isEnabled = false 53 | iv.startAnimating() 54 | } 55 | 56 | DispatchQueue.main.asyncAfter(deadline: .now() + .seconds(2)) { [weak self] in 57 | let proposals = ["My Phone", "My Awesome Phone", "iPhone", "Precious"] // FIXME: SwiftGen L10n 58 | let pIdx = Int(arc4random_uniform(UInt32(proposals.count))) 59 | let num = Int(arc4random_uniform(UInt32(200))) 60 | let format = NSLocalizedString("PhoneEditor.random.format", comment: "") // FIXME: SwiftGen L10n format 61 | self?.phone.name = String(format: format, proposals[pIdx], num) // FIXME: SwiftGen L10n format 62 | self?.phoneNameField.text = self?.phone.name 63 | self?.rollingImageViews.forEach { iv in 64 | iv.stopAnimating() 65 | iv.isHidden = true 66 | self?.phoneNameField.isEnabled = true 67 | } 68 | } 69 | } 70 | 71 | override func viewDidDisappear(_ animated: Bool) { 72 | super.viewDidDisappear(animated) 73 | self.onDismiss(self.phone) 74 | } 75 | } 76 | 77 | extension PhoneEditorViewController: UIPickerViewDataSource, UIPickerViewDelegate { 78 | func numberOfComponents(in pickerView: UIPickerView) -> Int { 79 | return 1 80 | } 81 | 82 | func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int { 83 | return PhoneModel.allCases.count 84 | } 85 | 86 | func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? { 87 | return PhoneModel.allCases[row].rawValue 88 | } 89 | 90 | func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) { 91 | phone.model = PhoneModel.allCases[row] 92 | } 93 | } 94 | 95 | extension PhoneEditorViewController: UITextFieldDelegate { 96 | func textFieldShouldReturn(_ textField: UITextField) -> Bool { 97 | textField.resignFirstResponder() 98 | return false 99 | } 100 | 101 | func textFieldDidEndEditing(_ textField: UITextField) { 102 | self.phone.name = textField.text ?? "" 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /CodeGenDemoTests/CodeGenDemoTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CodeGenDemoTests.swift 3 | // CodeGenDemoTests 4 | // 5 | // Created by Olivier Halligon on 17/09/2017. 6 | // Copyright © 2017 AliSoftware. All rights reserved. 7 | // 8 | 9 | import XCTest 10 | @testable import CodeGenDemo 11 | 12 | // FIXME: Uncomment once Sourcery AutoJSONDeserializable template in place 13 | /* 14 | class CodeGenDemoTests: XCTestCase { 15 | // FIXME: Sourcery (Custom Template) 16 | func test_Phone1_name() throws 17 | { 18 | let fileURL = Bundle(for: type(of: self)).url(forResource: "Phone1", withExtension: "json")! 19 | let json = try JSONSerialization.jsonObject(with: Data(contentsOf: fileURL), options: []) 20 | let obj = Phone(JSONObject: json) 21 | if let obj = obj { 22 | XCTAssertEqual(obj.name, "My Phone") 23 | } else { 24 | XCTFail("Nil returned when trying to deserialize") 25 | } 26 | } 27 | 28 | func test_Phone1_model() throws 29 | { 30 | let fileURL = Bundle(for: type(of: self)).url(forResource: "Phone1", withExtension: "json")! 31 | let json = try JSONSerialization.jsonObject(with: Data(contentsOf: fileURL), options: []) 32 | let obj = Phone(JSONObject: json) 33 | if let obj = obj { 34 | XCTAssertEqual(obj.model, .iPhone7) 35 | } else { 36 | XCTFail("Nil returned when trying to deserialize") 37 | } 38 | } 39 | 40 | func test_Phone2_name() throws 41 | { 42 | let fileURL = Bundle(for: type(of: self)).url(forResource: "Phone2", withExtension: "json")! 43 | let json = try JSONSerialization.jsonObject(with: Data(contentsOf: fileURL), options: []) 44 | let obj = Phone(JSONObject: json) // FIXME: Sourcery AutoJSONDeserializable 45 | if let obj = obj { 46 | XCTAssertEqual(obj.name, "Your Phone") 47 | } else { 48 | XCTFail("Nil returned when trying to deserialize") 49 | } 50 | } 51 | 52 | func test_Phone2_model() throws 53 | { 54 | let fileURL = Bundle(for: type(of: self)).url(forResource: "Phone2", withExtension: "json")! 55 | let json = try JSONSerialization.jsonObject(with: Data(contentsOf: fileURL), options: []) 56 | let obj = Phone(JSONObject: json) 57 | if let obj = obj { 58 | XCTAssertEqual(obj.model, .iPhone5s) 59 | } else { 60 | XCTFail("Nil returned when trying to deserialize") 61 | } 62 | } 63 | } 64 | */ 65 | -------------------------------------------------------------------------------- /CodeGenDemoTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /CodeGenDemoTests/fixtures/Phone1.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "My Phone", 3 | "model": "iPhone7" 4 | } 5 | -------------------------------------------------------------------------------- /CodeGenDemoTests/fixtures/Phone2.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Your Phone", 3 | "model": "iPhone5s" 4 | } 5 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Code Generation Classroom 2 | 3 | Learn to use SwiftGen & Sourcery to avoid having to type repetitive, boring code and improve your productivity and your code's type safety & maintenance! 4 | 5 | ## Requirements 6 | 7 | * This classroom expects that you already **know how to write Swift 3+ code** and have written a few (ideally iOS) applications. 8 | * We'll use Xcode 8.x, but Xcode 9.x should work too 9 | 10 | During the classroom, we'll learn how to install SwiftGen and Sourcery, but you are **encouraged to download the following ZIP files in advance** to have them around in your Download folders and avoid any download latency during the classroom: 11 | 12 | * SwiftGen 5.1.1 ([downloadable here](https://github.com/SwiftGen/SwiftGen/releases/latest)) 13 | * Sourcery 0.8.0 ([downloadable here](https://github.com/krzysztofzablocki/Sourcery/releases/latest)) 14 | 15 | ## Resources 16 | 17 | During the classroom, we'll use the following websites 18 | 19 | * SwiftGen & Sourcery GitHub repositories for their README & documentation 20 | * [Sourcery dedicated documentation's website](https://cdn.rawgit.com/krzysztofzablocki/Sourcery/master/docs/index.html) 21 | * [Stencil documentation](http://stencil.fuller.li/en/latest/builtins.html) 22 | 23 | ## Walkthrough & Step-Commits 24 | 25 | The classroom will consist of multiple steps that we'll go through together 26 | 27 | * **All the individual steps that we're gonna follow are listed [in this repo's wiki](https://github.com/FrenchKit/Mastering-code-generation-Classroom/wiki)**. 28 | * Each step is represented by an individual commit in the `steps` branch of this repository. 29 | 30 | 💡 Be sure to **keep that wiki open to follow along**. 31 | 32 | 💡 In case you get lost or left behind, don't hesitate to look at the ![Step x.y](https://img.shields.io/badge/Step-x.y-blue.svg) markers in the wiki walkthrough and jump directly to the corresponding commit to catch up with the rest of the class! 33 | 34 | --- 35 | 36 | ## Topics Overview 37 | 38 | #### Discover the project 39 | 40 | * Clone this repository 41 | * The teacher will make a quick tour of the code and app features 42 | 43 | #### SwiftGen 44 | 45 | * Download, install & discover SwiftGen 46 | * Convert the existing code to use it 47 | * [Bonus] learn how to customize a template 48 | 49 | #### Sourcery 50 | 51 | * Download, install & discover Sourcery 52 | * Try our first template to understand basic principles, discover the daemon mode 53 | * Discover & use the `AutoCases` template bundled with Sourcery 54 | * Try a third-party `AutoJSONDeserialization` template 55 | * Use `AutoEquatable` & `AutoHashable` templates 56 | * Create our own template for custom swift code 57 | 58 | #### Bonus : Gyro 59 | 60 | We won't probably have time to make a tour of [Gyro](https://github.com/NijiDigital/gyro), but if you're using Realm in your project, you'll likely be very interested in it. 61 | 62 | It's again another Code-Generation tool, but this time to generate code (typically your `Realm.Object` classes) from `.xcdatamodel`, so that you can use Xcode's visual datamodel editor to edit your Realm model with a nice UI. 63 | 64 | * Install gyro using `gem install gyro` 65 | * Visit [Gyro's repository](https://github.com/NijiDigital/gyro) and read the README 66 | * Open one `xcdatamodel` from the repo (or create your own) 67 | * Run `gyro` on that xcdatamodel with one of the template (Swift, ObjC, Android) provided and look at the generated code 68 | --------------------------------------------------------------------------------