├── VOODO.xctemplate ├── TemplateIcon.png ├── TemplateIcon@2x.png ├── TemplateInfo.plist └── ___FILEBASENAME___.swift ├── .gitignore └── README.md /VOODO.xctemplate/TemplateIcon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bigmountainstudio/VOODOFileTemplate/HEAD/VOODO.xctemplate/TemplateIcon.png -------------------------------------------------------------------------------- /VOODO.xctemplate/TemplateIcon@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bigmountainstudio/VOODOFileTemplate/HEAD/VOODO.xctemplate/TemplateIcon@2x.png -------------------------------------------------------------------------------- /VOODO.xctemplate/TemplateInfo.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SupportsSwiftPackage 6 | 7 | Kind 8 | Xcode.IDEFoundation.TextSubstitutionFileTemplateKind 9 | Description 10 | A SwiftUI file with a view, observable object, and data object 11 | Summary 12 | SwiftUI View 13 | SortOrder 14 | 1 15 | AllowedTypes 16 | 17 | public.swift-source 18 | 19 | Platforms 20 | 21 | DefaultCompletionName 22 | SwiftUIView 23 | MainTemplateFile 24 | ___FILEBASENAME___.swift 25 | 26 | 27 | -------------------------------------------------------------------------------- /VOODO.xctemplate/___FILEBASENAME___.swift: -------------------------------------------------------------------------------- 1 | //___FILEHEADER___ 2 | 3 | // View 4 | import SwiftUI 5 | 6 | struct ___FILEBASENAMEASIDENTIFIER___View: View { 7 | @StateObject private var oo = ___FILEBASENAMEASIDENTIFIER___OO() 8 | 9 | var body: some View { 10 | VStack { 11 | List(oo.data) { datum in 12 | Text(datum.name) 13 | } 14 | } 15 | .task { 16 | oo.fetch() 17 | } 18 | } 19 | } 20 | 21 | struct ___FILEBASENAMEASIDENTIFIER____Previews: PreviewProvider { 22 | static var previews: some View { 23 | ___FILEBASENAMEASIDENTIFIER___View() 24 | } 25 | } 26 | 27 | // Observable Object 28 | import Combine 29 | import SwiftUI 30 | 31 | class ___FILEBASENAMEASIDENTIFIER___OO: ObservableObject { 32 | @Published var data: [___FILEBASENAMEASIDENTIFIER___DO] = [] 33 | 34 | func fetch() { 35 | data = [___FILEBASENAMEASIDENTIFIER___DO(name: "Datum 1"), 36 | ___FILEBASENAMEASIDENTIFIER___DO(name: "Datum 2"), 37 | ___FILEBASENAMEASIDENTIFIER___DO(name: "Datum 3")] 38 | } 39 | } 40 | 41 | // Data Object 42 | import Foundation 43 | 44 | struct ___FILEBASENAMEASIDENTIFIER___DO: Identifiable { 45 | let id = UUID() 46 | var name: String 47 | } 48 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | # 3 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore 4 | 5 | ## User settings 6 | xcuserdata/ 7 | 8 | ## compatibility with Xcode 8 and earlier (ignoring not required starting Xcode 9) 9 | *.xcscmblueprint 10 | *.xccheckout 11 | 12 | ## compatibility with Xcode 3 and earlier (ignoring not required starting Xcode 4) 13 | build/ 14 | .DS_Store 15 | DerivedData/ 16 | *.moved-aside 17 | *.pbxuser 18 | !default.pbxuser 19 | *.mode1v3 20 | !default.mode1v3 21 | *.mode2v3 22 | !default.mode2v3 23 | *.perspectivev3 24 | !default.perspectivev3 25 | 26 | ## Obj-C/Swift specific 27 | *.hmap 28 | 29 | ## App packaging 30 | *.ipa 31 | *.dSYM.zip 32 | *.dSYM 33 | 34 | ## Playgrounds 35 | timeline.xctimeline 36 | playground.xcworkspace 37 | 38 | # Swift Package Manager 39 | # 40 | # Add this line if you want to avoid checking in source code from Swift Package Manager dependencies. 41 | # Packages/ 42 | # Package.pins 43 | # Package.resolved 44 | # *.xcodeproj 45 | # 46 | # Xcode automatically generates this directory with a .xcworkspacedata file and xcuserdata 47 | # hence it is not needed unless you have added a package configuration file to your project 48 | # .swiftpm 49 | 50 | .build/ 51 | 52 | # CocoaPods 53 | # 54 | # We recommend against adding the Pods directory to your .gitignore. However 55 | # you should judge for yourself, the pros and cons are mentioned at: 56 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control 57 | # 58 | # Pods/ 59 | # 60 | # Add this line if you want to avoid checking in source code from the Xcode workspace 61 | # *.xcworkspace 62 | 63 | # Carthage 64 | # 65 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 66 | # Carthage/Checkouts 67 | 68 | Carthage/Build/ 69 | 70 | # Accio dependency management 71 | Dependencies/ 72 | .accio/ 73 | 74 | # fastlane 75 | # 76 | # It is recommended to not store the screenshots in the git repo. 77 | # Instead, use fastlane to re-generate the screenshots whenever they are needed. 78 | # For more information about the recommended setup visit: 79 | # https://docs.fastlane.tools/best-practices/source-control/#source-control 80 | 81 | fastlane/report.xml 82 | fastlane/Preview.html 83 | fastlane/screenshots/**/*.png 84 | fastlane/test_output 85 | 86 | # Code Injection 87 | # 88 | # After new code Injection tools there's a generated folder /iOSInjectionProject 89 | # https://github.com/johnno1962/injectionforxcode 90 | 91 | iOSInjectionProject/ 92 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # VOODO File Template 2 | An Xcode file template that will create your view, observable object, and data object all in one file with sample data. 3 | 4 | ### You can then edit, delete or separate out parts if you want. 5 | 6 | ⚠️ Note: This template uses `ObservableObject`. 7 | 8 | 👉For the `@Observable` template, go [here](https://github.com/bigmountainstudio/VOODOFileTemplate2). 9 | 10 | # How to Install 11 | Add the VOODO.xctemplate to this directory: 12 | `~/Library/Developer/Xcode/Templates/File Templates/Custom/` 13 | 14 | *(Click your home directory and then show hidden folders with COMMAND+SHIFT+. )* 15 | 16 | *Note: That full directory might not even exist so you will have to create it.* 17 | 18 | # In Xcode 19 | 1. Start Xcode and add a new file. 20 | 1. Scroll down until you see the **Custom** section and select VOODO: 21 | ![image](https://user-images.githubusercontent.com/24855856/125980564-a21fc5f1-d0f3-4405-b3a9-85375634b02b.png) 22 | 23 | # Example Output 24 | ```swift 25 | // View 26 | import SwiftUI 27 | 28 | struct PersonView: View { 29 | @StateObject private var oo = PersonOO() 30 | 31 | var body: some View { 32 | List(oo.data) { datum in 33 | Text(datum.name) 34 | } 35 | .onAppear { 36 | oo.fetch() 37 | } 38 | } 39 | } 40 | 41 | struct Person_Previews: PreviewProvider { 42 | static var previews: some View { 43 | PersonView() 44 | } 45 | } 46 | 47 | // Observable Object 48 | import SwiftUI 49 | 50 | class PersonOO: ObservableObject { 51 | @Published var data: [PersonDO] = [] 52 | 53 | func fetch() { 54 | data = [PersonDO(name: "Datum 1"), 55 | PersonDO(name: "Datum 2"), 56 | PersonDO(name: "Datum 3")] 57 | } 58 | } 59 | 60 | // Data Object 61 | import Foundation 62 | 63 | struct PersonDO: Identifiable { 64 | let id = UUID() 65 | var name: String 66 | } 67 | ``` 68 | 69 | # Preview 70 | ![preview](https://user-images.githubusercontent.com/24855856/125980957-fd972bfe-daac-4ac7-8b3e-a68a96f53210.png) 71 | 72 | # You Are In Control 73 | From here, you can: 74 | * Delete what you don't need 75 | * Keep all the parts in one file 76 | * Break out the parts into separate files 77 | * Change the template to use any naming convention you want 78 | 79 | # Resources 80 | For more information on this architecture and how to work with data in SwiftUI, take a look at this book: **Working with Data in SwiftUI**. 81 | 82 | ![working with data in swiftui](https://user-images.githubusercontent.com/24855856/125804293-5f4ec808-220d-41a7-b1ce-9caebc06069e.png) 83 | 84 | [Learn More](https://www.bigmountainstudio.com/data) 85 | 86 | --------------------------------------------------------------------------------