{"id":4293,"date":"2020-05-27T12:00:34","date_gmt":"2020-05-27T12:00:34","guid":{"rendered":"https:\/\/blog.jetbrains.com\/objc\/?p=7345"},"modified":"2020-07-03T14:16:30","modified_gmt":"2020-07-03T14:16:30","slug":"tutorial-swiftui","status":"publish","type":"appcode","link":"https:\/\/blog.jetbrains.com\/fr\/appcode\/2020\/05\/tutorial-swiftui","title":{"rendered":"Tutorial: Create a SwiftUI application in AppCode"},"content":{"rendered":"<p>In this tutorial, you&#8217;ll create a simple SwiftUI application that shows a list of iOS conferences. The application will consist of two views:<\/p>\n<ul>\n<li>A list of conferences representing data from the local JSON file.<\/li>\n<li>Details for each conference<\/li>\n<\/ul>\n<p><img decoding=\"async\" alt=\"SwiftUI application\" width=\"800\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2020\/05\/objc-ac_swiftui_tutorial_app.png\"\/><\/p>\n<p>Along the way, you&#8217;ll get familiar with the basic AppCode workflow and useful features that help writing code easier and faster.<\/p>\n<p>Requirements: <\/p>\n<ul>\n<li>AppCode 2019.3 or later<\/li>\n<li>Xcode 11 or later<\/li>\n<\/ul>\n<p>Sample project: <a href=\"https:\/\/github.com\/JetBrains\/ac_tutorial_swiftui\/archive\/master.zip\" target=\"_blank\" rel=\"noopener\">iOSConferences<\/a><br \/>\n<!--more--><\/p>\n<h2 id=\"step_create_a_project\">Step 1. Create a project\ufeff<\/h2>\n<p>Projects created in AppCode are fully compatible with Xcode and use the same project model. After you create a project in AppCode, you can open and edit it in Xcode and vice versa, and all the data will be synchronized.<\/p>\n<p>Launch AppCode and click <strong>New Project<\/strong> on the <strong>Welcome<\/strong> screen:<\/p>\n<p><img decoding=\"async\" alt=\"Start new project\" width=\"778\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2020\/05\/objc-ac_welcome_screen_new_project.png\"\/><br \/>\nIf you have another project open in AppCode at the moment, select <strong>File | New Project<\/strong> from the main menu.<\/p>\n<p>In the dialog that opens, you see a list of Xcode project templates. Select <strong>iOS | Application | Single View App<\/strong> and click <strong>Next<\/strong>:<\/p>\n<p><img decoding=\"async\" alt=\"Create project dialog\" width=\"625\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2020\/05\/objc-ac_create_project_page1.png\"\/><\/p>\n<p>Fill in the following fields:<\/p>\n<ul>\n<li><strong>Product Name<\/strong>: your project name which will be also the name of your application. Type iOSConferences.<\/li>\n<li><strong>Organization Name<\/strong>: your or your company&#8217;s name.<\/li>\n<li><strong>Organization Identifier<\/strong>: your company&#8217;s identifier in reverse-DNS format, for example, <code>com.mycompany<\/code>:<\/li>\n<\/ul>\n<p><img decoding=\"async\" alt=\"Application details\" width=\"607\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2020\/05\/objc-ac_create_project_page1_names.png\"\/><\/p>\n<p>Your project name and organization identifier together build a bundle identifier \u2014 an automatically generated string that will identify your application in the operating system.<\/p>\n<div style=\"background-color: rgba(39, 40, 44, 0.03); color:rgba(44, 41, 39, 0.7); margin-bottom:15px; padding: 15px; margin-right: 0%; text-align: justify;\">If you need to change the project or organization name, bundle identifier, or other <a href=\"https:\/\/www.jetbrains.com\/help\/objc\/xcode-compatible-project-settings.html\" target=\"_blank\" rel=\"noopener\">project settings<\/a>, press <code>\u2318;<\/code> or select <strong>File | Project Settings<\/strong> from the main menu.<\/p>\n<p>You can also change your project settings in Xcode. Just select <strong>File | Open Project in Xcode<\/strong> from the main menu and change the necessary settings there. The changes will appear in AppCode as soon as you apply them in Xcode.<\/div>\n<p>Select <strong>Swift<\/strong> in the list of languages and <strong>SwiftUI<\/strong> in the <strong>User Interface<\/strong> field. Make sure that all checkboxes in the dialog are cleared as using tests or Core Data is outside the scope of this tutorial. Click <strong>Finish<\/strong>:<\/p>\n<p><img decoding=\"async\" alt=\"Create new project step\" width=\"625\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2020\/05\/objc-ac_create_project_page2.png\"\/><br \/>\nIn the Finder window that opens, select a directory where your project will be located.<\/p>\n<p>A new Swift project will be created and immediately opened in AppCode. In the left part of the AppCode window, you see the <strong>Project<\/strong> tool window. From here, you can navigate to necessary files, <a href=\"https:\/\/www.jetbrains.com\/help\/objc\/populating-projects.html\" target=\"_blank\" rel=\"noopener\">add<\/a> and delete files and folders, <a href=\"https:\/\/www.jetbrains.com\/help\/objc\/controlling-source-library-and-exclude-directories.html\" target=\"_blank\" rel=\"noopener\">exclude<\/a> files from indexing or from Xcode project, add files to different <a href=\"https:\/\/www.jetbrains.com\/help\/objc\/creating-and-managing-targets.html\" target=\"_blank\" rel=\"noopener\">targets<\/a>, and so on.<\/p>\n<p>To show and hide the <strong>Project<\/strong> tool window, press <code>\u23181<\/code>. For more information, see <a href=\"https:\/\/www.jetbrains.com\/help\/objc\/project-tool-window.html\" target=\"_blank\" rel=\"noopener\">Project tool window<\/a>:<\/p>\n<p><img decoding=\"async\" alt=\"Full IDE window\" width=\"736\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2020\/05\/objc-ac_empty_project.png\"\/><\/p>\n<h2 id=\"step_enable_interactive_preview\">Step 2. Enable interactive preview\ufeff<\/h2>\n<p>To preview changes in SwiftUI layouts from AppCode, you can use the <a href=\"https:\/\/github.com\/johnno1962\/InjectionIII\/blob\/master\/README.md\" target=\"_blank\" rel=\"noopener\">InjectionIII<\/a> application.<\/p>\n<h3 id=\"install_and_start_injectioniii\">Install and start InjectionIII\ufeff<\/h3>\n<p>Download InjectionIII from <a href=\"https:\/\/apps.apple.com\/us\/app\/injectioniii\/id1380446739?mt=12\" target=\"_blank\" rel=\"noopener\">AppStore<\/a> or from <a href=\"https:\/\/github.com\/johnno1962\/InjectionIII\/releases\" target=\"_blank\" rel=\"noopener\">GitHub<\/a> (version 1.8 or later). Place the InjectionIII application file to the Application folder and start the application. Its icon will appear in the status bar:<\/p>\n<p><img decoding=\"async\" alt=\"Injection III in the status bar\" width=\"212\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2020\/05\/objc-ac_injectionIII.png\"\/><\/p>\n<h3 id=\"prepare_the_project_for_working_with_injectioniii\">Prepare the project for working with InjectionIII\ufeff<\/h3>\n<p>In the <code>AppDelegate.swift<\/code> file, add the code for loading the InjectionIII bundle into the <code>application(_:didFinishLaunchingWithOptions:)<\/code> method:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"swift\" data-enlighter-title=\"\">func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -&gt; Bool {\r\n    \/\/ Override point for customization after application launch.\r\n    #if DEBUG\r\n    var injectionBundlePath = &quot;\/Applications\/InjectionIII.app\/Contents\/Resources&quot;\r\n    #if targetEnvironment(macCatalyst)\r\n    injectionBundlePath = &quot;\\(injectionBundlePath)\/macOSInjection.bundle&quot;\r\n    #elseif os(iOS)\r\n    injectionBundlePath = &quot;\\(injectionBundlePath)\/iOSInjection.bundle&quot;\r\n    #endif\r\n    Bundle(path: injectionBundlePath)?.load()\r\n    #endif\r\n    return true\r\n}<\/pre>\n<p>For more details, refer to the <a href=\"https:\/\/github.com\/johnno1962\/InjectionIII\/blob\/master\/README.md\" target=\"_blank\" rel=\"noopener\">InjectionIII documentation<\/a>.<\/p>\n<p>In the <code>ContentView.swift<\/code> file, go to the <code>ContentView_Previews<\/code> structure and add the <code>injected()<\/code> method inside the <code>#if DEBUG<\/code> block. Also, change <code>struct<\/code> to <code>class<\/code> for <code>ContentView_Previews<\/code>:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"swift\" data-enlighter-title=\"\">class ContentView_Previews: PreviewProvider {\r\n    static var previews: some View {\r\n        ContentView()\r\n    }\r\n\r\n    #if DEBUG\r\n    @objc class func injected() {\r\n        UIApplication.shared.windows.first?.rootViewController =\r\n                UIHostingController(rootView: ContentView())\r\n    }\r\n    #endif\r\n}\r\n<\/pre>\n<p>The <code>injected()<\/code> method reloads the view on code injection when the application is running in debug mode. Instead of reloading the view, you can have a design-time preview generated on code injection \u2014 the same way as Xcode 11 does. In this case, use the <code>previews<\/code> property of the current <a href=\"https:\/\/developer.apple.com\/documentation\/swiftui\/previewprovider\" target=\"_blank\" rel=\"noopener\">PreviewProvider<\/a>:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"swift\" data-enlighter-title=\"\">@objc class func injected() {\r\n    UIApplication.shared.windows.first?.rootViewController =\r\n            UIHostingController(rootView: ContentView_Previews.previews)\r\n}\r\n<\/pre>\n<h3 id=\"run_the_application_with_preview\">Run the application with preview\ufeff<\/h3>\n<p>Make sure that you have the <strong>Debug<\/strong> configuration selected for the current <a href=\"https:\/\/www.jetbrains.com\/help\/objc\/creating-and-editing-run-debug-configurations.html\" target=\"_blank\" rel=\"noopener\">run\/debug configuration<\/a>. To do this, select <strong>Run | Edit Configurations<\/strong> from the main menu:<\/p>\n<p><img decoding=\"async\" alt=\"Run\/debug configurations\" width=\"800\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2020\/05\/objc-ac_run_config_debug.png\"\/><\/p>\n<p>To run the application, select a device or simulator on the toolbar and press <code>\u2303R<\/code>:<\/p>\n<p><img decoding=\"async\" alt=\"Run\/debug configurations popup\" width=\"334\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2020\/05\/objc-ac_select_device_swiftui.png\"\/><\/p>\n<div style=\"background-color: rgba(39, 40, 44, 0.03); color:rgba(44, 41, 39, 0.7); margin-bottom:15px; padding: 15px; margin-right: 0%; text-align: justify;\">To run your application on a real device connected to your Mac, you need to <a href=\"https:\/\/help.apple.com\/xcode\/mac\/current\/#\/dev5a825a1ca\" target=\"_blank\" rel=\"noopener\">configure<\/a> your project in Xcode first.<\/div>\n<p>Then, press <code>\u2303R<\/code>. On the first run, you will be prompted to select the project directory in the Finder window that opens. <\/p>\n<div style=\"background-color: rgba(39, 40, 44, 0.03); color:rgba(44, 41, 39, 0.7); margin-bottom:15px; padding: 15px; margin-right: 0%; text-align: justify;\">In case you need to change the project directory later, for example, if you&#8217;ve changed your project location or want to use InjectionIII with another project, select <strong>Open Project<\/strong> from the <strong>InjectionIII<\/strong> menu and choose a new directory in Finder.<\/div>\n<p>Once InjectionIII is connected and the project directory is specified, you&#8217;ll see the following messages in the <strong>Run<\/strong> tool window:<\/p>\n<p><img decoding=\"async\" alt=\"Injection messages in Run toolwindow\" width=\"682\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2020\/05\/objc-ac_injection_connected.png\"\/><\/p>\n<p>Try to change some code in your view and see the changes on the simulator or device screen:<\/p>\n<p><img decoding=\"async\" alt=\"Try Injection\" width=\"800\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2020\/05\/objc-ac_swiftui_preview.png\"\/><\/p>\n<div style=\"background-color: rgba(39, 40, 44, 0.03); color:rgba(44, 41, 39, 0.7); margin-bottom:15px; padding: 15px; margin-right: 0%; text-align: justify;\">Changes that you make in your code appear in the preview on saving the file. AppCode <a href=\"https:\/\/www.jetbrains.com\/help\/objc\/working-with-source-code.html#auto_save\" target=\"_blank\" rel=\"noopener\">saves changes automatically<\/a> when you build and run an application, close files or projects, quit the IDE, and so on. Therefore, it may be useful to invoke autosave on a regular basis, let&#8217;s say, every second, so that you won&#8217;t need to trigger file saving manually. To do this, open the <strong>Preferences<\/strong> dialog <code>\u2318,<\/code> and go to <strong>Appearance &amp; Behavior | System Settings | Synchronization<\/strong>. Select the <strong>Save files automatically if application is idle for &#8230; sec<\/strong> checkbox and set the value to 1.<\/div>\n<h2 id=\"step_create_a_list\">Step 3. Create a list\ufeff<\/h2>\n<p>In <code>iOSConferences\/ContentView.swift<\/code>, rename <code>ContentView<\/code> to <code>ConferenceList<\/code> using the <a href=\"https:\/\/www.jetbrains.com\/help\/objc\/rename-refactorings.html\" target=\"_blank\" rel=\"noopener\">Rename<\/a> refactoring: place the caret at <code>ContentView<\/code>, press <code>\u21e7F6<\/code>, type the new name in the highlighted area, and press <code>\u23ce<\/code>:<\/p>\n<p><img decoding=\"async\" alt=\"Rename refactoring\" width=\"736\" data-gif-src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2020\/05\/objc-ac_rename_refactoring.gif\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2020\/05\/objc-ac_rename_refactoring.png\"\/><\/p>\n<p>The file itself will be renamed as well. The same way, rename <code>ContentView_Previews<\/code> to <code>ConferenceList_Previews<\/code>.<\/p>\n<p>Rebuild the project to have the interactive preview working after renaming the file by pressing <code>\u2318F9<\/code>. Instead of the <code>Hello, World!<\/code> text, add a list of two text elements:<\/p>\n<ul>\n<li>Select the <code>Text(&quot;Hello, World!&quot;)<\/code> line by pressing <code>\u2325\u2191<\/code> and add the <code>List<\/code> element containing <code>Text(&quot;Conference1&quot;)<\/code> instead:<img decoding=\"async\" alt=\"Extend selection\" width=\"500\" data-gif-src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2020\/05\/objc-ac_replace_code.gif\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2020\/05\/objc-ac_replace_code.png\"\/><\/li>\n<li>Add the second text element by duplicating <code>\u2318D<\/code> the first one:<img decoding=\"async\" alt=\"Duplicate line\" width=\"500\" data-gif-src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2020\/05\/objc-ac_duplicate_lines.gif\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2020\/05\/objc-ac_duplicate_lines.png\"\/><\/li>\n<li>You may notice that the code misses a space between <code>List<\/code> and <code>{<\/code>. Just press <code>\u2325\u2318L<\/code> to <a href=\"https:\/\/www.jetbrains.com\/help\/objc\/reformat-and-rearrange-code.html\" target=\"_blank\" rel=\"noopener\">reformat<\/a> the code on the whole page according to the guidelines specified in the <strong>Preferences | Editor | Code Style | Swift<\/strong>:<img decoding=\"async\" alt=\"Reformat code\" width=\"510\" data-gif-src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2020\/05\/objc-ac_reformat_code.gif\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2020\/05\/objc-ac_reformat_code.png\"\/><\/li>\n<\/ul>\n<p>As a result, you will have the following code:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"swift\" data-enlighter-title=\"\">struct ConferenceList: View {\r\n    var body: some View {\r\n        List {\r\n            Text(&quot;Conference1&quot;)\r\n            Text(&quot;Conference2&quot;)\r\n        }\r\n    }\r\n}\r\n<\/pre>\n<p>The application screen will look as follows:<\/p>\n<p><img decoding=\"async\" alt=\"Add SwiftUI list\" width=\"400\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2020\/05\/objc-ac_add_swiftui_list.png\"\/><\/p>\n<p>Add a title to the list. To do this, wrap the list with the <code>NavigationView<\/code> element and then call the <code>navigationBarTitle(_:)<\/code> method for the list:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"swift\" data-enlighter-title=\"\">struct ConferenceList: View {\r\n    var body: some View {\r\n        NavigationView {\r\n            List {\r\n                Text(&quot;Conference1&quot;)\r\n                Text(&quot;Conference2&quot;)\r\n            }.navigationBarTitle(&quot;Conferences&quot;)\r\n        }\r\n    }\r\n}\r\n<\/pre>\n<div style=\"background-color: rgba(39, 40, 44, 0.03); color:rgba(44, 41, 39, 0.7); margin-bottom:15px; padding: 15px; margin-right: 0%; text-align: justify;\">You can create custom <a href=\"https:\/\/www.jetbrains.com\/help\/objc\/using-live-templates.html\" target=\"_blank\" rel=\"noopener\">live templates<\/a> to quickly wrap your code with necessary constructs. See details in <a href=\"https:\/\/www.jetbrains.com\/help\/objc\/creating-and-editing-live-templates.html#surround_template\" target=\"_blank\" rel=\"noopener\">Create a surround live template<\/a>.<\/div>\n<p><img decoding=\"async\" alt=\"Conferences list\" width=\"400\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2020\/05\/objc-ac_add_swiftui_list_title.png\"\/><\/p>\n<p>Instead of two list items, let&#8217;s create one consisting of a title and subtitle. In the title, let&#8217;s display the conference name and in the subtitle \u2014 location. To do this, wrap the two <code>Text<\/code> elements in a <code>VStack<\/code> container, change their values, and apply the corresponding font styles to them:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"swift\" data-enlighter-title=\"\">VStack {\r\n    Text(&quot;Conference&quot;).font(.headline)\r\n    Text(&quot;Location&quot;).font(.subheadline)\r\n}\r\n<\/pre>\n<p><img decoding=\"async\" alt=\"Add element\" width=\"400\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2020\/05\/objc-ac_add_swiftui_list_one_element.png\"\/>]<\/p>\n<p>Align both <code>Text<\/code> elements left using the alignment parameter for the <code>VStack<\/code> container:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"swift\" data-enlighter-title=\"\">VStack(alignment: .leading) {\r\n   \/\/ ...\r\n}<\/pre>\n<p><img decoding=\"async\" alt=\"Add element\" width=\"400\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2020\/05\/objc-ac_add_swiftui_list_align.png\"\/><\/p>\n<div style=\"background-color: rgba(39, 40, 44, 0.03); color:rgba(44, 41, 39, 0.7); margin-bottom:15px; padding: 15px; margin-right: 0%; text-align: justify;\">To show <a href=\"https:\/\/www.jetbrains.com\/help\/objc\/viewing-reference-information.html\" target=\"_blank\" rel=\"noopener\">documentation<\/a> for the symbol at caret, press <code>F1<\/code>.<\/div>\n<h2 id=\"step_load_data_from_json\">Step 4. Load data from JSON\ufeff<\/h2>\n<p>Let&#8217;s make our list dynamic by loading data from the local <a href=\"https:\/\/raw.githubusercontent.com\/JetBrains\/ac_tutorial_swiftui\/master\/iOSConferences\/Resources\/conferencesData.json\" target=\"_blank\" rel=\"noopener\">conferencesData.json<\/a> file.<\/p>\n<p>Create a new group <code>Resources<\/code> where you will keep the JSON file:<\/p>\n<ul>\n<li>Right-click the <code>iOSConferences<\/code> group in the <strong>Project<\/strong> tool window and select <strong>New | Group<\/strong>.<\/li>\n<li>In the dialog that opens, type <code>Resources<\/code>.<\/li>\n<li>Make sure the <strong>Create folder<\/strong> checkbox is selected and click <strong>OK<\/strong>:<img decoding=\"async\" alt=\"Create Resources group\" width=\"470\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2020\/05\/objc-ac_create_group.png\"\/>\n<div style=\"background-color: rgba(39, 40, 44, 0.03); color:rgba(44, 41, 39, 0.7); margin-bottom:15px; padding: 15px; margin-right: 0%; text-align: justify;\">If you clear the <strong>Create folder<\/strong> checkbox, AppCode will create a group without adding the corresponding folder in the file system. See more in <a href=\"https:\/\/www.jetbrains.com\/help\/objc\/populating-projects.html#createGroups\" target=\"_blank\" rel=\"noopener\">Create groups<\/a>.<\/div>\n<\/li>\n<\/ul>\n<p>Add the <a href=\"https:\/\/raw.githubusercontent.com\/JetBrains\/ac_tutorial_swiftui\/master\/iOSConferences\/Resources\/conferencesData.json\" target=\"_blank\" rel=\"noopener\">downloaded JSON<\/a> to the newly created group:<\/p>\n<ul>\n<li>Right-click the <code>Resources<\/code> group and select <strong>Add | Files<\/strong>.<\/li>\n<li>Select the <code>conferencesData.jso<\/code>n file on your Mac.<\/li>\n<li>In the dialog that opens, leave the default settings and click <strong>OK<\/strong>:<img decoding=\"async\" alt=\"Add file\" width=\"427\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2020\/05\/objc-ac_add_file.png\"\/><\/li>\n<\/ul>\n<p>This file contains a list of iOS conferences. Each conference has a name, link to the official website, start and end dates, and location:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"json\" data-enlighter-title=\"\">\r\n{\r\n    &quot;name&quot;: &quot;SwiftLeeds&quot;,\r\n    &quot;link&quot;: &quot;https:\/\/swiftleeds.co.uk\/&quot;,\r\n    &quot;start&quot;: &quot;2020-10-07&quot;,\r\n    &quot;end&quot;: &quot;2020-10-08&quot;,\r\n    &quot;location&quot;: &quot;&#x1f1ec;&#x1f1e7; Leeds, UK&quot;\r\n}<\/pre>\n<p>Create a new <code>Data.swift<\/code> file where you will add a function for parsing the JSON data:<\/p>\n<ul>\n<li>Create a new group called <code>Model<\/code> as described above.<\/li>\n<li>Select this group, press <code>\u2318N<\/code>, and select <strong>Swift File<\/strong><\/li>\n<li>In the dialog that opens, type <code>Data<\/code> in the <strong>Name<\/strong> field and click <strong>OK<\/strong>:<img decoding=\"async\" alt=\"Add Swift file\" width=\"421\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2020\/05\/objc-ac_add_swift_file.png\"\/><\/li>\n<\/ul>\n<p>In the <code>Data.swift<\/code> file, add a function for reading data from JSON:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"swift\" data-enlighter-title=\"\">func loadFile&lt;T: Decodable&gt;(_ filename: String) -&gt; T {\r\n    let data: Data\r\n\r\n    guard let file = Bundle.main.url(forResource: filename, withExtension: nil)\r\n            else {\r\n        fatalError(&quot;Cannot find \\(filename)&quot;)\r\n    }\r\n    do {\r\n        data = try Data(contentsOf: file)\r\n    } catch {\r\n        fatalError(&quot;Cannot load \\(filename):\\n\\(error)&quot;)\r\n    }\r\n    do {\r\n        let decoder = JSONDecoder()\r\n        let format = DateFormatter()\r\n        format.dateFormat = &quot;yyyy-mm-dd&quot;\r\n        decoder.dateDecodingStrategy = .formatted(format)\r\n        return try decoder.decode(T.self, from: data)\r\n    } catch {\r\n        fatalError(&quot;Cannot&#039;t parse \\(filename): \\(T.self):\\n\\(error)&quot;)\r\n    }\r\n}<\/pre>\n<p>Create a new class for handling the parsed JSON data:<\/p>\n<ul>\n<li>Select the <code>Model<\/code> group.<\/li>\n<li>Press <code>\u2318N<\/code> and select <strong>Swift Type<\/strong>.<\/li>\n<li>In the dialog that opens, type <code>Conference<\/code> in the <strong>Name<\/strong> field and click <strong>OK<\/strong>:<img decoding=\"async\" alt=\"Add Conference\" width=\"421\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2020\/05\/objc-ac_add_swift_type.png\"\/><\/li>\n<li>Declare conformance to the <code>Codable<\/code> and <code>Identifiable<\/code> protocols and add a set of properties corresponding to the JSON data:\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"swift\" data-enlighter-title=\"\">class Conference: Codable,Identifiable {&lt;\/li&gt;&lt;\/ul&gt;\r\n    var name: String\r\n    var location: String\r\n    var start: Date\r\n    var end: Date?\r\n    var link: String\r\n}<\/pre>\n<p>In the <code>Data.swift<\/code> file, create a variable that will store the parsed data \u2014 an array of the <code>Conference<\/code> objects:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"swift\" data-enlighter-title=\"\">let conferencesData: [Conference] = loadFile(&quot;conferencesData.json&quot;)<\/pre>\n<div style=\"background-color: rgba(39, 40, 44, 0.03); color:rgba(44, 41, 39, 0.7); margin-bottom:15px; padding: 15px; margin-right: 0%; text-align: justify;\">You can use the <code>let<\/code> live template to introduce the variable: type <code>let<\/code> and press <code>\u21e5<\/code>. Press <code>\u21e5<\/code> to navigate between the template placeholders. To add the variable type, press <code>\u2325\u23ce<\/code> and select <strong>Add explicit type<\/strong>:<\/p>\n<p><img decoding=\"async\" alt=\"Live Template\" width=\"608\" data-gif-src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2020\/05\/objc-ac_use_live_template.gif\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2020\/05\/objc-ac_use_live_template.png\"\/><\/div>\n<p>In the <code>ConferenceList.swift<\/code> file, pass <code>conferencesData<\/code> to the <code>List<\/code> initializer and replace the strings in the <code>Text<\/code> elements by the values from the loaded JSON:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"swift\" data-enlighter-title=\"\">List(conferencesData) {conference in\r\n    VStack(alignment: .leading) {\r\n        Text(conference.name).font(.headline)\r\n        Text(conference.location).font(.subheadline)\r\n    }\r\n}.navigationBarTitle(&quot;Conferences&quot;)<\/pre>\n<p>The list of conferences will be displayed:<\/p>\n<p><img decoding=\"async\" alt=\"List of conferences\" width=\"398\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2020\/05\/objc-ac_dynamic_list.png\"\/><\/p>\n<h2 id=\"step_add_the_details_view\">Step 5. Add the details view\ufeff<\/h2>\n<p>The second view of our application will display the detailed data on each conference.<\/p>\n<p>Create a new SwiftUI file:<\/p>\n<ul>\n<li>In the <strong>Project<\/strong> tool window, press <code>\u2318N<\/code> and select <strong>File from Xcode Template<\/strong>.<\/li>\n<li>In the dialog that opens, select <strong>iOS | User Interface | SwiftUI View<\/strong> and click <strong>Next<\/strong>:<img decoding=\"async\" alt=\"Add SwiftUI file\" width=\"574\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2020\/05\/objc-ac_create_swiftui_file.png\"\/><\/li>\n<li>On the next page, type the filename \u2014 <code>ConferenceDetails<\/code>, make sure that the <strong>iOSConferences<\/strong> group and location are selected, and click <strong>Finish<\/strong>.<\/li>\n<\/ul>\n<p>Instead the default <code>Hello, World!<\/code> text, add the conference location:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"swift\" data-enlighter-title=\"\">struct ConferenceDetails: View {\r\n    var body: some View {\r\n        Text(conference.location)\r\n    }\r\n}<\/pre>\n<p>Since the <code>conference<\/code> variable is not defined in the current context, it is highlighted red. To define it directly from its usage, do the following:<\/p>\n<ul>\n<li>Place the caret at <code>conference<\/code> and press <code>\u2325\u23ce<\/code>.<\/li>\n<li>Select<strong> Create local variable &#8216;conference&#8217;<\/strong> and press <code>\u23ce<\/code>.<\/li>\n<li>In the list that appears, select <code>var<\/code>.<\/li>\n<li>To specify the type of the variable, press <code>\u2325\u23ce<\/code> again, select <strong>Add explicit type<\/strong>, and start typing <code>Conference<\/code>.<\/li>\n<li>Move the code line up by pressing <code>\u2325\u21e7\u2191<\/code>.<\/li>\n<li>Press <code>\u2325\u2318L<\/code> to fix the code formatting.<\/li>\n<\/ul>\n<p>As a result, your code will look as follows:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"swift\" data-enlighter-title=\"\">struct ConferenceDetails: View {\r\n    var conference: Conference\r\n    var body: some View {\r\n        Text(conference.location)\r\n    }\r\n}<\/pre>\n<p>Now, the <code>conference<\/code> parameter is missing in the <code>ConferenceDetails()<\/code> initializer within the <code>ConferenceDetails_Preview<\/code> structure. Place the caret at the highlighted code, press <code>\u2325\u23ce<\/code>, and select <strong>Apply Fix-it<\/strong>. The parameter name and placeholder for its value will appear. Pass <code>Conference()<\/code> as a parameter:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"swift\" data-enlighter-title=\"\">struct ConferenceDetails_Previews: PreviewProvider {\r\n    static var previews: some View {\r\n        ConferenceDetails(conference: Conference())\r\n    }\r\n}<\/pre>\n<p><code>Conference()<\/code> is highlighted red as the necessary initializer for the <code>Conference<\/code> class is missing. To add it, with the caret placed at the highlighted code, press <code>\u2325\u23ce<\/code> and select Create initializer. An empty initializer will be added to the Conference class. Set initial values for all the properties there, for example:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"swift\" data-enlighter-title=\"\">init() {\r\n    name = &quot;Conference Name&quot;\r\n    location = &quot;Location&quot;\r\n    start = Date()\r\n    end = Date()\r\n    link = &quot;https:\/\/www.google.com&quot;\r\n}<\/pre>\n<p>Duplicate <code>\u2318D<\/code> the <code>Text(conference.location)<\/code> line two times and wrap these three <code>Text<\/code> elements in a <code>VStack<\/code> container.<\/p>\n<div style=\"background-color: rgba(39, 40, 44, 0.03); color:rgba(44, 41, 39, 0.7); margin-bottom:15px; padding: 15px; margin-right: 0%; text-align: justify;\">You can create custom <a href=\"https:\/\/www.jetbrains.com\/help\/objc\/using-live-templates.html\" target=\"_blank\" rel=\"noopener\">live templates<\/a> to quickly wrap your code with necessary constructs. See details in <a href=\"https:\/\/www.jetbrains.com\/help\/objc\/creating-and-editing-live-templates.html#surround_template\" target=\"_blank\" rel=\"noopener\">Create a surround live template<\/a>.<\/div>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"swift\" data-enlighter-title=\"\">struct ConferenceDetails: View {\r\n    var conference: Conference\r\n    var body: some View {\r\n        VStack {\r\n            Text(conference.location)\r\n            Text(conference.location)\r\n            Text(conference.location)\r\n        }\r\n    }\r\n}<\/pre>\n<p>Enable the interactive preview for the <code>ConferenceDetails<\/code> by adding the <code>injected()<\/code> method for <code>ConferenceDetails_Previews<\/code> the same way you did for <code>ConferenceList_Previews<\/code>:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"swift\" data-enlighter-title=\"\">class ConferenceDetails_Previews: PreviewProvider {\r\n    static var previews: some View {\r\n        ConferenceDetails(conference: Conference())\r\n    }\r\n\r\n    #if DEBUG\r\n    @objc class func injected() {\r\n        UIApplication.shared.windows.first?.rootViewController =\r\n                UIHostingController(rootView: ConferenceDetails(conference: Conference()))\r\n    }\r\n    #endif\r\n}<\/pre>\n<p>Rebuild <code>\u2318F9<\/code> the application to have the preview working after adding the new file. By now, leave the <code>ConferenceDetails<\/code> view as is. Later, you will display here the conference dates and link.<\/p>\n<h2 id=\"step_set_up_navigation_between_the_list_and_details\">Step 6. Set up navigation between the list and details\ufeff<\/h2>\n<p>In the <code>ConferenceList.swift<\/code> file, go to the <code>ConferenceList<\/code> structure and wrap the <code>VStack<\/code> container in a <code>NavigationLink<\/code>.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"swift\" data-enlighter-title=\"\">NavigationLink {\r\n    VStack(alignment: .leading) {\r\n        Text(conference.name).font(.headline)\r\n        Text(conference.location).font(.subheadline)\r\n    }\r\n}<\/pre>\n<p>Pass the <code>ConferenceDetails<\/code> view as the destination parameter for the <code>NavigationLink<\/code>:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"swift\" data-enlighter-title=\"\">NavigationLink(destination: ConferenceDetails(conference: conference)) {\r\n    VStack(alignment: .leading) {\r\n        Text(conference.name).font(.headline)\r\n        Text(conference.location).font(.subheadline)\r\n     }\r\n}<\/pre>\n<p>The list items are now clickable, and the details view opens on tapping each of them:<\/p>\n<p><img decoding=\"async\" alt=\"List details\" width=\"398\" data-gif-src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2020\/05\/objc-ac_list_details_connection.gif\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2020\/05\/objc-ac_list_details_connection.png\"\/><\/p>\n<h2 id=\"step_display_the_conference_date_and_link\">Step 7. Display the conference date and link\ufeff<\/h2>\n<h3 id=\"display_the_conference_date\">Display the conference date\ufeff<\/h3>\n<p>In the ConferenceDetails view, the start and end dates should be displayed in format <code>MMMM dd, yyyy - MMMM dd, yyyy<\/code>.<\/p>\n<p>In the <code>Data.swift<\/code> file, add a new function <code>dateToString<\/code> as an extension for the <code>Date<\/code> class. This function converts <code>Date<\/code> to <code>String<\/code> and changes the date format:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"swift\" data-enlighter-title=\"\">extension Date {\r\n    func dateToString() -&gt; String {\r\n        let format = DateFormatter()\r\n        format.dateFormat = &quot;MMM dd, yyyy&quot;\r\n        format.string(from: self)\r\n    }\r\n}<\/pre>\n<p>The code above won&#8217;t be resolved as the function doesn&#8217;t return anything. Place the caret within the highlighted symbol and press <code>\u2325\u23ce<\/code>:<\/p>\n<p><img decoding=\"async\" alt=\"Apply fix-it\" width=\"462\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2020\/05\/objc-ac_fix_it.png\"\/><\/p>\n<p>Press <code>\u23ce<\/code> to apply the <a href=\"https:\/\/www.jetbrains.com\/help\/objc\/resolving-problems.html#apply-quick-fixes\" target=\"_blank\" rel=\"noopener\">quick-fix<\/a>. The <code>return<\/code> statement will be added:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"swift\" data-enlighter-title=\"\">extension Date {\r\n    func dateToString() -&gt; String {\r\n        let format = DateFormatter()\r\n        format.dateFormat = &quot;MMM dd, yyyy&quot;\r\n        return format.string(from: self)\r\n    }\r\n}<\/pre>\n<p>Create a method of the <code>Conference<\/code> class that will return the data of a conference in text format. Open <code>Conference.swift<\/code> and add the following method after the <code>var link: String<\/code> line:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"swift\" data-enlighter-title=\"\">func textDates() -&gt; String {\r\n    var result = start.dateToString()\r\n    if let end = self.end {\r\n        result = &quot;\\(result) - \\(end.dateToString())&quot;\r\n    }\r\n    return result\r\n}<\/pre>\n<p>In the <code>ConferenceDetails<\/code> view, replace the value of the second <code>Text<\/code> element with the conference date returned by the newly created <code>textDates()<\/code> method:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"swift\" data-enlighter-title=\"\">VStack {\r\n    Text(conference.location)\r\n    Text(conference.textDates())\r\n    Text(conference.location)\r\n}<\/pre>\n<p>The dates will appear in the preview:<\/p>\n<p><img decoding=\"async\" alt=\"Preview dates\" width=\"398\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2020\/05\/objc-ac_preview_dates.png\"\/><\/p>\n<h3 id=\"display_the_conference_link\">Display the conference link\ufeff<\/h3>\n<p>To make the conference link clickable, you need to add a button and pass a method for opening the URL as its action.<\/p>\n<p>In the <code>ConferenceDetails.swift<\/code> file, add a new structure named <code>LinkButton<\/code> that conforms to the <code>View<\/code> protocol and includes a <code>Button<\/code> with the <code>Go to official website<\/code> text:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"swift\" data-enlighter-title=\"\">struct LinkButton: View {\r\n    var body: some View {\r\n        Button() {\r\n            Text(&quot;Go to official website&quot;)\r\n        }\r\n    }\r\n}<\/pre>\n<div style=\"background-color: rgba(39, 40, 44, 0.03); color:rgba(44, 41, 39, 0.7); margin-bottom:15px; padding: 15px; margin-right: 0%; text-align: justify;\">You can use the <code>struct<\/code> live template for writing the structure code faster: just type <code>struct<\/code> and press <code>\u21e5<\/code>.<\/div>\n<p>Add an action for the <code>Button<\/code> \u2014 opening the conference link with the <code>open(_:)<\/code> method:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"swift\" data-enlighter-title=\"\">struct LinkButton: View {\r\n    var link = &quot;&quot;\r\n    var body: some View {\r\n        Button(action: {\r\n            UIApplication.shared.open(URL(string: self.link)!)\r\n        }) {\r\n            Text(&quot;Go to official website&quot;)\r\n        }\r\n    }\r\n}<\/pre>\n<p>Put the newly created <code>LinkButton<\/code> in the <code>ConferenceDetails<\/code> view and pass the conference link as a parameter for the <code>LinkButton<\/code> initializer:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"swift\" data-enlighter-title=\"\">struct ConferenceDetails: View {\r\n    var conference: Conference\r\n    var body: some View {\r\n        VStack {\r\n            Text(conference.location)\r\n            Text(conference.textDates())\r\n            LinkButton(link: conference.link)\r\n        }\r\n    }\r\n}<\/pre>\n<p>The link will appear in the preview:<\/p>\n<p><img decoding=\"async\" alt=\"Link preview\" width=\"398\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2020\/05\/objc-ac_link_preview.png\"\/><\/p>\n<h2 id=\"step_adjust_the_details_view_appearance\">Step 8. Adjust the details view appearance\ufeff<\/h2>\n<p>In the <code>ConferenceDetails<\/code> view, place the content of the <code>VStack<\/code> container to the top left corner of the screen by adjusting its frame width, height, and alignment:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"swift\" data-enlighter-title=\"\">struct ConferenceDetails: View {\r\n      var conference: Conference\r\n      var body: some View {\r\n          VStack {\r\n              Text(conference.location)\r\n              Text(conference.textDates())\r\n              LinkButton(link: conference.link)\r\n          }.frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: .infinity, alignment: .topLeading)\r\n      }\r\n}<\/pre>\n<p><img decoding=\"async\" alt=\"Adjust details step 1\" width=\"400\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2020\/05\/objc-ac_details_view_1.png\"\/><\/p>\n<p>Align the <code>VStack<\/code> content left by using the <code>alignment<\/code> parameter:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"swift\" data-enlighter-title=\"\">VStack(alignment: .leading) {\r\n\/\/ ...\r\n}<\/pre>\n<p><img decoding=\"async\" alt=\"Adjust details step 2\" width=\"400\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2020\/05\/objc-ac_details_view_2.png\"\/><\/p>\n<p>Add the default padding for the <code>VStack<\/code> container using the <code>padding()<\/code> method:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"swift\" data-enlighter-title=\"\">VStack(alignment: .leading) {\r\n    \/\/ ...\r\n}.frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: .infinity, alignment: .topLeading)\r\n        .padding()\r\n<\/pre>\n<p><img decoding=\"async\" alt=\"Adjust details step 3\" width=\"400\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2020\/05\/objc-ac_details_view_3.png\"\/><\/p>\n<p>Add the bottom padding for the elements within the <code>VStack<\/code> container:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"swift\" data-enlighter-title=\"\">VStack(alignment: .leading) {\r\n      Text(conference.location).padding(.bottom)\r\n      Text(conference.textDates()).padding(.bottom)\r\n      LinkButton(link: conference.link).padding(.bottom)\r\n}<\/pre>\n<p><img decoding=\"async\" alt=\"Adjust details step 4\" width=\"400\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2020\/05\/objc-ac_details_view_4.png\"\/><\/p>\n<div style=\"background-color: rgba(39, 40, 44, 0.03); color:rgba(44, 41, 39, 0.7); margin-bottom:15px; padding: 15px; margin-right: 0%; text-align: justify;\">You can place <a href=\"https:\/\/www.jetbrains.com\/help\/objc\/working-with-source-code.html#multiple_cursor\" target=\"_blank\" rel=\"noopener\">multiple carets<\/a> and type your code in several lines at the same time. To do this, place the caret where you want to start typing, press and hold <code>\u21e7\u2325<\/code>, and place the caret at the other lines:<br \/>\n<img decoding=\"async\" alt=\"Multiple cursors\" width=\"526\" data-gif-src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2020\/05\/objc-ac_multicursor.gif\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2020\/05\/objc-ac_multicursor.png\"\/><\/div>\n<p>Put the conference name in the view title by using the <code>navigationBarTitle(_:)<\/code> method for the <code>VStack<\/code> container:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"swift\" data-enlighter-title=\"\">\r\nVStack(alignment: .leading) {\r\n    \/\/ ...\r\n}.frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: .infinity, alignment: .topLeading)\r\n        .padding()\r\n        .navigationBarTitle(conference.name)\r\n\r\n<\/pre>\n<p>This change won&#8217;t be available in the interactive preview. Rerun the application to check it:<\/p>\n<p><img decoding=\"async\" alt=\"Adjust details - last step\" width=\"398\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2020\/05\/objc-ac_details_view_6.png\"\/><\/p>\n<h2 id=\"what_s_next\">What&#8217;s next\ufeff<\/h2>\n<p>You can elaborate this application by making it load the data from the <a href=\"https:\/\/github.com\/Lascorbe\/CocoaConferences\/blob\/master\/_data\/conferences.yml\" target=\"_blank\" rel=\"noopener\">remote YAML file<\/a> containing the up-to-date list of iOS\/macOS conferences. For parsing the data, you can use the <a href=\"https:\/\/github.com\/jpsim\/Yams\" target=\"_blank\" rel=\"noopener\">Yams<\/a> library added to the project by means of the <a href=\"https:\/\/cocoapods.org\/\" target=\"_blank\" rel=\"noopener\">CocoaPods<\/a> dependency manager. Stay tuned to learn it in action in our future tutorials!<\/p>\n<p><em>Your AppCode team<\/em><br \/>\n<em>JetBrains<\/em><br \/>\n<em>The Drive to Develop<\/em><\/p>\n","protected":false},"author":437,"featured_media":4294,"comment_status":"open","ping_status":"open","template":"","categories":[89,601],"tags":[791,792],"cross-post-tag":[],"acf":[],"_links":{"self":[{"href":"https:\/\/blog.jetbrains.com\/fr\/wp-json\/wp\/v2\/appcode\/4293"}],"collection":[{"href":"https:\/\/blog.jetbrains.com\/fr\/wp-json\/wp\/v2\/appcode"}],"about":[{"href":"https:\/\/blog.jetbrains.com\/fr\/wp-json\/wp\/v2\/types\/appcode"}],"author":[{"embeddable":true,"href":"https:\/\/blog.jetbrains.com\/fr\/wp-json\/wp\/v2\/users\/437"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.jetbrains.com\/fr\/wp-json\/wp\/v2\/comments?post=4293"}],"version-history":[{"count":1,"href":"https:\/\/blog.jetbrains.com\/fr\/wp-json\/wp\/v2\/appcode\/4293\/revisions"}],"predecessor-version":[{"id":55064,"href":"https:\/\/blog.jetbrains.com\/fr\/wp-json\/wp\/v2\/appcode\/4293\/revisions\/55064"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/blog.jetbrains.com\/fr\/wp-json\/wp\/v2\/media\/4294"}],"wp:attachment":[{"href":"https:\/\/blog.jetbrains.com\/fr\/wp-json\/wp\/v2\/media?parent=4293"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.jetbrains.com\/fr\/wp-json\/wp\/v2\/categories?post=4293"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.jetbrains.com\/fr\/wp-json\/wp\/v2\/tags?post=4293"},{"taxonomy":"cross-post-tag","embeddable":true,"href":"https:\/\/blog.jetbrains.com\/fr\/wp-json\/wp\/v2\/cross-post-tag?post=4293"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}