<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Vadim Atamanenko</title>
    <description>The latest articles on DEV Community by Vadim Atamanenko (@vadimatamanenko).</description>
    <link>https://dev.to/vadimatamanenko</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F700009%2Fcae70efc-5313-4b2f-b281-6129c0676470.jpeg</url>
      <title>DEV Community: Vadim Atamanenko</title>
      <link>https://dev.to/vadimatamanenko</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/vadimatamanenko"/>
    <language>en</language>
    <item>
      <title>The Future of Artificial Intelligence: Trends and Implications for Software Engineers</title>
      <dc:creator>Vadim Atamanenko</dc:creator>
      <pubDate>Tue, 07 Mar 2023 19:00:00 +0000</pubDate>
      <link>https://dev.to/vadimatamanenko/the-future-of-artificial-intelligence-trends-and-implications-for-software-engineers-266b</link>
      <guid>https://dev.to/vadimatamanenko/the-future-of-artificial-intelligence-trends-and-implications-for-software-engineers-266b</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;Artificial Intelligence (AI) is one of the fastest growing fields in computer science and software engineering. It has the potential to transform numerous industries by automating processes, making predictions, and providing insights. AI is also a rapidly evolving field, with new trends and technologies emerging regularly. In this article, we will explore some of the current and future trends in AI, their implications for software engineers, and some of the leading experts in the field.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Current Trends in AI:
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Natural Language Processing (NLP): NLP is a subfield of AI that deals with the interaction between computers and human language. NLP has become increasingly important in recent years with the growth of chatbots, voice assistants, and automated content creation.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Deep Learning: Deep learning is a subset of machine learning that involves the use of neural networks with multiple layers. This technology is particularly useful for tasks that involve large amounts of data, such as image and speech recognition.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Robotics: Robotics involves the use of robots to perform tasks that are typically performed by humans. AI is crucial for robotics because it allows robots to adapt to their environment and perform complex tasks.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Explainable AI: Explainable AI (XAI) is a field that seeks to make AI more transparent and understandable. XAI is important for applications such as healthcare, where it is essential to understand how decisions are made.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Implications for Software Engineers:
&lt;/h2&gt;

&lt;p&gt;The growth of AI has significant implications for software engineers. Software engineers will need to be familiar with AI technologies and be able to integrate them into their applications. They will also need to understand the ethical and societal implications of AI, such as bias and privacy concerns.&lt;/p&gt;

&lt;h2&gt;
  
  
  Top 5 Leading AI Experts:
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Yoshua Bengio:&lt;/strong&gt; Bengio is a computer scientist and AI expert who is known for his work on deep learning. He is one of the pioneers of deep learning and has received numerous awards for his contributions to the field.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Fei-Fei Li:&lt;/strong&gt; Li is a computer scientist and AI expert who is known for her work on computer vision. She is the founder of AI4ALL, a nonprofit organization that seeks to increase diversity and inclusion in AI.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Andrew Ng:&lt;/strong&gt; Ng is a computer scientist and AI expert who is known for his work on deep learning and online education. He is the founder of Coursera, an online learning platform that offers courses in AI and other fields.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Yann LeCun:&lt;/strong&gt; LeCun is a computer scientist and AI expert who is known for his work on convolutional neural networks (CNNs). He is the director of AI research at Facebook and has received numerous awards for his contributions to the field.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Demis Hassabis:&lt;/strong&gt; Hassabis is a computer scientist and AI expert who is known for his work on reinforcement learning. He is the founder and CEO of DeepMind, a company that develops AI technologies for a variety of applications, including healthcare and gaming.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Conclusion:
&lt;/h2&gt;

&lt;p&gt;AI is a rapidly evolving field with numerous applications and implications for software engineers. As AI continues to grow and evolve, software engineers will need to keep up with the latest trends and technologies to remain competitive in the job market. By staying informed and continuing to learn, software engineers can take advantage of the many opportunities that AI has to offer.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>writing</category>
    </item>
    <item>
      <title>10 Must-Have Tools for Swift iOS Development: Boost Your Productivity Today</title>
      <dc:creator>Vadim Atamanenko</dc:creator>
      <pubDate>Tue, 07 Feb 2023 08:15:32 +0000</pubDate>
      <link>https://dev.to/vadimatamanenko/10-must-have-tools-for-swift-ios-development-boost-your-productivity-today-1dni</link>
      <guid>https://dev.to/vadimatamanenko/10-must-have-tools-for-swift-ios-development-boost-your-productivity-today-1dni</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;As an iOS developer, having the right tools can greatly enhance your productivity and the quality of your work. With the increasing popularity of Swift, a programming language developed by Apple, there has been a surge of tools specifically designed for iOS development. In this article, we will be discussing the top 10 tools for iOS developers using Swift, including their technical details and a simple explanation to help you understand their purpose and usage. Whether you're a seasoned iOS developer or just starting out, these tools are sure to make your development process smoother and more efficient. So without further ado, let's dive in!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Here are the top 10 tools for iOS developers using Swift:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvjhgwd5mtyx0f7dsg6rq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvjhgwd5mtyx0f7dsg6rq.png" alt="Image description" width="150" height="150"&gt;&lt;/a&gt;&lt;br&gt;
&lt;strong&gt;Xcode&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The official integrated development environment (IDE) for iOS, macOS, tvOS, and watchOS development.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjsk6p4jytxnnjruutvqa.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjsk6p4jytxnnjruutvqa.png" alt="Image description" width="150" height="150"&gt;&lt;/a&gt;&lt;br&gt;
&lt;strong&gt;CocoaPods&lt;/strong&gt; - A dependency manager for Swift and Objective-C Cocoa projects.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Feilj1sc63jytij2yjsqo.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Feilj1sc63jytij2yjsqo.png" alt="Image description" width="150" height="150"&gt;&lt;/a&gt;&lt;br&gt;
&lt;strong&gt;Alamofire&lt;/strong&gt; - An HTTP networking library written in Swift.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqxcs34xz89q69nxrfau5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqxcs34xz89q69nxrfau5.png" alt="Image description" width="150" height="150"&gt;&lt;/a&gt;&lt;br&gt;
&lt;strong&gt;Realm&lt;/strong&gt; - An open-source object database management system for mobile devices.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fs8ncr67efbte6k5lmab6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fs8ncr67efbte6k5lmab6.png" alt="Image description" width="267" height="150"&gt;&lt;/a&gt;&lt;br&gt;
&lt;strong&gt;SwiftLint&lt;/strong&gt; - A tool for maintaining a consistent coding style in Swift projects.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fz76dr1cshqs2z2dxyxiu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fz76dr1cshqs2z2dxyxiu.png" alt="Image description" width="150" height="136"&gt;&lt;/a&gt;&lt;br&gt;
&lt;strong&gt;Sketch&lt;/strong&gt; - A digital design tool for user interface and user experience design.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fy2852y0gxwnf4n8p48sx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fy2852y0gxwnf4n8p48sx.png" alt="Image description" width="150" height="145"&gt;&lt;/a&gt;&lt;br&gt;
&lt;strong&gt;Fastlane&lt;/strong&gt; - A continuous delivery platform for iOS and Android apps.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fabric&lt;/strong&gt; - A mobile platform with modular kits for crash reporting, analytics, and beta testing.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhukzrorh85nskw36qyu3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhukzrorh85nskw36qyu3.png" alt="Image description" width="150" height="150"&gt;&lt;/a&gt;&lt;br&gt;
&lt;strong&gt;GitHub&lt;/strong&gt; - A web-based hosting service for version control repositories.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4d622y1olg0mbe4vgzjg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4d622y1olg0mbe4vgzjg.png" alt="Image description" width="570" height="150"&gt;&lt;/a&gt;&lt;br&gt;
&lt;strong&gt;Stack Overflow&lt;/strong&gt; - A question-and-answer community for programmers to share their knowledge and learn from each other.&lt;/p&gt;

&lt;p&gt;These tools are some of the most widely used by iOS developers and can greatly enhance your development process. Whether you're working on a small personal project or a large enterprise application, these tools can help you get the job done more efficiently and effectively.&lt;/p&gt;

</description>
      <category>discuss</category>
      <category>community</category>
    </item>
    <item>
      <title>Environment Objects &amp; SwiftUI Styles</title>
      <dc:creator>Vadim Atamanenko</dc:creator>
      <pubDate>Mon, 26 Dec 2022 09:46:43 +0000</pubDate>
      <link>https://dev.to/vadimatamanenko/environment-objects-swiftui-styles-p7l</link>
      <guid>https://dev.to/vadimatamanenko/environment-objects-swiftui-styles-p7l</guid>
      <description>&lt;p&gt;SwiftUI environments and styles are the two pillars of Apple's official framework (declarative structure). Despite this, when SwiftUI was first launched, using them together resulted in a guaranteed application crash.&lt;/p&gt;

&lt;p&gt;In particular, the crash happened when we used &lt;code&gt;@EnvironmentObject&lt;/code&gt; inside our style definition: when is it safe to use them together? Let's find out.&lt;/p&gt;

&lt;h2&gt;
  
  
  Example
&lt;/h2&gt;

&lt;p&gt;Meet &lt;code&gt;FSStyle&lt;/code&gt;, a button style that expects an environment object &lt;code&gt;FSEnvironmentObject&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class FSEnvironmentObject: ObservableObject {
  @Published var title = "tap me"
}

struct FSStyle: ButtonStyle {
  @EnvironmentObject var object: FSEnvironmentObject

  func makeBody(configuration: Configuration) -&amp;gt; some View {
    Button(object.title) { }
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Based on the definition, we expect everything to work as long as we inject the environment object at some point before applying the style. For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;struct ContentView: View {
  @StateObject var object = FSEnvironmentObject()

  var body: some View {
    Button("tap me") {
    }
    .buttonStyle(FSStyle())
    .environmentObject(object)
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;..and yet if we ran this code on any version of iOS prior to 14.5, it was guaranteed to fail 100% of the time with a &lt;code&gt;Fatal error: No ObservableObject of type FSEnvironmentObject found..&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;It fails as soon as an environment object is used inside the &lt;code&gt;makeBody(configuration: )&lt;/code&gt; method, and both the definition of the object and the execution of &lt;code&gt;makeBody(configuration: )&lt;/code&gt; are irrelevant.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;There are two main ways to work around the bug: either style it to match &lt;code&gt;DynamicProperty&lt;/code&gt;(many thanks to &lt;a href="https://github.com/linqingmo" rel="noopener noreferrer"&gt;Lin Qing Mo&lt;/a&gt; for the tip!), or return a View in the &lt;code&gt;makeBody (configuration: )&lt;/code&gt; method and have that View read the environment object.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Now that we have seen what the problem is, let's find out in which iOS versions and styles this error occurs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Test setup
&lt;/h2&gt;

&lt;p&gt;We want to find out which versions of iOS are safe to use all possible styles (not just button styles). We can create a small test app and run it on all versions of iOS that support SwiftUI and get results.&lt;/p&gt;

&lt;p&gt;Continuing with the &lt;code&gt;ButtonStyle&lt;/code&gt;example, here is the complete application:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import UIKit
import SwiftUI

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate { }

class SceneDelegate: UIResponder, UIWindowSceneDelegate {
  var window: UIWindow?
  var object: FSEnvironmentObject = FSEnvironmentObject()

  func scene(
    _ scene: UIScene, 
    willConnectTo session: UISceneSession, 
    options connectionOptions: UIScene.ConnectionOptions
  ) {
    if let windowScene = scene as? UIWindowScene {
      let window = UIWindow(windowScene: windowScene)
      let contentView = ContentView().environmentObject(object)
      window.rootViewController = UIHostingController(rootView: contentView)
      self.window = window
      window.makeKeyAndVisible()
    }
  }
}

struct ContentView: View {
  var body: some View {
    Button("tap me") {
    }
    .buttonStyle(FSStyle())
  }
}

struct FSStyle: ButtonStyle {
  @EnvironmentObject var object: FSEnvironmentObject

  func makeBody(configuration: Configuration) -&amp;gt; some View {
    Button(object.title) { }
  }
}

class FSEnvironmentObject: ObservableObject {
  @Published var title = "tap me"
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The application consists of a single screen that contains our test component/style.&lt;/p&gt;

&lt;p&gt;A few notes:&lt;/p&gt;

&lt;p&gt;we're using the UIKit lifecycle because we want to run tests on iOS 13 as well&lt;br&gt;
we don't use &lt;code&gt;@StateObject&lt;/code&gt; on the environment object because this property wrapper is only for iOS 14+&lt;br&gt;
the only difference between testing &lt;code&gt;ButtonStyle&lt;/code&gt; and other styles is defining the &lt;code&gt;FSStyle&lt;/code&gt; and &lt;code&gt;ContentView&lt;/code&gt; body, everything else remains the same&lt;/p&gt;

&lt;h2&gt;
  
  
  CI/CD setup
&lt;/h2&gt;

&lt;p&gt;We will be testing twelve versions of iOS, from iOS 13.0 to iOS 14.5, and all eight styles that support customization.&lt;/p&gt;

&lt;p&gt;Testing each combination by hand would be quite difficult, instead we can let the CI/CD provider do all the hard work for us. Any CI/CD setup will do, here's how the different versions of Xcode/iOS were distributed for this study:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;macOS 10.14&lt;/strong&gt;&lt;br&gt;
&lt;em&gt;iOS 13.0, Xcode 11.0&lt;br&gt;
iOS 13.1, Xcode 11.1&lt;br&gt;
iOS 13.2, Xcode 11.2&lt;/em&gt;&lt;br&gt;
&lt;strong&gt;macOS 10.15&lt;/strong&gt;&lt;br&gt;
&lt;em&gt;iOS 13.3, Xcode 11.3.1&lt;br&gt;
iOS 13.4, Xcode 11.4.1&lt;br&gt;
iOS 13.5, Xcode 11.5&lt;br&gt;
iOS 13.6, Xcode 11.6&lt;br&gt;
iOS 13.7, Xcode 11.7&lt;br&gt;
iOS 14.0, Xcode 12.0.1&lt;br&gt;
iOS 14.1, Xcode 12.1&lt;br&gt;
iOS 14.2, Xcode 12.2&lt;br&gt;
iOS 14.3, Xcode 12.3&lt;/em&gt;&lt;br&gt;
&lt;strong&gt;macOS 11.4:&lt;/strong&gt;&lt;br&gt;
&lt;em&gt;iOS 14.4, Xcode 12.4&lt;br&gt;
iOS 14.5, Xcode 12.5&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Results
&lt;/h2&gt;

&lt;p&gt;Since the test application has only one screen that immediately displays the component under test, all that is needed to pass the test is to launch the application and not immediately crash. Here is the result:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Foxdnu8zkw9vxpqycd5a8.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Foxdnu8zkw9vxpqycd5a8.PNG" alt="Image description" width="800" height="392"&gt;&lt;/a&gt;&lt;br&gt;
💥 = crash, ✅ = passed. *Style available since iOS 14.&lt;/p&gt;

&lt;p&gt;Let's summarize:&lt;/p&gt;

&lt;p&gt;all styles except &lt;code&gt;ButtonStyle&lt;/code&gt;support &lt;code&gt;@EnvironmentObject&lt;/code&gt; as of iOS 14.0&lt;br&gt;
since iOS 14.5 all styles including &lt;code&gt;ButtonStyle&lt;/code&gt;support &lt;code&gt;@EnvironmentObject&lt;/code&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusions
&lt;/h2&gt;

&lt;p&gt;The reason why styles + &lt;code&gt;@EnvironmentObject&lt;/code&gt; was not supported from the start is likely to remain inside the SwiftUI command, however this could have been intentional:&lt;/p&gt;

&lt;p&gt;Looking at how standard SwiftUI styles are applied, in addition to the few parameters passed through &lt;code&gt;Configuration&lt;/code&gt;, most of the mutable components come from &lt;code&gt;EnvironmentValues&lt;/code&gt;, such as &lt;code&gt;@Environment (\.IsEnabled)&lt;/code&gt;, &lt;code&gt;@Environment (\.font)&lt;/code&gt; and &lt;code&gt;@Environment (\.controlProminence)&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Unlike &lt;code&gt;@EnvironmentObject&lt;/code&gt;, &lt;code&gt;EnvironmentValues&lt;/code&gt; ​​has been supported (no crash!) since iOS 13.0, so I recommend them when adding dynamics to our custom styles.&lt;/p&gt;

&lt;p&gt;Whether this was a mistake or intentional, as an SDK vendor, it's important for us to disambiguate and clarify such scenarios for developers.&lt;/p&gt;

&lt;p&gt;To the best of my knowledge, this has not been documented anywhere and has not been covered in any release notes: if the developers have allowed it, it is in the framework.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Another place where this could be a problem is in View modifiers, however both &lt;code&gt;EnvironmentValues&lt;/code&gt; ​​and &lt;code&gt;@EnvironmentObject&lt;/code&gt; are supported (without the 💥) from iOS 13.0.&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>redux</category>
      <category>javascript</category>
      <category>react</category>
    </item>
    <item>
      <title>Localized Error Meanings in Swift Practice</title>
      <dc:creator>Vadim Atamanenko</dc:creator>
      <pubDate>Sat, 17 Dec 2022 05:14:25 +0000</pubDate>
      <link>https://dev.to/vadimatamanenko/localized-error-meanings-in-swift-practice-3g4h</link>
      <guid>https://dev.to/vadimatamanenko/localized-error-meanings-in-swift-practice-3g4h</guid>
      <description>&lt;p&gt;How many times have we looked at this code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;do {
  try writeEverythingToDisk()
} catch let error {
  // ???
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;or this one:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;switch result {
case .failure(let error):
  // ???
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and asked themselves the question: &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“How can I extract information from this error?”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The problem is that the error probably contains a lot of information that could help us. But obtaining this information is often not easy.&lt;/p&gt;

&lt;p&gt;To understand the reason for this, let's look at the ways we have at our disposal to attach information to errors.&lt;/p&gt;

&lt;h2&gt;
  
  
  New: LocalizedError
&lt;/h2&gt;

&lt;p&gt;In Swift, we pass errors according to the Error protocol. The LocalizedError protocol inherits it, extending it with some useful properties:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;errorDescription&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;failureReason&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;recoverySuggestion&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Compliance with the &lt;code&gt;LocalizedError&lt;/code&gt; protocol instead of the &lt;code&gt;Error&lt;/code&gt; protocol (and ensuring that these new properties are implemented) allows us to augment our error with a lot of useful information that can be passed at runtime (the NSHipster weblog covers this in &lt;a href="https://nshipster.com/swift-foundation-error-protocols/" rel="noopener noreferrer"&gt;more detail&lt;/a&gt;):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;enum MyError: LocalizedError {
  case badReference

  var errorDescription: String? {
    switch self {
    case .badReference:
      return "The reference was bad."
    }
  }

  var failureReason: String? {
    switch self {
    case .badReference:
      return "Bad Reference"
    }
  }

  var recoverySuggestion: String? {
    switch self {
    case .badReference:
      return "Try using a good one."
    }
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Old: userInfo
&lt;/h2&gt;

&lt;p&gt;The well-known &lt;code&gt;NSError&lt;/code&gt; class contains a property - a &lt;code&gt;userInfo&lt;/code&gt; dictionary, which we can fill with whatever we want. But also, this dictionary contains several predefined keys:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;NSLocalizedDescriptionKey&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;NSLocalizedFailureReasonErrorKey&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;NSLocalizedRecoverySuggestionErrorKey&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You may notice that their names are very similar to the &lt;code&gt;LocalizedError&lt;/code&gt; properties. And, in fact, they play a similar role:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;let info = [ 
  NSLocalizedDescriptionKey:
    "The reference was bad.",
  NSLocalizedFailureReasonErrorKey:
    "Bad Reference",
  NSLocalizedRecoverySuggestionErrorKey:
    "Try using a good one."
]

let badReferenceNSError = NSError(
  domain: "ReferenceDomain", 
  code: 42, 
  userInfo: info
)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It looks like &lt;code&gt;LocalizedError&lt;/code&gt; and &lt;code&gt;NSError&lt;/code&gt; should be basically the same, right? Well, therein lies the main problem.&lt;/p&gt;

&lt;h2&gt;
  
  
  Old meets new
&lt;/h2&gt;

&lt;p&gt;The point is that the &lt;code&gt;NSError&lt;/code&gt; class conforms to the &lt;code&gt;Error&lt;/code&gt; protocol, but not to the &lt;code&gt;LocalizedError&lt;/code&gt; protocol. In other words:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;badReferenceNSError is NSError        //&amp;gt; true
badReferenceNSError is Error          //&amp;gt; true
badReferenceNSError is LocalizedError //&amp;gt; false
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This means that if we try to extract information from any arbitrary error in the usual way, it will only work properly for &lt;code&gt;Error&lt;/code&gt; and &lt;code&gt;LocalizedError&lt;/code&gt;, but for &lt;code&gt;NSError&lt;/code&gt;, only the value of the &lt;code&gt;localizedDescription&lt;/code&gt; property will be reflected:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// The obvious way that doesn’t work:
func log(error: Error) {
  print(error.localizedDescription)
  if let localized = error as? LocalizedError {
    print(localized.failureReason)
    print(localized.recoverySuggestion)
  }
}

log(error: MyError.badReference)
//&amp;gt; The reference was bad.
//&amp;gt; Bad Reference
//&amp;gt; Try using a good one.

log(error: badReferenceNSError)
//&amp;gt; The reference was bad.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is rather annoying, because our &lt;code&gt;NSError&lt;/code&gt; class object is known to contain information about the cause of the failure and a suggestion for correcting the error, registered in its &lt;code&gt;userInfo&lt;/code&gt; dictionary. And this, for some reason, is not shown through the &lt;code&gt;LocalizedError&lt;/code&gt; match.&lt;/p&gt;

&lt;h2&gt;
  
  
  New becomes old
&lt;/h2&gt;

&lt;p&gt;At this point, we can get frustrated by mentally imagining a lot of &lt;code&gt;switch&lt;/code&gt; statements trying to sort by type and by the presence of various properties in the &lt;code&gt;userInfo&lt;/code&gt; dictionary. But don't be afraid! There is an easy solution. It's just not very obvious.&lt;/p&gt;

&lt;p&gt;Note that the &lt;code&gt;NSError&lt;/code&gt; class defines convenience methods for retrieving the localized description, failure reason, and recovery suggestion in the &lt;code&gt;userInfo&lt;/code&gt; property:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;badReferenceNSError.localizedDescription
//&amp;gt; "The reference was bad."

badReferenceNSError.localizedFailureReason
//&amp;gt; "Bad Reference"

badReferenceNSError.localizedRecoverySuggestion
//&amp;gt; "Try using a good one."
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;They are great for handling &lt;code&gt;NSError&lt;/code&gt;, but they don't help us extract those values ​​from &lt;code&gt;LocalizedError&lt;/code&gt;...or is it?&lt;/p&gt;

&lt;p&gt;It turns out that the Swift &lt;code&gt;Error&lt;/code&gt; language protocol is connected by the compiler to the &lt;code&gt;NSError&lt;/code&gt; class. This means we can turn an &lt;code&gt;Error&lt;/code&gt; into an &lt;code&gt;NSError&lt;/code&gt; with a simple cast:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;let bridgedError: NSError
bridgedError = MyError.badReference as NSError
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But what's even more impressive is that when we cast a &lt;code&gt;LocalizedError&lt;/code&gt; this way, the bridge works properly and wires up &lt;code&gt;localizedDescription&lt;/code&gt;, &lt;code&gt;localizedFailureReason&lt;/code&gt;, and &lt;code&gt;localizedRecoverySuggestion&lt;/code&gt;, pointing to the appropriate values!&lt;/p&gt;

&lt;p&gt;So if we want a consistent interface to extract localized information from &lt;code&gt;Error&lt;/code&gt;, &lt;code&gt;LocalizedError&lt;/code&gt;, and &lt;code&gt;NSError&lt;/code&gt;, we just need to cast everything to &lt;code&gt;NSError&lt;/code&gt; without hesitation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;func log(error: Error) {
  let bridge = error as NSError
  print(bridge.localizedDescription)
  print(bridge.localizedFailureReason)
  print(bridge.localizedRecoverySuggestion)
}

log(error: MyError.badReference)
//&amp;gt; The reference was bad.
//&amp;gt; Bad Reference
//&amp;gt; Try using a good one.

log(error: badReferenceNSError)
//&amp;gt; The reference was bad.
//&amp;gt; Bad Reference
//&amp;gt; Try using a good one.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;✌️ &lt;/p&gt;

</description>
      <category>angular</category>
      <category>react</category>
    </item>
    <item>
      <title>Info.plist missing in XCode 13</title>
      <dc:creator>Vadim Atamanenko</dc:creator>
      <pubDate>Sun, 11 Dec 2022 11:15:26 +0000</pubDate>
      <link>https://dev.to/vadimatamanenko/infoplist-missing-in-xcode-13-26f3</link>
      <guid>https://dev.to/vadimatamanenko/infoplist-missing-in-xcode-13-26f3</guid>
      <description>&lt;p&gt;When you create a new SwiftUI project in Xcode 13, you may find that it does not have an Info.plist file. Why is this happening?&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fejo2pnum1xifjnijl5h1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fejo2pnum1xifjnijl5h1.png" alt="Image description" width="357" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Xcode 13 Project Templates
&lt;/h2&gt;

&lt;p&gt;First of all, this change only affects projects created in Xcode 13. If you open a project created in Xcode 12 or earlier with Xcode 13, this will not affect Info.plist.&lt;/p&gt;

&lt;h2&gt;
  
  
  Project Storyboard
&lt;/h2&gt;

&lt;p&gt;Creating a new iOS project using Storyboard in Xcode 13 will also create an Info.plist:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcaeq9q0d6qd2bjaidcx6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcaeq9q0d6qd2bjaidcx6.png" alt="Image description" width="482" height="520"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If we click on &lt;code&gt;info.plist&lt;/code&gt; to see the contents, you'll notice that this file is somewhat unusual:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxhhgeth4zubli2gpncjw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxhhgeth4zubli2gpncjw.png" alt="Image description" width="800" height="271"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It only has some default settings for the &lt;code&gt;Application Scene Manifest&lt;/code&gt; where multi-windows are disabled. But where are the rest of the settings?&lt;/p&gt;

&lt;h2&gt;
  
  
  SwiftUI Project
&lt;/h2&gt;

&lt;p&gt;The change will be more noticeable if you create a new SwiftUI project. You will notice that there will be no Info.plist file in the project navigator (or on disk) at all:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgvhfgp5m4zhqsa7kntmg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgvhfgp5m4zhqsa7kntmg.png" alt="Image description" width="480" height="380"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Also note that the SwiftUI template no longer uses the start screen storyboard.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is going on here?
&lt;/h2&gt;

&lt;p&gt;As far as I know, this was not mentioned at WWDC21 and the only &lt;a href="https://developer.apple.com/documentation/xcode-release-notes/xcode-13-release-notes" rel="noopener noreferrer"&gt;documentation &lt;/a&gt; on this seems to be the Xcode 13 release notes.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Projects based on multiple templates no longer require configuration files such as permissions and &lt;code&gt;Info.plist&lt;/code&gt; files. Set up common fields in the info tab of the target and create parameters in the project editor. These files are added to the project when using additional fields. (68254857)&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The idea seems to be to create a complete &lt;code&gt;Info.plist&lt;/code&gt; for the target at project build time, and create the project's &lt;code&gt;Info.plist&lt;/code&gt; file only for changes you make other than the defaults.&lt;/p&gt;

&lt;h2&gt;
  
  
  Changing information settings
&lt;/h2&gt;

&lt;p&gt;Some Xcode templates, such as the SwiftUI template, do not create an &lt;code&gt;Info.plist&lt;/code&gt; in the source project. You can still make changes using the &lt;code&gt;Info&lt;/code&gt; tab for target settings:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fagv9emrjwb1fw6goee4z.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fagv9emrjwb1fw6goee4z.png" alt="Image description" width="800" height="381"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After the changes are made, Xcode adds an &lt;code&gt;Info.plist&lt;/code&gt; file to the project and it appears in the project navigator. For example, if I add some App Transport Security options in the Info tab:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flkrq77t35n58yiw8hegm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flkrq77t35n58yiw8hegm.png" alt="Image description" width="800" height="115"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Xcode creates an &lt;code&gt;Info.plist&lt;/code&gt; file containing just these App Transport settings:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzsl0wu6bydimywd02q1w.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzsl0wu6bydimywd02q1w.png" alt="Image description" width="800" height="254"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We can then change the setting anywhere, and in theory Xcode keeps the two sets of settings in sync.&lt;/p&gt;

&lt;p&gt;I say theoretically, because in practice problems can arise. For example, if I edit the Info settings in the project navigator, Xcode does not update the settings in the Info tab for the target to reflect the changes I made. I need to close and reopen the project for it to update. Let's hope this is a beta bug that will be fixed before the final release (FB9397345).&lt;/p&gt;

&lt;h2&gt;
  
  
  Build Settings
&lt;/h2&gt;

&lt;p&gt;To add to the confusion, there are also some &lt;code&gt;Info.plist&lt;/code&gt; settings that only show up in the build settings for the target. Basically these are the settings you change on the &lt;code&gt;General&lt;/code&gt; tab for the target, such as supported orientations and launch screen:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffv6hyufzyffj2opol4k9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffv6hyufzyffj2opol4k9.png" alt="Image description" width="800" height="207"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can change these options on the General tab, Info tab, or Build Settings (but they don't appear in the &lt;code&gt;Info.plist&lt;/code&gt; file you see in the project navigator).&lt;/p&gt;

&lt;p&gt;The Packaging section of the build settings allows you to disable Xcode's creation of the &lt;code&gt;Info.plist&lt;/code&gt; file (more on this in a moment):&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwg1rl5d6j8m2ijkr23py.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwg1rl5d6j8m2ijkr23py.png" alt="Image description" width="800" height="177"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Backward compatibility
&lt;/h2&gt;

&lt;p&gt;The Xcode 13 project format is not backward compatible with Xcode 12. If you create a project in Xcode 13, you cannot open it with Xcode 12. Apple mentions this in the release notes:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;New projects created with Xcode 13 use the new version of the project. Using new projects with an older version of Xcode requires changing the project version in the file inspector, as well as manually migrating the configuration options for &lt;code&gt;Info.plist&lt;/code&gt;and the permissions you can now specify in the target's build options. (77344653)&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;To make a project compatible with Xcode 12, change the project format in the Xcode File Inspector:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxw9ei1om5wkspzzc48xb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxw9ei1om5wkspzzc48xb.png" alt="Image description" width="520" height="200"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You also need to manually revert to the non-Xcode generated &lt;code&gt;Info.plist&lt;/code&gt; file, otherwise you will lose your settings when you create the project with Xcode 12. Copying each setting manually from the Info tab is labor intensive. You may find it easier to start with the default &lt;code&gt;Info.plist&lt;/code&gt; created in Xcode 12 and add any changes to it.&lt;/p&gt;

&lt;p&gt;Finally, in Xcode 13, disable the creation of the &lt;code&gt;Info.plist&lt;/code&gt; file in the build settings:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fu9s1x2vin561z8m7ccmz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fu9s1x2vin561z8m7ccmz.png" alt="Image description" width="800" height="202"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>deepseek</category>
    </item>
    <item>
      <title>Use Async / Await in SwiftUI</title>
      <dc:creator>Vadim Atamanenko</dc:creator>
      <pubDate>Mon, 05 Dec 2022 16:33:31 +0000</pubDate>
      <link>https://dev.to/vadimatamanenko/use-async-await-in-swiftui-4kjj</link>
      <guid>https://dev.to/vadimatamanenko/use-async-await-in-swiftui-4kjj</guid>
      <description>&lt;p&gt;Convert your SwiftUI app to take advantage of Swift's new multithreading mechanism and see what's going on underneath the colorful shell.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Software version&lt;/strong&gt;&lt;br&gt;
Swift 5.5, iOS 15, Xcode 13&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Swift 5.5 has a bright new &lt;code&gt;threading framework&lt;/code&gt; to help you write safe code faster. To help everyone get started, Apple provided a bunch of videos and code examples at WWDC 2021. There is a summary of what they cover at the end of this tutorial.&lt;/p&gt;

&lt;p&gt;Twitter has exploded, and the usual actors (actors - this concept will be discussed later in the article) have already published several instructions. This tutorial is similar to the micro version of &lt;a href="https://developer.apple.com/wwdc21/10194" rel="noopener noreferrer"&gt;Swift concurrency: Update a sample app&lt;/a&gt; from WWDC. You'll take small steps to transform a much simpler application to learn how async/await and actors help you write safer code. To help you decipher Xcode error messages and protect you from inevitable future API changes, you'll learn what's going on under the bright surface.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;The note&lt;/strong&gt;&lt;br&gt;
You will need Xcode 13. This tutorial was written using beta 1. If you want to run it on an iOS device, Xcode 13 must be running iOS 15 beta. For your Mac, Big Sur will do. If you have a Mac [partition] running the Monterey beta, you can try running your code there if it doesn't work in Big Sur. You should be comfortable using SwiftUI, Swift, and Xcode to develop iOS apps.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Let's get started
&lt;/h2&gt;

&lt;p&gt;Create a new Xcode project using the SwiftUI interface and name it WaitForIt.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5l5e49evawl23j9hdrvl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5l5e49evawl23j9hdrvl.png" alt="Image description" width="727" height="518"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In &lt;code&gt;ContentView.swift&lt;/code&gt;, replace the body content with this code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;AsyncImage(url: URL(string: "https://files.betamax.raywenderlich.com/attachments/collections/194/e12e2e16-8e69-432c-9956-b0e40eb76660.png")) { image in
  image.resizable()
} placeholder: {
  Color.red
}
.frame(width: 128, height: 128)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In Xcode 13 beta 1 you get this error:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9189gv54ro4m2js1b9hd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9189gv54ro4m2js1b9hd.png" alt="Image description" width="397" height="211"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Do not click&lt;/strong&gt; any of the &lt;strong&gt;Fix **buttons! Go to the landing page and change the **Deployment Info&lt;/strong&gt; from &lt;code&gt;iOS 14.0&lt;/code&gt; to &lt;code&gt;iOS 15.0&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fy0pxuzyye8umjj1w6br6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fy0pxuzyye8umjj1w6br6.png" alt="Image description" width="487" height="106"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Return to &lt;code&gt;ContentView.swift&lt;/code&gt;. If the error message is still present, press &lt;strong&gt;Command-B&lt;/strong&gt; to build the project.&lt;/p&gt;

&lt;p&gt;Launch &lt;strong&gt;Live Preview&lt;/strong&gt; to see the image for the video “SwiftUI vs. UIKit”:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fg5hw84y9y6hdt98ymlt0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fg5hw84y9y6hdt98ymlt0.png" alt="Image description" width="129" height="130"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Okay, this was just a quick check to fix this Xcode crash and also show you the new SwiftUI &lt;code&gt;AsyncImage&lt;/code&gt; view. Okay, right?&lt;/p&gt;

&lt;p&gt;Before you get started on a real WaitForIt application, take a close look at how Swift's new threading fixes problems with the old GCD threading.&lt;/p&gt;

&lt;h2&gt;
  
  
  Old and new multithreading
&lt;/h2&gt;

&lt;p&gt;The old GCD threading has several problems that make it difficult to write applications that use threading safely.&lt;/p&gt;

&lt;p&gt;Multithreading Swift provides the necessary tools to split work into smaller tasks that can run concurrently. This allows tasks to wait for each other to complete and allows you to efficiently manage the overall progress of a task.&lt;/p&gt;

&lt;h2&gt;
  
  
  Pyramid of Doom (Pyramid of Doom)
&lt;/h2&gt;

&lt;p&gt;Swift APIs like URLSession are asynchronous. Methods are automatically dispatched to a background queue and immediately return control to the calling code. The methods take a completion handler and call delegate methods. Finalization or delegation code that accesses UI elements must be sent to the main queue.&lt;/p&gt;

&lt;p&gt;If a completion handler calls another asynchronous function, and that function has a completion handler, it's hard to see the exit in the resulting pyramid of doom. This makes it difficult to check the correctness of the code. For example, this code example from &lt;a href="https://developer.apple.com/wwdc21/10132" rel="noopener noreferrer"&gt;Meet async/await in Swift&lt;/a&gt; at WWDC loads data, creates an image from the data, and then displays a thumbnail of the image. Error handling is special because completion handlers cannot throw errors.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;func fetchThumbnail(
  for id: String,
  completion: @escaping (UIImage?, Error?) -&amp;gt; Void
) {
  let request = thumbnailURLRequest(for: id)
  let task = URLSession.shared
    .dataTask(with: request) { data, response, error in
    if let error = error {
      completion(nil, error)
    } else if (response as? HTTPURLResponse)?.statusCode != 200 {
      completion(nil, FetchError.badID)
    } else {
      guard let image = UIImage(data: data!) else {
        completion(nil, FetchError.badImage)
        return
      }
      image.prepareThumbnail(of: CGSize(width: 40, height: 40)) { thumbnail in
        guard let thumbnail = thumbnail else {
          completion(nil, FetchError.badImage)
          return
        }
        completion(thumbnail, nil)
      }
    }
  }
  task.resume()
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The sequence of operations is much easier to see with async/await, and you can take advantage of Swift's robust error handling mechanism:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;func fetchThumbnail(for id: String) async throws -&amp;gt; UIImage {
  let request = thumbnailURLRequest(for: id)
  let (data, response) = try await URLSession.shared.data(for: request)
  guard (response as? HTTPURLResponse)?.statusCode == 200 else {
    throw FetchError.badID
  }
  let maybeImage = UIImage(data: data)
  guard let thumbnail = await maybeImage?.thumbnail else {
    throw FetchError.badImage
  }
  return thumbnail
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Data Races
&lt;/h2&gt;

&lt;p&gt;When multiple tasks can read or write object data, data races are possible. A data race occurs when one task pauses while another task writes and exits, then the sleeping task resumes and overwrites what was written by the previous task. This creates inconsistent results.&lt;/p&gt;

&lt;p&gt;In an app using legacy multithreading, Xcode can detect data races if you enable the &lt;code&gt;Thread Sanitizer&lt;/code&gt; runtime diagnostic in your app's &lt;code&gt;Run&lt;/code&gt;scheme. You can then implement a sequential queue to prevent concurrent access.&lt;/p&gt;

&lt;p&gt;Swift's new multithreading model provides the Actor protocol to prevent concurrent access to object data. Subjects also allow you to structure your application into code that runs on the main thread and code that runs on background threads, so the compiler can help you prevent concurrent access.&lt;/p&gt;

&lt;h2&gt;
  
  
  Thread Explosion/Starvation (stream explosion/starvation)
&lt;/h2&gt;

&lt;p&gt;In GCD, the basic unit of work is the &lt;code&gt;thread&lt;/code&gt;. If your code queues a lot of read/write tasks, most of them should sleep while they wait. This means that their threads are blocked, so the system creates more threads for the next tasks. If each task also puts a completion handler on a different queue, this creates even more threads. Each blocked thread holds the stack and kernel data structures so that it can be resumed. A blocked thread may be holding resources that another thread needs, so the thread is blocked.&lt;/p&gt;

&lt;p&gt;This is an explosion of threads: the system is overloaded with many times more threads than there are cores to process them. The scheduler has to allocate time to hundreds of threads, which results in a lot of context switches. All this slows down your application and may even starve some threads so they never run.&lt;/p&gt;

&lt;h2&gt;
  
  
  Tasks and continuations
&lt;/h2&gt;

&lt;p&gt;In Swift multithreading, the basic unit of work is the task. A task executes tasks sequentially. To achieve multithreading, a task can create child tasks. Or you can create tasks in a task group.&lt;/p&gt;

&lt;p&gt;The system knows that these tasks are related, so it can manage due dates, priority, and cancellation flags for all tasks in a task tree or group. This makes it easier to check for and respond to cancellation status, thus avoiding issue leaks. If it is important to respond immediately to cancellation, you can write a function with a cancellation handler.&lt;/p&gt;

&lt;p&gt;If a task is suspended, it releases its thread and saves its state in the &lt;code&gt;continuation&lt;/code&gt;. Threads switch between continuations instead of context switching.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhnt6ib2748fhbdkp005y.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhnt6ib2748fhbdkp005y.png" alt="Image description" width="588" height="224"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Threads switch between continuations.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;The note&lt;/strong&gt;&lt;br&gt;
This image is taken from the WWDC session of &lt;a href="https://developer.apple.com/wwdc21/10254" rel="noopener noreferrer"&gt;Swift concurrency: Behind the scenes&lt;/a&gt;&lt;br&gt;
The &lt;code&gt;await&lt;/code&gt;keyword marks the point of suspension, and the &lt;code&gt;async frame&lt;/code&gt; on the heap stores the information it needs when it resumes.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Ideally, the number of threads never exceeds the number of cores. There is a shared pool of threads and a runtime contract whereby each thread will do its job. Your code maintains this contract by using await, actors, and task groups to make dependencies visible to the compiler.&lt;/p&gt;

&lt;h2&gt;
  
  
  Joke Service
&lt;/h2&gt;

&lt;p&gt;Enough theory! It's time to convert simple loading to using async/await.&lt;/p&gt;

&lt;p&gt;The starter folder contains &lt;code&gt;JokeService.swift&lt;/code&gt;. Add this file to WaitForIt.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;JokeService&lt;/code&gt; is an &lt;code&gt;ObservableObject&lt;/code&gt;that sends a request to an API that returns a random &lt;a href="https://en.wikipedia.org/wiki/Chuck_Norris" rel="noopener noreferrer"&gt;Chuck Norris&lt;/a&gt; joke. I adapted this code from the sample application in &lt;a href="https://www.raywenderlich.com/books/combine-asynchronous-programming-with-swift" rel="noopener noreferrer"&gt;Combine: Asynchronous Programming with Swift&lt;/a&gt;. The request element specifies the category of developers, so all the jokes have a technical flavor. Warning: Some of these jokes are a little cruel.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;JokeService&lt;/code&gt;publishes the joke and its &lt;code&gt;isFetching&lt;/code&gt;status. Its &lt;code&gt;fetchJoke()&lt;/code&gt; method uses the standard &lt;code&gt;URLSession.shared.dataTask&lt;/code&gt; with a completion handler. If something goes wrong, it prints an error message with either a &lt;code&gt;dataTask&lt;/code&gt;error or an "Unknown error". In the case of "Unknown error", it does not provide information on whether the problem was in the data or in the decoder.&lt;/p&gt;

&lt;h2&gt;
  
  
  Minimal error handling
&lt;/h2&gt;

&lt;p&gt;Reliable error handling is one of the main reasons for using async/await. The data task completion handler cannot throw errors, so if it calls a generating function such as &lt;code&gt;JSONDecoder().decode(_:from:)&lt;/code&gt;, it must handle any errors that are thrown.&lt;/p&gt;

&lt;p&gt;Usually they take the easy way out and just ignore the error. This is what the starter file does:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;if let decodedResponse = try? JSONDecoder().decode(Joke.self, from: data)&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Previous versions of Xcode offer this as a fix if you just write try and don't wrap it in do/catch. This means: just assign &lt;code&gt;nil&lt;/code&gt;if the function throws an error.&lt;/p&gt;

&lt;p&gt;Delete ? to see what's going on:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxxune11cytvuazg6qntu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxxune11cytvuazg6qntu.png" alt="Image description" width="677" height="160"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Xcode is now taking a tougher stance: no more helpful suggestions for simple fixes.&lt;/p&gt;

&lt;p&gt;But ? still works here so bring it back.&lt;/p&gt;

&lt;h2&gt;
  
  
  Show me a joke!
&lt;/h2&gt;

&lt;p&gt;To get the joke, open &lt;code&gt;ContentView.swift&lt;/code&gt; and replace the content of the &lt;code&gt;ContentView&lt;/code&gt;with this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@StateObject var jokeService = JokeService()

var body: some View {
  ZStack {
    Text(jokeService.joke)
      .multilineTextAlignment(.center)
      .padding(.horizontal)
    VStack {
      Spacer()
      Button { jokeService.fetchJoke() } label: {
        Text("Fetch a joke")
          .padding(.bottom)
          .opacity(jokeService.isFetching ? 0 : 1)
          .overlay {
            if jokeService.isFetching { ProgressView() }
          }
      }
    }
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Launch &lt;strong&gt;Live Preview&lt;/strong&gt; and click the button. This has a nice effect with opacity and &lt;code&gt;ProgressView()&lt;/code&gt; to indicate that a fetch is in progress.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fj9nwwtfugvaa47uar2gl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fj9nwwtfugvaa47uar2gl.png" alt="Image description" width="319" height="324"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Concurrent Binding (parallel binding)
&lt;/h2&gt;

&lt;p&gt;Okay, the old way works, so now you're going to convert it to the new one.&lt;/p&gt;

&lt;p&gt;Comment out &lt;code&gt;URLSession&lt;/code&gt; up to and including &lt;code&gt;.resume()&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Add this code below &lt;code&gt;isFetching = true&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;async let (data, response) = URLSession.shared.data(from: url)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The new &lt;code&gt;data(from:) URLSession&lt;/code&gt; method is asynchronous, so you use &lt;code&gt;async let&lt;/code&gt; to assign the return value to the &lt;code&gt;(data, response)&lt;/code&gt; tuple. These are the same &lt;code&gt;data&lt;/code&gt;and &lt;code&gt;response&lt;/code&gt;that &lt;code&gt;dataTask(with:)&lt;/code&gt; provides to its completion handler, but &lt;code&gt;data(from:)&lt;/code&gt; returns them directly to the calling function.&lt;/p&gt;

&lt;p&gt;Where is the error that &lt;code&gt;dataTask(with:)&lt;/code&gt; throws? You'll find out soon - stay tuned!&lt;/p&gt;

&lt;p&gt;The following errors and suggested fixes appear:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fg88r5k79knibqf3ca18l.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fg88r5k79knibqf3ca18l.png" alt="Image description" width="528" height="92"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The errors are similar: you can't call an async function within a synchronous function. You must tell the compiler that &lt;code&gt;fetchJoke()&lt;/code&gt; is asynchronous.&lt;/p&gt;

&lt;p&gt;Both fixes are the same, so click on either one. This gives you:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;func fetchJoke() async {
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Like &lt;code&gt;throws&lt;/code&gt;, the &lt;code&gt;async&lt;/code&gt;keyword appears between the closing brace and the opening curly brace. You will interrupt &lt;code&gt;throws&lt;/code&gt;again soon.&lt;/p&gt;

&lt;p&gt;Back to &lt;code&gt;async let:&lt;/code&gt; this is one way to assign the result of &lt;code&gt;data(from:)&lt;/code&gt; to the tuple &lt;code&gt;(data, response)&lt;/code&gt;. This is called &lt;strong&gt;concurrent binding&lt;/strong&gt; because the parent task continues executing after the child task is created to run &lt;code&gt;data(from:)&lt;/code&gt; on a different thread. The child task inherits the priority and local values ​​of the parent task. When the parent task needs to use &lt;code&gt;data&lt;/code&gt;or &lt;code&gt;response&lt;/code&gt;, it suspends itself (releases its thread) until the child task completes.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdfcgf9lt0uv9zrdsrs56.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdfcgf9lt0uv9zrdsrs56.png" alt="Image description" width="650" height="131"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Parent and child tasks run at the same time.&lt;/p&gt;

&lt;h2&gt;
  
  
  async wait
&lt;/h2&gt;

&lt;p&gt;The verb for &lt;code&gt;async&lt;/code&gt;is &lt;code&gt;await&lt;/code&gt;, just like the verb for &lt;code&gt;throws&lt;/code&gt;is &lt;code&gt;try&lt;/code&gt;. You try the throwing function and wait for the async function.&lt;/p&gt;

&lt;p&gt;Add this line of code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;await (data, response)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1rzk4vidqm61t042ht0f.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1rzk4vidqm61t042ht0f.png" alt="Image description" width="630" height="167"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And there's a missing error here that &lt;code&gt;dataTask(with:)&lt;/code&gt; passes to its completion handler: &lt;code&gt;data(from:)&lt;/code&gt; throws it. So, you should use &lt;code&gt;try await&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;try! await (data, response)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;The note&lt;/strong&gt;&lt;br&gt;
The keywords must be in that order, *&lt;em&gt;not *&lt;/em&gt;&lt;code&gt;await try&lt;/code&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;You're not really going to use this code, so don't bother catching bugs. It's just a chance to see what's going on.&lt;/p&gt;

&lt;p&gt;What is happening is amazing:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvicbnkbpw6crhwhkl5mu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvicbnkbpw6crhwhkl5mu.png" alt="Image description" width="361" height="92"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;An immutable value can only be initialized once.&lt;/p&gt;

&lt;p&gt;This is surprising because the &lt;a href="https://developer.apple.com/wwdc21/10134" rel="noopener noreferrer"&gt;Explore structured concurrency in Swift&lt;/a&gt; video says, “And don't worry. Reading the result value again will not recalculate its value."&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;The note&lt;/strong&gt;&lt;br&gt;
Looks like it's a tuple error. You can wait for data or a response, but not both.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Go ahead and accept the suggested fix to change &lt;code&gt;let&lt;/code&gt;to &lt;code&gt;var&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6defovon7i28zvpgim4l.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6defovon7i28zvpgim4l.png" alt="Image description" width="468" height="45"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Hm! Think back to your early days learning Swift, when Xcode kept saying, "You can't do that here." Maybe it's a beta bug. It doesn't matter in this case, because between calling &lt;code&gt;data(from:)&lt;/code&gt; and processing what it returns, there is no other code to execute.&lt;/p&gt;

&lt;h2&gt;
  
  
  Sequential Binding (serial binding)
&lt;/h2&gt;

&lt;p&gt;Instead, you will use another binding: &lt;strong&gt;sequential binding&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Replace two lines with this piece of code:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;let (data, response) = try? await URLSession.shared.data(from: url)&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Unlike &lt;code&gt;async let&lt;/code&gt;, calling &lt;code&gt;data(from:)&lt;/code&gt; in this way does not create a child task. It is executed sequentially as a job in the &lt;code&gt;fetchJoke()&lt;/code&gt; task. While it waits for a response from the server, this job suspends itself, releasing the task thread.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgu0rkvgqfz3ypb66ocf4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgu0rkvgqfz3ypb66ocf4.png" alt="Image description" width="650" height="65"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;data(from:)&lt;/code&gt; tasks are suspended.&lt;/p&gt;

&lt;p&gt;But there's a problem:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6p2oed9p3xj3j9oklsny.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6p2oed9p3xj3j9oklsny.png" alt="Image description" width="673" height="44"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Xcode refuses to understand &lt;code&gt;try?&lt;/code&gt; here.&lt;/p&gt;

&lt;p&gt;You'll try the lazy way, but this time it won't work in Xcode, even if you use nil union to specify a nil tuple:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;let (data, response) = 
  try? await URLSession.shared.data(from: url) ?? (nil, nil)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No, you have to do the right thing. First, remove the ? and ?? (nil, nil):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;let (data, response) = try await URLSession.shared.data(from: url)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Error handling options
&lt;/h2&gt;

&lt;p&gt;You have two options for handling errors caused by &lt;code&gt;data(from:)&lt;/code&gt;. The first is to bite the bullet and deal with it right away with do/catch:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;do {
  let (data, response) = try await URLSession.shared.data(from: url)
} catch {
  print(error.localizedDescription)
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;An easier(?) option is to make &lt;code&gt;fetchJoke()&lt;/code&gt; throw:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;func fetchJoke() async throws {
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These keywords must be in the order listed - &lt;code&gt;throws async&lt;/code&gt; does not work:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvzquvp8sex8arbhowfr7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvzquvp8sex8arbhowfr7.png" alt="Image description" width="614" height="69"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;async&lt;/code&gt;must come before &lt;code&gt;throws&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Now &lt;code&gt;fetchJoke()&lt;/code&gt; simply propagates the error to everyone who calls &lt;code&gt;fetchJoke()&lt;/code&gt;. This is the button in the ContentView, where Xcode is already complaining about &lt;code&gt;fetchJoke()&lt;/code&gt; being asynchronous:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fiqrenw0z3sfd5rw6kpat.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fiqrenw0z3sfd5rw6kpat.png" alt="Image description" width="559" height="84"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;fetchJoke()&lt;/code&gt; is &lt;code&gt;async&lt;/code&gt;and returns: Do something!&lt;/p&gt;

&lt;p&gt;So what's now? You cannot mark anything in a &lt;code&gt;ContentView&lt;/code&gt;as &lt;code&gt;async&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Create an unstructured task
&lt;/h2&gt;

&lt;p&gt;Luckily, you can create an asynchronous task in a button action. Replace Button { jokeService.fetchJoke() } label: { with this piece of code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Button {
  async {
    try? await jokeService.fetchJoke()
  }
} label: {
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You create an asynchronous task with &lt;code&gt;async { }&lt;/code&gt;. Since it is asynchronous, you need to wait for it to complete. Because it &lt;code&gt;throws&lt;/code&gt;, you should try to catch any errors. Xcode allows you to use &lt;code&gt;try?&lt;/code&gt; here, or you can write a do/catch statement.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;The note&lt;/strong&gt;&lt;br&gt;
The syntax for creating a task will change to &lt;code&gt;Task { ... }&lt;/code&gt; in a future beta release.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This is an &lt;strong&gt;unstructured task&lt;/strong&gt; because it is not part of the &lt;strong&gt;task tree&lt;/strong&gt;. The &lt;code&gt;async let&lt;/code&gt; task that you created in &lt;code&gt;fetchJokes()&lt;/code&gt; is a &lt;strong&gt;child task&lt;/strong&gt; of the task that &lt;code&gt;fetchJokes()&lt;/code&gt; runs on. A child task is bound to the scope of its parent task: the fetchJokes() task cannot complete until its child tasks have completed.&lt;/p&gt;

&lt;p&gt;An unstructured task inherits the actor, priority, and local values ​​of its origin, but is not limited in scope. Canceling the original task does not signal an unstructured task, and the original task can be completed even if the raw task is not completed.&lt;/p&gt;

&lt;p&gt;Creating an unstructured task in a non-async context looks just like &lt;code&gt;DispatchQueue.global().async&lt;/code&gt;, only with less input. But there is a big difference: it runs on the &lt;code&gt;MainActor&lt;/code&gt;thread with &lt;code&gt;userInteractive&lt;/code&gt;priority when the main thread is not blocked.&lt;/p&gt;

&lt;p&gt;You can specify a lower priority with &lt;code&gt;asyncDetached&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftnwtst9s7lk0gkgn4qx1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftnwtst9s7lk0gkgn4qx1.png" alt="Image description" width="323" height="151"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Specify a priority for an individual task.&lt;/p&gt;

&lt;p&gt;But it will still run on the main thread. More on this later.&lt;/p&gt;

&lt;h2&gt;
  
  
  Joke decoding
&lt;/h2&gt;

&lt;p&gt;Return to &lt;code&gt;JokeService.swift&lt;/code&gt; to finish writing &lt;code&gt;fetchJoke()&lt;/code&gt;. If you thought throwing was the easier option, let's see what you think after this section.&lt;/p&gt;

&lt;p&gt;Since &lt;code&gt;fetchJoke()&lt;/code&gt; throws, it passes on any error thrown by &lt;code&gt;data(from:)&lt;/code&gt; to the calling function. You can also take advantage of this mechanism and throw other errors that may occur.&lt;/p&gt;

&lt;p&gt;Errors thrown by the calling function must comply with the &lt;code&gt;Error&lt;/code&gt;protocol, so add this code above the &lt;code&gt;JokeService&lt;/code&gt;extension:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;enum DownloadError: Error {
  case statusNotOk
  case decoderError
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You are creating an enumeration of the possible errors that &lt;code&gt;fetchJoke()&lt;/code&gt; might throw.&lt;/p&gt;

&lt;p&gt;Then add this piece of code to &lt;code&gt;fetchJoke()&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;guard 
  let httpResponse = response as? HTTPURLResponse,
  httpResponse.statusCode == 200   // 1
else {
  throw DownloadError.statusNotOk
}
guard let decodedResponse = try? JSONDecoder()
  .decode(Joke.self, from: data) // 2
else { throw DownloadError.decoderError }
joke = decodedResponse.value   // 3
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Using &lt;code&gt;guard&lt;/code&gt;allows you to pass your specific errors to the calling function.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;You check the response status code and throw &lt;code&gt;statusNotOk&lt;/code&gt;if it's not 200.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;You decode the response and throw a &lt;code&gt;decoderError&lt;/code&gt;if something goes wrong.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;You assign the decoded &lt;code&gt;joke&lt;/code&gt;value.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;The note&lt;/strong&gt;&lt;br&gt;
You always have the option of catching an error, including those caused by &lt;code&gt;data(from:)&lt;/code&gt;, instead of throwing one.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Now where to set &lt;code&gt;isFetching&lt;/code&gt;to &lt;code&gt;false&lt;/code&gt;? This &lt;code&gt;Published&lt;/code&gt;value controls the button's &lt;code&gt;ProgressView&lt;/code&gt;, so you want to set it even if &lt;code&gt;fetchJoke()&lt;/code&gt;throws an error. Throwing an error causes &lt;code&gt;fetchJokes()&lt;/code&gt; to exit, so you still need to set &lt;code&gt;isFetching&lt;/code&gt;in the defer statement before any possible early exit.&lt;/p&gt;

&lt;p&gt;Add this line right below &lt;code&gt;isFetching = true;&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;defer { isFetching = false }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  MainActor
&lt;/h2&gt;

&lt;p&gt;If Xcode has tweaked you a lot, you might feel a little uncomfortable. &lt;code&gt;Published&lt;/code&gt;values ​​update SwiftUI views, so you can't set &lt;code&gt;Published&lt;/code&gt;values ​​from a background thread. To set &lt;code&gt;Published&lt;/code&gt;to &lt;code&gt;isFetching&lt;/code&gt;and &lt;code&gt;joke&lt;/code&gt;, a &lt;code&gt;dataTask(with:)&lt;/code&gt; completion handler is dispatched to the main queue. But your new code doesn't bother to do that. Will you get main thread errors when you run the application?&lt;/p&gt;

&lt;p&gt;Try it. Build and run in the simulator. No, there are no mainstream errors. Why not?&lt;/p&gt;

&lt;p&gt;Because you used &lt;code&gt;async { }&lt;/code&gt; to create the &lt;code&gt;fetchJoke()&lt;/code&gt; task in the button action, it's already running on the &lt;code&gt;MainActor&lt;/code&gt;thread with UI priority.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Actor&lt;/code&gt; is a Swift multithreading mechanism that allows you to make an object thread-safe (thread-safe). Like &lt;code&gt;Class&lt;/code&gt;, it is a named reference type. Its synchronization mechanism isolates its shared mutable state and does not guarantee concurrent access to that state.&lt;/p&gt;

&lt;p&gt;MainActor is a special Actor that represents the main thread. You can think of this as just using &lt;code&gt;DispatchQueue.main&lt;/code&gt;. All SwiftUI views run on the &lt;code&gt;MainActor&lt;/code&gt;thread, just like the flat task you created.&lt;/p&gt;

&lt;p&gt;To see this, place a breakpoint anywhere in &lt;code&gt;fetchJoke()&lt;/code&gt;. Make a build and run, then click the button.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxphjahs7dhouss5c3r2k.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxphjahs7dhouss5c3r2k.png" alt="Image description" width="553" height="41"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;fetchJoke()&lt;/code&gt;runs on the main thread.&lt;/p&gt;

&lt;p&gt;Yes, &lt;code&gt;fetchJoke()&lt;/code&gt; runs on the main thread.&lt;/p&gt;

&lt;p&gt;What if you lower the priority? In &lt;strong&gt;ContentView.swift&lt;/strong&gt; in button action change &lt;code&gt;async {&lt;/code&gt; to this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;asyncDetached(priority: .default) {
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;The note&lt;/strong&gt;&lt;br&gt;
The syntax for this parameter will change to &lt;code&gt;Task.detached&lt;/code&gt; in a future beta release.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Build and run. Click on the button:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwl0ixmsa6w7r9n06jqai.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwl0ixmsa6w7r9n06jqai.png" alt="Image description" width="553" height="41"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;fetchJoke()&lt;/code&gt; is still running on the main thread.&lt;/p&gt;

&lt;p&gt;You lowered the priority to the default, but this does not move the task to the background queue. The task is still running on the main thread!&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;The note&lt;/strong&gt;&lt;br&gt;
It looks like it's a coincidence. The video &lt;a href="https://developer.apple.com/wwdc21/10134" rel="noopener noreferrer"&gt;Explore structured concurrency in Swift&lt;/a&gt; says that a detached task doesn't inherit anything from its source, so it shouldn't inherit from the MainActor thread. A future beta release of Xcode may provide this.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Change the code back to &lt;code&gt;async {&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;To move asynchronous work from the main thread, you need to create an &lt;code&gt;actor&lt;/code&gt;that is not &lt;code&gt;MainActor&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Actor
&lt;/h2&gt;

&lt;p&gt;Actors allow you to structure your application into actors on background threads and actors on the main thread, just like you now create a model, view and view model files. The code in actor (lowercase, not MainActor) is running on a background thread. So you just need to move the async part of fetchJoke() to a separate actor.&lt;/p&gt;

&lt;p&gt;In &lt;code&gt;JokeService.swift&lt;/code&gt;, remove the breakpoint and add this piece of code above the &lt;code&gt;JokeService&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;private actor JokeServiceStore {
  private var loadedJoke = Joke(value: "")

  func load() async throws -&amp;gt; Joke {
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You create an &lt;code&gt;actor&lt;/code&gt;with a &lt;code&gt;Joke&lt;/code&gt;variable and initialize it to an empty string, then write a &lt;code&gt;load()&lt;/code&gt; stub where you move your loading code. This method resets &lt;code&gt;loadedJoke&lt;/code&gt;and also returns &lt;code&gt;Joke&lt;/code&gt;, so you don't need the Joke property for this simple example, but you probably need it for more complex data.&lt;/p&gt;

&lt;p&gt;Then create a &lt;code&gt;JokeServiceStore&lt;/code&gt;object in the &lt;code&gt;JokeService&lt;/code&gt;(in a class, not an extension):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;private let store = JokeServiceStore()
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now move the &lt;code&gt;url&lt;/code&gt;code from &lt;code&gt;JokeService&lt;/code&gt;to &lt;code&gt;JokeServiceStore&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;private var url: URL {
  urlComponents.url!
}

private var urlComponents: URLComponents {
  var components = URLComponents()
  components.scheme = "https"
  components.host = "api.chucknorris.io"
  components.path = "/jokes/random"
  components.setQueryItems(with: ["category": "dev"])
  return components
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then move the loading code from &lt;code&gt;fetchJoke()&lt;/code&gt; to &lt;code&gt;load()&lt;/code&gt; leaving only two &lt;code&gt;isFetching&lt;/code&gt;lines in &lt;code&gt;fetchJoke()&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// move this code from fetchJoke() to load()
let (data, response) = try await URLSession.shared.data(from: url)
guard
  let httpResponse = response as? HTTPURLResponse,
  httpResponse.statusCode == 200
else {
  throw DownloadError.statusNotOk
}
guard let decodedResponse = try? JSONDecoder().decode(Joke.self, from: data)
else { throw DownloadError.decoderError }
joke = decodedResponse.value
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;JokeServiceStore&lt;/code&gt;has a &lt;code&gt;Joke&lt;/code&gt;property, not a &lt;code&gt;String&lt;/code&gt;property, so replace the last line with the following code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;loadedJoke = decodedResponse
return loadedJoke
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Instead of retrieving just the value from the &lt;code&gt;decodedResponse&lt;/code&gt;, you set the &lt;code&gt;Joke&lt;/code&gt;property and also return that &lt;code&gt;Joke&lt;/code&gt;instance.&lt;/p&gt;

&lt;p&gt;Now call &lt;code&gt;load()&lt;/code&gt; in &lt;code&gt;fetchJoke()&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;let loadedJoke = try await store.load()
joke = loadedJoke.value
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Build and run.&lt;/p&gt;

&lt;p&gt;A joke appears, but you have purple warnings:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F22kpb80lsn8hl80k09jf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F22kpb80lsn8hl80k09jf.png" alt="Image description" width="800" height="139"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Posting changes from background threads is not allowed.&lt;/p&gt;

&lt;p&gt;Add a breakpoint inside &lt;code&gt;load()&lt;/code&gt; and in &lt;code&gt;fetchJoke()&lt;/code&gt; in &lt;code&gt;isFetching = true&lt;/code&gt;, &lt;code&gt;let loadedJoke = ...&lt;/code&gt; and &lt;code&gt;joke = loadedJoke.value;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqe1surv4diwryhmynvxt.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqe1surv4diwryhmynvxt.png" alt="Image description" width="800" height="532"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Setting breakpoints.&lt;/p&gt;

&lt;p&gt;Click the button again, then watch the threads by clicking &lt;strong&gt;Continue program execution&lt;/strong&gt; after each dot:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fus2hyes1kr7a2ipwrrkc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fus2hyes1kr7a2ipwrrkc.png" alt="Image description" width="650" height="219"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;fetchJoke()&lt;/code&gt; runs on the main thread but goes to a background thread.&lt;/p&gt;

&lt;p&gt;The first two lines of &lt;code&gt;fetchJoke()&lt;/code&gt; are executed on the main thread because view is calling it. The &lt;code&gt;load()&lt;/code&gt; is then run on a background thread, as it should be. But when execution returns to &lt;code&gt;fetchJoke()&lt;/code&gt; it is still on a background thread. You need to do something to make it run on the main thread.&lt;/p&gt;

&lt;h2&gt;
  
  
  @MainActor
&lt;/h2&gt;

&lt;p&gt;The code that sets the &lt;code&gt;Published&lt;/code&gt;value must run on the &lt;code&gt;MainActor&lt;/code&gt;thread. When &lt;code&gt;fetchJoke()&lt;/code&gt; did all the work and you called it from a Button in an unstructured task, &lt;code&gt;fetchJoke()&lt;/code&gt; inherited &lt;code&gt;MainActor&lt;/code&gt;from &lt;code&gt;Button&lt;/code&gt;and all of its code was running on the &lt;code&gt;MainActor&lt;/code&gt;thread.&lt;/p&gt;

&lt;p&gt;Now &lt;code&gt;fetchJoke()&lt;/code&gt; calls &lt;code&gt;load()&lt;/code&gt; which runs on a background thread. &lt;code&gt;fetchJoke()&lt;/code&gt;still runs on the main thread, but when &lt;code&gt;load()&lt;/code&gt; completes, &lt;code&gt;fetchJoke()&lt;/code&gt; continues to run on the background thread.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;fetchJoke()&lt;/code&gt; should not rely on &lt;code&gt;MainActor&lt;/code&gt;being inherited from &lt;code&gt;Button&lt;/code&gt;. You can mark a class or function with the &lt;code&gt;@MainActor&lt;/code&gt; attribute to indicate that it should run on the &lt;code&gt;MainActor&lt;/code&gt;thread.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The note&lt;/strong&gt;&lt;br&gt;
If you mark a class as &lt;code&gt;@MainActor&lt;/code&gt;, any calls from outside &lt;code&gt;MainActor&lt;/code&gt;must be &lt;code&gt;await&lt;/code&gt;, even if it's a method call that exits immediately. A method that does not refer to any mutable state may drop the &lt;code&gt;MainActor&lt;/code&gt;with the &lt;code&gt;nonisolated&lt;/code&gt;keyword.&lt;/p&gt;

&lt;p&gt;Add this line above &lt;code&gt;func fetchJoke() throws {&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@MainActor
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Compile and run again and hit breakpoints:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fx1d1ilocw6l24ruy5pgm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fx1d1ilocw6l24ruy5pgm.png" alt="Image description" width="800" height="59"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;fetchJoke()&lt;/code&gt;runs on the main thread after &lt;code&gt;load()&lt;/code&gt; completes.&lt;/p&gt;

&lt;p&gt;The first three points are the same as before, but now &lt;code&gt;fetchJoke()&lt;/code&gt;runs on the main thread after &lt;code&gt;load()&lt;/code&gt; completes.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F78bagrgujys566ux19ox.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F78bagrgujys566ux19ox.png" alt="Image description" width="650" height="141"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When &lt;code&gt;fetchJoke()&lt;/code&gt; calls &lt;code&gt;load()&lt;/code&gt; , it pauses, freeing up the main thread for UI tasks. When the download completes, &lt;code&gt;fetchJoke()&lt;/code&gt; runs again on the main thread, where &lt;code&gt;Published&lt;/code&gt;is allowed to be set.&lt;/p&gt;

&lt;p&gt;Your work is done here! Try converting your own SwiftUI projects: take it slow, make small changes, and try to keep the app buildable after each change.&lt;/p&gt;

&lt;h2&gt;
  
  
  Optional: Asynchronous View Modifiers
&lt;/h2&gt;

&lt;p&gt;SwiftUI now has (at least) two view modifiers that expect their action to call an async function.&lt;/p&gt;

&lt;p&gt;Create a new SwiftUI View file named &lt;code&gt;RefreshableView.swift&lt;/code&gt; and replace the contents of RefreshableView with the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@StateObject var jokeService = JokeService()

var body: some View {
  List {
    Text("Chuck Norris Joke")
      .font(.largeTitle)
      .listRowSeparator(.hidden)
    Text(jokeService.joke)
      .multilineTextAlignment(.center)
      .lineLimit(nil)
      .lineSpacing(5.0)
      .padding()
      .font(.title)
  }
  .task {
    try? await jokeService.fetchJoke()
  }
  .refreshable {
    try? await jokeService.fetchJoke()
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;&lt;p&gt;This view is a &lt;code&gt;List&lt;/code&gt;because &lt;code&gt;refreshable(action:)&lt;/code&gt; only works on scrollable views.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The task modifier performs its action when the view appears. The type of its action parameter is &lt;code&gt;action - @escaping() async -&amp;gt; Void&lt;/code&gt;. It creates a task to run the action so you don't need it.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The type of the &lt;code&gt;action&lt;/code&gt;parameter of the &lt;code&gt;refreshable&lt;/code&gt;modifier is the same. It must be asynchronous. When applied to a scrollable view, the user can drag down to refresh its content, and it displays a refresh indicator until the asynchronous task completes.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Launch &lt;strong&gt;Live Preview&lt;/strong&gt;. The joke comes up:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvq1rcgq3inzik5tuxclt.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvq1rcgq3inzik5tuxclt.png" alt="Image description" width="264" height="294"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The joke appears when the view is loaded.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;The note&lt;/strong&gt;&lt;br&gt;
It's actually an O(N) complexity algorithm.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Pull down to get another joke. You may need to pull down quite far.&lt;/p&gt;

&lt;p&gt;If you want to run this version in the simulator or device, open &lt;code&gt;WaitForItApp.swift&lt;/code&gt; and change &lt;code&gt;ContentView()&lt;/code&gt; to &lt;code&gt;RefreshableView()&lt;/code&gt; in the &lt;code&gt;WindowGroup&lt;/code&gt;closure.&lt;/p&gt;

&lt;p&gt;In this tutorial, you converted a simple SwiftUI app from the old GCD threading implementation to the new Swift threading implementation using async/await, unstructured task, actor, and @MainActor.&lt;/p&gt;

</description>
      <category>rust</category>
      <category>discuss</category>
    </item>
    <item>
      <title>24 Quick Tips for Xcode</title>
      <dc:creator>Vadim Atamanenko</dc:creator>
      <pubDate>Sun, 27 Nov 2022 10:46:14 +0000</pubDate>
      <link>https://dev.to/vadimatamanenko/24-quick-tips-for-xcode-3hje</link>
      <guid>https://dev.to/vadimatamanenko/24-quick-tips-for-xcode-3hje</guid>
      <description>&lt;p&gt;&lt;strong&gt;XCode&lt;/strong&gt; is a huge program, and if you can even use a couple of tricks to make your work more efficient, you can save a few hours every week. In this article, I want to introduce you to 24 Xcode tips that will help you code faster, create better tests, and navigate large projects more efficiently—I'm sure there's something for everyone!&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Generation of class initializers
&lt;/h2&gt;

&lt;p&gt;Swift can synthesize memberwise initializers for structures, but not for classes. Luckily, XCode can generate code for us: select your class name, then go to the Xcode menu and choose &lt;code&gt;Refactor&lt;/code&gt;&amp;gt; &lt;code&gt;Generate Memberwise Initializer&lt;/code&gt;. Ready!&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Redefining the environment
&lt;/h2&gt;

&lt;p&gt;When building software, it's important to make sure your application works for everyone. A great way to do this is to use XCode's Environment Overrides panel, which allows you to configure dynamic type size, accessibility options, and appearance in one place.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Choice of code blocks
&lt;/h2&gt;

&lt;p&gt;You probably already know that you can click after any opening &lt;code&gt;{&lt;/code&gt; or closing &lt;code&gt;}&lt;/code&gt; brace to have XCode highlight the corresponding brace, but another good tip is that you can double-click on a brace to select the entire block of code, which it contains.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Checking our spelling
&lt;/h2&gt;

&lt;p&gt;XCode can check spelling and even understands that camelCaseNames should be treated as separate words. Go to the XCode menu and select &lt;code&gt;Format&lt;/code&gt;&amp;gt; &lt;code&gt;Spelling and Grammar&lt;/code&gt; &amp;gt; &lt;code&gt;Check Spelling While Typing&lt;/code&gt; and Xcode will check your code for typos.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Correction of all problems
&lt;/h2&gt;

&lt;p&gt;If you have a Swift file that contains a lot of errors, you can use XCode hints to try and fix the errors one by one. But a faster way is to go to the menu and select &lt;code&gt;Fix All Issues&lt;/code&gt; to apply all the fixes at once. (Make sure and double-check what changes have been made!).&lt;/p&gt;

&lt;h2&gt;
  
  
  6. Deleting search results
&lt;/h2&gt;

&lt;p&gt;When you search using XCode's search navigator, you can click to view individual results and make any changes you want. But when you're done, I recommend that you press Backspace to remove that search item from the results so you can see what results are left to check.&lt;/p&gt;

&lt;h2&gt;
  
  
  7. Resuming the SwiftUI Canvas
&lt;/h2&gt;

&lt;p&gt;This is the easiest tip I know, but it will save you time if you don't already know it. Whenever you see the preview auto update pause on the SwiftUI canvas, press Opt+Cmd+P to resume the preview. Or use Opt+Cmd+Return to completely hide the canvas.&lt;/p&gt;

&lt;h2&gt;
  
  
  8. Simulator tiling
&lt;/h2&gt;

&lt;p&gt;If you often switch from XCode to the simulator, place them next to each other. With the simulator active, go to the menu window and select Tile Window To Right Of Screen, then select Xcode on the left. Adjust the position.&lt;/p&gt;

&lt;h2&gt;
  
  
  9. Autocomplete Extension
&lt;/h2&gt;

&lt;p&gt;XCode has great code completion built in, but sometimes when you're scrolling through the options, you may find that the names are too long to fit. Luckily, you can just grab the edge of the autocomplete popup and drag it as wide as you want!&lt;/p&gt;

&lt;h2&gt;
  
  
  10. Fast switching breakpoints
&lt;/h2&gt;

&lt;p&gt;Breakpoints are great for debugging - place them by selecting the line number, or remove them by right-clicking and choosing Delete Breakpoint. You can also remove one by dragging it, but a quick way is to use &lt;code&gt;Cmd+\&lt;/code&gt; to toggle the breakpoint on the current line.&lt;/p&gt;

&lt;h2&gt;
  
  
  11. Test Order Randomization
&lt;/h2&gt;

&lt;p&gt;Sometimes the output of one test affects the input of another. XCode has a solution: go to the &lt;code&gt;Product menu&lt;/code&gt;, &lt;code&gt;hold down the Option button&lt;/code&gt;, then click &lt;code&gt;Test&lt;/code&gt;. On the &lt;code&gt;Info tab&lt;/code&gt;, click &lt;code&gt;Options&lt;/code&gt;, then check the R&lt;code&gt;andomize Execution Order&lt;/code&gt; checkbox to run the tests in a different order each time.&lt;/p&gt;

&lt;h2&gt;
  
  
  12. Jump bar filtering
&lt;/h2&gt;

&lt;p&gt;Jump bar in XCode (&lt;code&gt;Ctrl-6&lt;/code&gt;) is the best way to quickly navigate through long files, allowing you to see all the properties and methods in your file. For longer files, start typing with the jump bar open and Xcode will filter them out - a trick that also works for device selection.&lt;/p&gt;

&lt;h2&gt;
  
  
  13. Interface file generation
&lt;/h2&gt;

&lt;p&gt;Often you want to get an idea of ​​how some code works. If you press Ctrl+Cmd+Up, XCode will create a generated interface showing properties, function signatures, and comments. If you click it again, XCode will take you to the tests for that file, if they exist.&lt;/p&gt;

&lt;h2&gt;
  
  
  14. Quickly add comments
&lt;/h2&gt;

&lt;p&gt;One of my most used XCode keyboard shortcuts is &lt;code&gt;Cmd+/&lt;/code&gt; to toggle comments on the current line or selection, but another useful one is &lt;code&gt;Option+Cmd+/&lt;/code&gt; - press it just before a method to have Xcode generate a documentation comment, including its options.&lt;/p&gt;

&lt;h2&gt;
  
  
  15. Find files faster
&lt;/h2&gt;

&lt;p&gt;As your projects grow, it becomes more and more difficult to use the project navigator to find something. There are two solutions, one is to right-click on any group of files and select Sort By Name to sort them alphabetically, and the other is to type in the filter box at the bottom.&lt;/p&gt;

&lt;h2&gt;
  
  
  16. Display initial changes at runtime
&lt;/h2&gt;

&lt;p&gt;XCode can process source changes right in its editor. To try it, turn on Show Source Control Changes in XCode Preferences and then make your changes. You'll see a blue bar on the left, but if you click on it and select Show Change, Xcode will show you the old and new inline code.&lt;/p&gt;

&lt;h2&gt;
  
  
  17. Search code on the minimap
&lt;/h2&gt;

&lt;p&gt;The XCode minimap helps us view long files - turn it on in the &lt;code&gt;Editor&lt;/code&gt;&amp;gt; &lt;code&gt;Minimap&lt;/code&gt; menu. When you hover your mouse over it, the mini-map tells you the name of the method you've completed. You can also hold &lt;code&gt;Cmd&lt;/code&gt;to show the names of everything and then click on the name to jump to it.&lt;/p&gt;

&lt;h2&gt;
  
  
  18. Rerun the last test
&lt;/h2&gt;

&lt;p&gt;It often happens that bad tests have been written, especially when using TDD. Luckily, XCode has a keyboard shortcut to run only the last test, which is faster than running everything: Ctrl+Opt+Cmd+G. John Reed has a special name that makes it easier to remember: "Smash Go!"&lt;/p&gt;

&lt;h2&gt;
  
  
  19. Remapping useless keys
&lt;/h2&gt;

&lt;p&gt;Some great keyboard shortcuts (like &lt;code&gt;Shift+Cmd+O&lt;/code&gt; for quick opening) sit next to useless keyboard shortcuts (&lt;code&gt;Shift+Cmd+P&lt;/code&gt; when you want to type code). It only takes a few seconds to remove useless keys, and you can even remap shortcuts like &lt;code&gt;Cmd + P&lt;/code&gt; to resume SwiftUI preview.&lt;/p&gt;

&lt;h2&gt;
  
  
  20. Improve your searches
&lt;/h2&gt;

&lt;p&gt;All headings in the XCode search navigator can be changed: Find can be "Replace", Text can be a link or regular expression, and Containing can be a match, start, etc. You can also click the magnifying glass to view recent searches - when choosing one of them, it repeats.&lt;/p&gt;

&lt;h2&gt;
  
  
  21. Change code indentation
&lt;/h2&gt;

&lt;p&gt;If you've copied the code from somewhere else, then there's a good chance you'll paste something with the wrong indentation. XCode can fix this with one shortcut: select the code you want to fix, then press Ctrl+I to change its indentation.&lt;/p&gt;

&lt;h2&gt;
  
  
  22. Testing in-app purchases
&lt;/h2&gt;

&lt;p&gt;You can test in-app purchases without App Store Connect. Create a new StoreKit config file and add your IAP. Now go to the Product menu, hold down the Option key and press Run. On the Options tab, change the StoreKit configuration and you will now use the test IAP.&lt;/p&gt;

&lt;h2&gt;
  
  
  23. Explore build options
&lt;/h2&gt;

&lt;p&gt;There are plenty of settings to control how XCode builds your code, but it's hard to remember what they all do. Luckily, you can select one and use the Quick Help inspector to view the documentation for most of the options, or Option-click and double-click to get the built-in help.&lt;/p&gt;

&lt;h2&gt;
  
  
  24. Pin preview
&lt;/h2&gt;

&lt;p&gt;Canvas is a great way to preview layouts as you work, but it's harder to use when one view is split into multiple files. To make things easier, use the pin below to keep the current preview active, allowing you to change one file while previewing another.&lt;/p&gt;

</description>
      <category>xcode</category>
      <category>swift</category>
      <category>swifttip</category>
      <category>programming</category>
    </item>
    <item>
      <title>Create Better code with Swift Algorithms</title>
      <dc:creator>Vadim Atamanenko</dc:creator>
      <pubDate>Sun, 20 Nov 2022 13:03:15 +0000</pubDate>
      <link>https://dev.to/vadimatamanenko/create-better-code-with-swift-algorithms-4gio</link>
      <guid>https://dev.to/vadimatamanenko/create-better-code-with-swift-algorithms-4gio</guid>
      <description>&lt;p&gt;The Swift Standard Library includes types and functions to quickly and efficiently solve common code problems, but it doesn't cover everything. Therefore, for more complex tasks, we often need to use &lt;a href="https://github.com/apple/swift-algorithms" rel="noopener noreferrer"&gt;Swift algorithms&lt;/a&gt;: Apple's on-demand algorithms and data collection package, with the source code tuned for performance and flexibility.&lt;/p&gt;

&lt;p&gt;A great time to see at the upcoming Advent of Code 2021 how Swift Algorithms can help you write faster, simpler, and safer code. There is functionality to create unique sequences, divide them, select multiple random elements, compress them, etc. And most of them return new types of sequences, highly optimized, more efficient than reducing everything to a simple array.&lt;/p&gt;

&lt;p&gt;Apple also &lt;a href="https://www.swift.org/blog/swift-algorithms/" rel="noopener noreferrer"&gt;said &lt;/a&gt;that Swift Algorithms provides an opportunity to study the problems and solutions of algorithms before translating them into the main standard library: you get better code today, and see what the standard library can become in the future. Isn't it great?&lt;/p&gt;

&lt;p&gt;Best of all, adding Swift Algorithms to your Xcode project only takes a few minutes: go to File, select Add Packages, select Apple Swift Packages, then select "swift-algorithms" and click &lt;code&gt;Add Package&lt;/code&gt;. Now just add import Algorithms to your code and you're done!&lt;/p&gt;

&lt;p&gt;In this article, I'm going to highlight just a few of what Swift Algorithms can already do, focusing on nine specific algorithms that I find most useful. Let's get started...&lt;/p&gt;

&lt;h2&gt;
  
  
  Sequence chain
&lt;/h2&gt;

&lt;p&gt;If you have two arrays of data and want to iterate over both of them, you can write something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;let names1 = ["Jane", "Elizabeth", "Mary", "Kitty"]
let names2 = ["Daphne", "Eloise", "Francesca", "Hyacinth"]

for name in names1 + names2 {
    print(name)
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will print all eight names, but in doing so we had to create a new temporary array by concatenating &lt;code&gt;names1&lt;/code&gt;and &lt;code&gt;names2&lt;/code&gt;together. In this case, this is not a problem, but if your arrays were much larger, it would be quite expensive.&lt;/p&gt;

&lt;p&gt;Swift Algorithms has a solution called &lt;code&gt;chain()&lt;/code&gt; it creates a new sequence by concatenating two others without doing any further distributions. Here's what it looks like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;for name in chain(names1, names2) {
    print(name)
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Behind the scenes, &lt;code&gt;chain()&lt;/code&gt; keeps references to your two existing sequences and just effectively chains their iterators together so that when one ends, another begins.&lt;/p&gt;

&lt;p&gt;This works with other types of sequences too, so we can check exactly if a value is in two different ranges:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;let tooLow = 0...20
let tooHigh = 80...100
let outOfBounds = chain(tooLow, tooHigh)

let value = 35
print(outOfBounds.contains(value))
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What's more, this works for any type of sequence, so we can link a range and an array:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;let reservedSeats = 0...50
let unavailableSeats = [61, 68, 75, 76, 77, 92]
let disallowed = chain(reservedSeats, unavailableSeats)

let requestedSeat = 39
print(disallowed.contains(requestedSeat))
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Splitting sequences
&lt;/h2&gt;

&lt;p&gt;Have you ever wanted to split a sequence into equal parts, or perhaps based on certain criteria? Swift Algorithms provides several flavors of split functions that do just that: they are extremely efficient at turning complex, error-prone work into single-line code.&lt;/p&gt;

&lt;p&gt;As an example, we could create an array of students with names and grades as letters like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;struct Student {
    let name: String
    let grade: String
}

let results = [
    Student(name: "Taylor", grade: "A"),
    Student(name: "Sophie", grade: "A"),
    Student(name: "Bella", grade: "B"),
    Student(name: "Rajesh", grade: "C"),
    Student(name: "Tony", grade: "C"),
    Student(name: "Theresa", grade: "D"),
    Student(name: "Boris", grade: "F")
]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Using Swift Algorithms, we could split this array of results based on the scores, and then neatly print them out:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;let studentsByGrade = results.chunked(on: \.grade)

for (grade, students) in studentsByGrade {
    print("Grade \(grade)")

    for student in students {
        print("\t\(student.name)")
    }

    print()
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It will automatically create a new fragment whenever the value being checked changes, so you need to be careful if your value jumps around. In the code above, all student grades are displayed in order - two "A"s together, as well as two "Cs", so this is not a problem. But if we need to split the array by taking student names, we must first sort them to make sure the initial letters are grouped together:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;let studentsByName = results.sorted { $0.name &amp;lt; $1.name }.chunked(on: \.name.first!)

for (firstLetter, students) in studentsByName {
    print(firstLetter)

    for student in students {
        print("\t\(student.name)")
    }

    print()
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There is an alternative fragmentation method that allows us to split the sequence by the number of elements in each fragment. For example, we could pair our students like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;let pairs = results.chunks(ofCount: 2)

for pair in pairs {
    let names = ListFormatter.localizedString(byJoining: pair.map(\.name))
    print(names)
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It will print "Taylor and Sophie", "Bella and Rajesh", and "Tony and Teresa", but since "Boris" does not have a match, it will be a one-piece fragment.&lt;/p&gt;

&lt;p&gt;Be careful: data fragmentation will return a slice of the array, not an array, because that's more efficient. This means that if you try to read indices like 0 and 1 for our pair, you will run into a problem. So avoid code like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;let pairs = results.chunks(ofCount: 2)

for pair in pairs {
    if pair.count == 2 {
        print("\(pair[0].name) and \(pair[1].name) are working together")
    } else {
        print("\(pair[0].name) is working alone")
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you definitely want an array and not a slice of an array, transform each element before the loop, like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;let pairs = results.chunks(ofCount: 2).map(Array.init)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Random sampling&lt;br&gt;
One of my favorite features of Swift Algorithms is the &lt;code&gt;randomSample(count:)&lt;/code&gt; method and its analog &lt;code&gt;randomStableSample(count:)&lt;/code&gt;, both of which are improved forms of &lt;code&gt;randomElement()&lt;/code&gt; and vice versa select N random non-repeating elements.&lt;/p&gt;

&lt;p&gt;Of the two methods, &lt;code&gt;randomSample(count:)&lt;/code&gt; is the fastest and works on all sequences. However, it doesn't preserve the order of your elements, so you'll end up with N random non-repeating elements in any order.&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;let lotteryBalls = 1...50
let winningNumbers = lotteryBalls.randomSample(count: 7)
print(winningNumbers)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you specify a number equal to or greater than the number of elements in your sequence, the entire sequence will be returned, again in random order.&lt;/p&gt;

&lt;p&gt;An alternative is &lt;code&gt;randomStableSample(count:)&lt;/code&gt;, which works a little differently. First, it only works with collections, because it needs to know how many elements it is sampling from, and is also slightly slower than &lt;code&gt;randomSample(count:)&lt;/code&gt;. However, it preserves the order of your elements, which can be useful:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;let people = ["Chidi", "Eleanor", "Jason", "Tahani"]
let selected = people.randomStableSample(count: 2)
print(selected)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Walking in sequence
&lt;/h2&gt;

&lt;p&gt;Swift Algorithms has added a new &lt;code&gt;striding(by:)&lt;/code&gt; method that moves through a sequence in steps of a certain size, similar to &lt;code&gt;stride(from:through:by)&lt;/code&gt;, except that it works directly with sequences and is therefore much more efficient.&lt;/p&gt;

&lt;p&gt;First, a simple example so that you can see the direct difference between the old and the new. This code prints all odd numbers from 1 to 1000:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;let numbers = 1...1000
let oddNumbers = numbers.striding(by: 2)

for oddNumber in oddNumbers {
    print(oddNumber)
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can get the same result using &lt;code&gt;stride(from:through:by:)&lt;/code&gt; like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;let oddNumbers = stride(from: numbers.lowerBound, through: numbers.upperBound, by: 2)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The advantage of using &lt;code&gt;striding()&lt;/code&gt; is that it works on more complex collections such as strings and array fragments. So we can efficiently extract parts of a string like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;let inputString = "a1b2c3d4e5"
let letters = inputString.striding(by: 2)

for letter in letters {
    print(letter)
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Lately I've been using this to handle the decryption of columnar transposition ciphers, where plaintext letters are spaced at fixed intervals in a string.&lt;/p&gt;

&lt;h2&gt;
  
  
  Finding Unique Items
&lt;/h2&gt;

&lt;p&gt;Swift Algorithms has useful functionality for finding unique elements in a sequence, either based on their natural uniqueness (if your type is &lt;code&gt;Hashable&lt;/code&gt; compliant) or using a function you specify.&lt;/p&gt;

&lt;p&gt;Let's start with a simple example: you ask a group of people about their lucky number and get different answers. If you want to select each unique response, you can do this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;let allNumbers = [3, 7, 8, 8, 7, 67, 8, 7, 13, 8, 3, 7, 31]
let uniqueNumbers = allNumbers.uniqued().sorted()

for number in uniqueNumbers {
    print("\(number) is a lucky number")
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you need something a little more advanced, &lt;code&gt;uniqued(on:)&lt;/code&gt; allows you to provide a function that takes one element from a sequence and returns a &lt;code&gt;Hashable&lt;/code&gt; of whatever type you want to use in your uniqueness test. Using &lt;code&gt;key paths&lt;/code&gt; as functions, we can write code to iterate through an array of cities and select only one city for each country:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;struct City {
    let name: String
    let country: String
}

let destinations = [
    City(name: "Hamburg", country: "Germany"),
    City(name: "Kyoto", country: "Japan"),
    City(name: "Osaka", country: "Japan"),
    City(name: "Naples", country: "Italy"),
    City(name: "Florence", country: "Italy"),
]

let selectedCities = destinations.uniqued(on: \.country)

for city in selectedCities {
    print("Visit \(city.name) in \(city.country)")
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this situation, &lt;code&gt;uniqued(on:)&lt;/code&gt; will always return the first unique element from multiple choices, so the above code will return Hamburg, Kyoto, and Naples.&lt;/p&gt;

&lt;h2&gt;
  
  
  Removing an optionality
&lt;/h2&gt;

&lt;p&gt;The Swift standard library provides &lt;code&gt;compactMap()&lt;/code&gt; to convert an element to some optional result, but then unwrap that optional and remove any nil's. However, it's common to think of &lt;code&gt;compactMap { $0 }&lt;/code&gt; as a way of not doing a transformation, but just storing the optional expanded and removing steps, for example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;let numbers = [10, nil, 20, nil, 30]
let safeNumbers = numbers.compactMap { $0 }
print(safeNumbers.count)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This works, but Swift Algorithms offers an improved version called simply c&lt;code&gt;ompacted()&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;let numbers = [10, nil, 20, nil, 30]
let safeNumbers = numbers.compacted()
print(safeNumbers.count)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Ok, a little less typing, but much clearer what you mean. The use of &lt;code&gt;$0&lt;/code&gt; in &lt;code&gt;compactMap()&lt;/code&gt; has always seemed more of a workaround than intentional.&lt;/p&gt;

&lt;p&gt;However, &lt;code&gt;compacted()&lt;/code&gt; has another major advantage, which is that it is always lazy, not just when you request it. This way the deployment and removal process will only happen when you actually use it, which makes it much more efficient when you chain operations together.&lt;/p&gt;

&lt;h2&gt;
  
  
  Nested Loops Improvement
&lt;/h2&gt;

&lt;p&gt;Nested loops allow us to iterate over one sequence every time we iterate over another, and Swift Algorithms provides a &lt;code&gt;product()&lt;/code&gt; function that gives us extra control in a situation like this.&lt;/p&gt;

&lt;p&gt;For example, if we have two arrays of people and games, we could use &lt;code&gt;product()&lt;/code&gt; to iterate over each combination so that each person could play each game:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;let people = ["Sophie", "Charlotte", "Maddie", "Sennen"]
let games = ["Mario Kart", "Boomerang Fu"]

let allOptions = product(people, games)

for option in allOptions {
    print("\(option.0) will play \(option.1)")
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The loop will print: "Sophie will play Mario Kart", "Sophie will play Boomerang Fu", "Charlotte will play Mario Kart", "Charlotte will play Boomerang Fu" and so on.&lt;/p&gt;

&lt;p&gt;The first parameter to &lt;code&gt;product()&lt;/code&gt; can be any sequence because it loops once, but the second parameter must be a collection because it iterates many times. Of course, you can also provide the same collection for both options if you like, which means we can print out the full set of multiplication tables, like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;let range = 1...12
let allMultiples = product(range, range)

for pair in allMultiples {
    print("\(pair.0) x \(pair.1) is \(pair.0 * pair.1)")
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You might think that this is no better than using nested for loops, but the magic is that &lt;code&gt;product()&lt;/code&gt; gives us a new collection that we can manipulate further. For example, we want to select 20 random questions from all possible multiplication tables, like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;let range = 1...12
let questionCount = 20
let allMultiples = product(range, range).shuffled().prefix(questionCount)

for pair in allMultiples {
    print("\(pair.0) x \(pair.1) is \(pair.0 * pair.1)")
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you've been following closely, you may have noticed that we can just use &lt;code&gt;randomSample(count:)&lt;/code&gt; instead of shuffling and prepending:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;let allMultiples = product(range, range).randomSample(count: questionCount)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;One slight downside to using &lt;code&gt;product()&lt;/code&gt; right now is that it only works with two parameters, meaning that if you need to iterate over multiple collections, you'll have to nest calls to your &lt;code&gt;product()&lt;/code&gt;. So we could make the world's most tedious Cluedo/Clue (detective game) game like this:&lt;/p&gt;

&lt;p&gt;let suspects = ["Colonel Mustard", "Professor Plum", "Mrs White"]&lt;br&gt;
let locations = ["kitchen", "library", "study", "hall"]&lt;br&gt;
let weapons = ["candlestick", "dagger", "lead pipe", "rope"]&lt;br&gt;
let guesses = product(product(suspects, locations), weapons)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;for guess in guesses {
    print("Was it \(guess.0.0) in the \(guess.0.1) with the \(guess.1)?")
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is how my 8 year old plays, so not bad for just a few lines of code!&lt;/p&gt;

&lt;h2&gt;
  
  
  Sliding windows in sequence
&lt;/h2&gt;

&lt;p&gt;Another one of my favorite additions to Swift Algorithms is the ability to read duplicate (overlapping) subsequences of the main sequence, which is great for things like calculating moving averages over a sequence.&lt;/p&gt;

&lt;p&gt;If you just want all adjacent pairs, you can use the lazy &lt;code&gt;adjacentPairs()&lt;/code&gt; method in sequence, like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;let numbers = (1...100).adjacentPairs()

for pair in numbers {
    print("Pair: \(pair.0) and \(pair.1)")
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;However, for more advanced tasks, there is also a &lt;code&gt;windows(ofCount:)&lt;/code&gt; method that allows you to control how big your sliding window should be. So we could make groups of 5 like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;let numbers = (1...100).windows(ofCount: 5)

for group in numbers {
    let strings = group.map(String.init)
    print(ListFormatter.localizedString(byJoining: strings))
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When it runs, it will print "1, 2, 3, 4 and 5", "2, 3, 4, 5 and 6", "3, 4, 5, 6 and 7" and so on. These are all subsequences of the original sequence, so again, this is super efficient.&lt;/p&gt;

&lt;p&gt;I recently used the &lt;code&gt;windows(ofCount:)&lt;/code&gt; method when decoding a Vigenère cipher because it allowed me to look through a huge string of letters and find all repeated substrings.&lt;/p&gt;

&lt;h2&gt;
  
  
  Minimum and maximum
&lt;/h2&gt;

&lt;p&gt;Finally, Swift Algorithms offers advanced methods for calculating the minimum and maximum values ​​in a sequence. You can provide your own test if you want, but if your sequence matches &lt;code&gt;Comparable&lt;/code&gt;, you get the default test, with a &amp;lt; sign, like so:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;let names = ["John", "Paul", "George", "Ringo"]

if let (first, last) = names.minAndMax() {
    print(first)
    print(last)
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Methods are also provided for reading multiple highest and lowest values ​​at the same time, for example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;let scores = [42, 4, 23, 8, 16, 15]
let threeLowest = scores.min(count: 3)
print(threeLowest)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Under the hood, the results will be sorted and padded at the beginning or end if you try to read more than 10% of the entire sequence, but otherwise it uses a faster algorithm, just doing the right thing automatically, like a lot of things in Swift Algorithms.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;And that is not all!&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I just touched on just a few of my favorites in Swift Algorithms.&lt;/p&gt;

&lt;p&gt;To learn more, I recommend you visit the Swift Algorithms GitHub repository: &lt;a href="https://github.com/apple/swift-algorithms" rel="noopener noreferrer"&gt;https://github.com/apple/swift-algorithms&lt;/a&gt;. All of this is Swift open source, so you can explore it for yourself and see how Swift Algorithms squeeze so much out of their code.&lt;/p&gt;

</description>
      <category>watercooler</category>
    </item>
    <item>
      <title>Memory types in Swift</title>
      <dc:creator>Vadim Atamanenko</dc:creator>
      <pubDate>Sun, 02 Oct 2022 15:13:34 +0000</pubDate>
      <link>https://dev.to/vadimatamanenko/memory-types-in-swift-dko</link>
      <guid>https://dev.to/vadimatamanenko/memory-types-in-swift-dko</guid>
      <description>&lt;p&gt;Hey everyone, this time I propose to analyze the theoretical part and an equally interesting topic.&lt;/p&gt;

&lt;p&gt;Let's talk about memory types in Swift. Let's start as we should from the very beginning, memory management is an important part of developing efficient applications, misusing it to problems ranging from slow loading to crashes.&lt;/p&gt;

&lt;p&gt;There are three types of memory:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;static&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;automatically&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;dynamic&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A &lt;strong&gt;static type&lt;/strong&gt; is responsible for allocating memory before the start of program execution; such memory is available throughout the entire program execution time in many languages. To allocate static memory objects, it is enough to declare its global scope.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Automatic type&lt;/strong&gt; or stacking is the most basic. Arguments and local variables of the function are automatically allocated, as well as other meta information when the function is called, and memory is freed when it exits.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Dynamic type&lt;/strong&gt; allocation of memory from the operating system as required by the application. The application can, if necessary, request additional memory from the operating system via the Locator or directly via a system call. An locator is a part of a program that requests memory in large chunks directly from the operating system through system calls, then gives this memory to the application piece by piece.&lt;/p&gt;

&lt;p&gt;How is RAM used when running a program? When executing a program, it needs access to RAM to load its machine code for execution, store the value of variables and data structure, and load external modules needed to perform tasks. In addition to the place used to load its own code, the application uses two areas of RAM during operation, the stack on the basis of which automatic memory works and the so-called Heap, which is used for dynamic memory allocation.&lt;/p&gt;

&lt;p&gt;Now let's talk more about these mysterious stacks and heaps. &lt;/p&gt;

&lt;p&gt;So let's start with &lt;strong&gt;stacks&lt;/strong&gt;.&lt;br&gt;
The allocation of memory for the stack is determined when the program is compiled, access to it is very fast. The stack is organized in a Last In First Out (LIFO).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--IAdOklPN--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/fxdekp8cz3m8ap0dcndq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--IAdOklPN--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/fxdekp8cz3m8ap0dcndq.png" alt="Image description" width="880" height="495"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The stack can be visualized as a stack of books with which we are only allowed to interact with the topmost book, read it and put on a new one. All manipulations are performed with the top book in the stack, the book is added to the very top if you need to save the data, or taken from the top if the data needs to be read. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ol9WJBmb--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9kyf377838x0inb2ojxq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ol9WJBmb--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9kyf377838x0inb2ojxq.png" alt="Image description" width="880" height="660"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;There are two main commands for working with stacks.&lt;/p&gt;

&lt;p&gt;Push pushes data to the top of our stack of books and Pop gets the book from the top of the stack. Each function on the stack has its own place called a frame. When one function calls another, the latter always knows where to get its arguments at the end of the stack.&lt;/p&gt;

&lt;p&gt;How does the function know where the end of the stack is? The processor has a special register for this, which finally stores the stack pointers and in most cases it is located closer to the end of the virtual memory and grows towards the beginning. Each thread of a multithreaded application has access to its own stack. &lt;/p&gt;

&lt;p&gt;Stacks are used for value types, that is, for value types. If the size of a value type can be determined at compile time or if our value type does not contain a recursion of itself or is in a reference type then it will require stack allocation.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--clmSfve7--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/r0g03m97swi294rvfztq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--clmSfve7--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/r0g03m97swi294rvfztq.png" alt="Image description" width="880" height="375"&gt;&lt;/a&gt;&lt;br&gt;
Now let's move on to Heap.&lt;/p&gt;

&lt;p&gt;Heaps are used to dynamically allocate memory, you can think of a heap as a big bookcase where a needed book can be found using a specific instruction. After allocating memory, the program receives a pointer to the beginning of the allocated memory, which, in turn, must also be stored somewhere, in static, automatic, or also dynamic memory.&lt;/p&gt;

&lt;p&gt;Ultra-high-level languages use dynamic memory as the main one. All or almost all objects are created in dynamic memory, and a pointer to these objects is kept on the stack or in static memory. Operations on the heap are somewhat slower than on the stack, since it requires an additional step to look up the data.&lt;/p&gt;

&lt;p&gt;The heap is shared by all threads in an application due to its dynamic nature. The heap is more difficult to manage and causes most of all memory-related problems and errors. The heap is used for reference types.&lt;/p&gt;

&lt;p&gt;When does heap partitioning happen differently? One option for when the Swift compiler will promote reference types to be placed on the stack is when their size is fixed or the lifetime can be predicted.&lt;/p&gt;

&lt;p&gt;Also, the Swift compiler can box value types and allocate them on heaps in the following cases:&lt;/p&gt;

&lt;p&gt;By following the protocol. In addition to resource allocation costs, additional memory leaks occur when the value type is stored in an existential container and exceeds three machine words in length.&lt;/p&gt;

&lt;p&gt;An existential container is a generic container for a value of an unknown runtime type, small value types can be inlined in an existential container, larger ones are placed on the heap and referenced in the container's existential buffer. Also the second option when mixing a value type and a reference type. A regular reference to a class is stored in a struct, and a struct is a field of the class.&lt;/p&gt;

&lt;p&gt;The third case is escaping closures. In the case where a value is stored on the stack and is captured by an escaping closure, then that value is copied to the heap so that it becomes available before the closure is executed.&lt;/p&gt;

&lt;p&gt;And one more option is the inout parameter.&lt;/p&gt;

&lt;p&gt;The inout parameters are passed to the entry point at address, the callee does not take ownership of the specified memory, the specified memory must be initialized when the function enters and exits.&lt;/p&gt;

&lt;p&gt;So, we got acquainted with the types of memory and let's sum up some results.&lt;/p&gt;

&lt;p&gt;Stacks store temporary data, method parameters and local variables. Each time we call a method on the stack, a new piece of memory is allocated, this memory is freed when the method exits. Stacks are specific to value types. Heaps store objects that have a lifetime. The heap is specific to reference types. The overhead of allocating and deallocating memory on the heap is much greater than allocating memory on the stack.&lt;/p&gt;

&lt;p&gt;That's all I hope you liked this theoretical material, that's all.&lt;/p&gt;

</description>
      <category>swift</category>
      <category>memorytypes</category>
    </item>
    <item>
      <title>How to Become an IT Thought Leader</title>
      <dc:creator>Vadim Atamanenko</dc:creator>
      <pubDate>Sun, 04 Sep 2022 10:35:18 +0000</pubDate>
      <link>https://dev.to/vadimatamanenko/how-to-become-an-it-thought-leader-2k71</link>
      <guid>https://dev.to/vadimatamanenko/how-to-become-an-it-thought-leader-2k71</guid>
      <description>&lt;h2&gt;
  
  
  Influencer and Brand Advocate
&lt;/h2&gt;

&lt;p&gt;Let's first understand what an opinion leader is and how he differs from an influencer and a brand advocate.&lt;br&gt;
Most companies strive to attract a loyal audience and form a pool of regular customers who will appreciate not only the company and its products, but also worry and help this company develop.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A brand advocate&lt;/strong&gt; is a loyal, passionate and devoted fan who is even better than in-house marketers at talking about your product, helping to promote it and achieve good results.&lt;br&gt;
&lt;strong&gt;An opinion leader&lt;/strong&gt; is a person who can influence the formation of the opinions of others and the general public, influence the emergence of trends, create or intensify discussion of various topics.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“If your product gets into the circle of discussions and topics covered by an opinion leader and a person starts promoting it, then he is both an opinion leader and a brand advocate.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Collaboration with an opinion leader helps to effectively reach out to specific consumers, have the most fruitful impact on them and build trust between the audience and the brand.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;An influencer&lt;/strong&gt; is a person who spreads ideas or information in a particular environment.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“From the point of view of communication technologies and mechanics, an opinion leader and an agent of influence are practically the same thing.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;But an agent of influence is not necessarily an opinion leader. This is a person who can set the tone for communications and influence some action on the part of the target audience. Strengthen or reduce the influence of specific influencers, marketing messages and enable businesses to more effectively develop communication between the brand and the consumer.&lt;/p&gt;

&lt;h2&gt;
  
  
  Who can be an opinion leader
&lt;/h2&gt;

&lt;p&gt;It is usually considered that opinion leaders are politicians, representatives of show business, creative professions, athletes, social activists or authorities in various fields of activity. But opinion leaders can also be ordinary people who influence the decisions of their relatives, friends and associates. For example, you can be an authority for your environment and, accordingly, influence their opinions.&lt;/p&gt;

&lt;p&gt;Opinion leaders in social networks are bloggers, journalists (both professional and non-professional), as well as users who actively publish their own content that has an impact on the audience that reads it.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“The main feature of an opinion leader is the ability not only to broadcast information to a large audience, but also to really influence the opinions, actions, and behavior of specific people.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Through their ability to get the message across, influencers can generate public outcry on a variety of issues, both in relation to certain products and in relation to certain situations.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Characteristics of an opinion leader&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;An opinion leader has the following qualities:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;active life position;&lt;/li&gt;
&lt;li&gt;an extensive network of social contacts online and offline;&lt;/li&gt;
&lt;li&gt;the desire to disseminate useful information, bring value to their audience;&lt;/li&gt;
&lt;li&gt;demonstrating your expertise;&lt;/li&gt;
&lt;li&gt;confidence in the formation of microtrends;&lt;/li&gt;
&lt;li&gt;the ability to raise various issues that cause a certain response from the audience;&lt;/li&gt;
&lt;li&gt;strong involvement in the process of solving any problems.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;An opinion leader influences through emotions or rational arguments, inspiring trust and response from people who find in his words and actions a correspondence with their internal problems and expectations.&lt;/p&gt;

&lt;h2&gt;
  
  
  How influencers can be useful for business
&lt;/h2&gt;

&lt;p&gt;Attracting opinion leaders allows you to quickly convey certain information about the company, product, specific situation to the target audience.&lt;/p&gt;

&lt;p&gt;People trust the leader of opinions, and sometimes imitate. He has real authority, his achievements are beyond doubt, and his competence in his field is not even disputed. The combination of these qualities makes an opinion leader an ideal tool for promoting various kinds of messages.&lt;/p&gt;

&lt;p&gt;The important thing is that this is not only communication with the target audience, but also the opportunity to stimulate certain follow-up actions of this target audience:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;purchase of a specific product;&lt;/li&gt;
&lt;li&gt;resolving situations in relation to service problems;&lt;/li&gt;
&lt;li&gt;getting good reviews about the product;&lt;/li&gt;
&lt;li&gt;feedback at the stage of testing the product and its refinement;&lt;/li&gt;
&lt;li&gt;opening up new opportunities for using the product.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;An opinion leader values ​​his usefulness to the audience. It can both negatively and positively influence the solution of various situations related to the brand. For example, to extinguish the negative impact of certain facts on the public, or, conversely, to strengthen.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“Interaction with opinion leaders is one of the important moments of brand interaction with the target audience. Business needs to find common ground with influential people and establish effective communications.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Where to find influencers
&lt;/h2&gt;

&lt;p&gt;To find influencers that will be useful for your business, you first need to analyze your target audience. During the evaluation, you will see where your target audience dominates, who they follow, what they read, what content they are interested in.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“Based on this analysis, you will be able to find those opinion leaders who are trusted by your target audience.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The audience can be found in the circle of their immediate environment. You can go to specialized events where your target audience and experts who convey key information prevail. You will simultaneously see people broadcasting certain content and how your target audience reacts to certain opinion leaders.&lt;/p&gt;

&lt;p&gt;Opinion leaders need to be searched on the Internet using simple monitoring or services that allow you to determine certain people by rating or interests.&lt;br&gt;
Pay attention to the number of followers and their degree of involvement on the person's page.&lt;/p&gt;

&lt;p&gt;In addition to followers, look at how people react to the influencer's posts. He doesn't have to write posts every hour, but the return on posts that have deep content should be very high.&lt;br&gt;
Interview members of your target audience about the personalities they are interested in, whose opinion they value and whose recommendations they listen to. This is the easiest way to determine the points of influence on your target audience, and maybe give an answer with whom you should cooperate with in the future.&lt;br&gt;
Interview experts in your field of activity, they will indicate to you people whom they trust and whose opinion they listen to. Often the interests of the target audience coincide with the opinions of experts.&lt;/p&gt;

&lt;p&gt;You can use monitoring services that provide additional information about the number of subscribers and influencer ratings. If your target audience is very narrow, then it is important to sort either by key queries or by a specific topic of content that this or that influencer publishes.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to negotiate and communicate effectively with opinion leaders
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;“Opinion leaders are people. And all communication with them is people to people, per-to-per.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;To work effectively with influencers, you need to build trust between a brand, a company representative and a certain person. These relationships are built on the principles of mutual benefit.&lt;/p&gt;

&lt;p&gt;The advent of social media has made it easier to find, communicate, and connect with opinion leaders. But at the same time, no one canceled the element of trust. If for some reason you could not agree with the influencer you wanted to attract, find people in your environment who could recommend you and improve relations with the person.&lt;/p&gt;

&lt;p&gt;This is an interpersonal relationship, so it is important to fine-tune communication. The further effectiveness of his interaction with your target audience depends on the opinion leader's perception of your company.&lt;br&gt;
Try to be useful to a specific influencer and provide all possible information about your product or service. Give the product for testing so that the person knows exactly what you want to convey to the public.&lt;/p&gt;

&lt;p&gt;At the same time, do not openly impose a product and do not focus solely on financial components and on the benefits of a particular opinion leader. It is important to build trust in you and your company, to identify the influencer's interest in interacting with your brand and product. If you do not achieve this, you will receive very dry feedback or communication that will be supported solely by financial motives and will not have the desired effect.&lt;/p&gt;

&lt;h2&gt;
  
  
  Options for cooperation with opinion leaders
&lt;/h2&gt;

&lt;p&gt;There are three options for working with influencers:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;financial motivation.&lt;/li&gt;
&lt;li&gt;commodity-material relations.&lt;/li&gt;
&lt;li&gt;free promotion of your product.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The third is solely the result of the formed trust, which depends on your personal communication. But here it is important to remember that "free cheese" may well be the expected "mousetrap". Especially when personal relationships collapse or when the opinion leader will have a completely different result than the one that was originally laid down in communication.&lt;/p&gt;

&lt;p&gt;The most trivial way to interact with an influencer is money or paid posts. The mechanics are simple. You contact an opinion leader, agree on specific conditions, offer certain rewards for hidden or native advertising of products. If this does not contradict the life principles and moral character of the opinion leader, then you will achieve a result.&lt;br&gt;
An important point is to give an understanding that a certain involvement in this communication must be obtained from the opinion leader.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“The more sincerely the opinion leader will talk about your product, the more the target audience will believe in this product and you will get a better result.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The second option is inventory items that can be presented as a gift to an opinion leader. This can form a small, short human communication with your target audience.&lt;br&gt;
Typically, this method is used in the fashion and lifestyle industry, where a gift is a small element of communication with the audience. An opinion leader can talk about his emotions when receiving a gift, share his impression about the product: what he liked, what he didn’t like.&lt;/p&gt;

&lt;p&gt;At the same time, it is important that the process itself should be emotionally filled.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“The higher the emotion of the opinion leader himself, the stronger the effect will be achieved in the communication that the opinion leader develops.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The third option is free promotion. If you are interesting and useful to the opinion leader, then it will not be difficult to persuade him to publish a post about your product.&lt;/p&gt;

&lt;h2&gt;
  
  
  Principles of working with opinion leaders
&lt;/h2&gt;

&lt;p&gt;There are several principles of working with opinion leaders:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Define your target audience and see which people they trust. Start communicating with these influencers.&lt;/li&gt;
&lt;li&gt;Choose quality leaders, don't chase stars with a huge number of followers. Perhaps they will treat you and your product with some condescension, showing their superiority. In communication with opinion leaders, trust and a certain friendly atmosphere are important. Start with less popular personalities.&lt;/li&gt;
&lt;li&gt;Make everything beautiful. In communication with an opinion leader, the state that you cause in a person is also important. If he trusts you, treats you warmly, then the tone of communication with your target audience will also be permeated with these feelings.&lt;/li&gt;
&lt;li&gt;Be sure to follow the opinion leaders.&lt;/li&gt;
&lt;li&gt;Always be honest.&lt;/li&gt;
&lt;li&gt;Don't place high hopes on them.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is where communication is important. The more often you communicate with influencers, the better you understand them and can bring more trust and friendly notes into your relationship. Also, you must broadcast your attitude towards the influencer to his audience.&lt;/p&gt;

&lt;h2&gt;
  
  
  Alternatives to face-to-face communication with influencers
&lt;/h2&gt;

&lt;p&gt;If it’s hard for you to personally communicate with specific opinion leaders, then services such as Publicfast (which was mentioned above) allow you to quickly and efficiently find your target audience.&lt;/p&gt;

&lt;p&gt;You can register there under the name of the brand and start interacting with the audience you are interested in.&lt;/p&gt;

&lt;p&gt;Instead of a conclusion&lt;/p&gt;

&lt;p&gt;Opinion leaders are not dogma. This is a separate communication channel that will allow a business to be more effective on the Internet. By collaborating with influencers, you speed up the moment of delivering information and build trust. Influencers share their trust and translate it into a brand or business, which adds value to your product.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Top mobile app development trends in 2022</title>
      <dc:creator>Vadim Atamanenko</dc:creator>
      <pubDate>Tue, 17 May 2022 03:57:19 +0000</pubDate>
      <link>https://dev.to/vadimatamanenko/top-mobile-app-development-trends-in-2022-4d58</link>
      <guid>https://dev.to/vadimatamanenko/top-mobile-app-development-trends-in-2022-4d58</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;In 2020, the number of unique mobile Internet users reached 4.28 billion, which means that more than 90% of the global Internet population used mobile devices to access the Internet. The trend of using mobile gadgets to access the Internet is gaining momentum, as evidenced by the active development of mobile networks, as well as the constant innovations that appear in mobile application development solutions.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In order to reach more consumers and improve the customer experience, more and more companies are choosing mobile apps based on the latest digital innovations. In this article, we'll take a look at the top mobile app development trends that will take off in 2022 and explain how they can help businesses thrive.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1). What types of mobile apps do you most commonly build now in 2022? (Hybrid, Native, etc.)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In recent years, the development of cross-platform solutions has become the future of mobile application development. Well-known companies such as Facebook, Pinterest, Alibaba and others are using this solution to improve their productivity.&lt;/p&gt;

&lt;p&gt;Competition is growing every day in many areas, and if you have an idea for a startup, you need to quickly validate it.  Creating native applications takes a lot of time and money, and the product may not be in demand.  Therefore, it is worth making a choice in favor of cross-platform.  Due to the common code base, developing your product for two platforms at once - iOS and Android - takes less time and budget.  Plus, app updates happen from the inside — without the need to add a new version to the AppStore and GooglePlay.&lt;/p&gt;

&lt;p&gt;We have already mentioned that cross-platform development is twice as fast as native development, but even parts of the React Native code can be integrated into ready-made native applications. So Instagram, originally developed natively, added push notifications and post promotion to its application.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2). What types of mobile app features are currently in high demand? (Payment gateway, security, search functions, etc.) Why?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;At the moment, the following types of applications are being developed and upgraded quite often:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Internet of Things (IoT) application integration&lt;/strong&gt;&lt;br&gt;
Here's how mobile apps improve the Internet of Things:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;provide a single centralized platform for multiple IoT devices;&lt;/li&gt;
&lt;li&gt;simple control of the device, narrowing down a significant number of settings to 1-2 buttons;&lt;/li&gt;
&lt;li&gt;provide increased security through access to a biometric application or two-factor authentication;&lt;/li&gt;
&lt;li&gt;increases personalization, when each user of the mobile application can customize the IoT network according to their preferences;&lt;/li&gt;
&lt;li&gt;allow you to manage IoT devices anywhere and anytime.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Development for wearable devices&lt;/strong&gt;&lt;br&gt;
Wearable devices are not a new invention in the gadget industry, however, their popularity will continue to grow in 2022. According to Statista, there were 722 million wearable devices in 2019, and its number is projected to be over 1 billion by 2022.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Augmented Reality (AR) and Virtual Reality&lt;/strong&gt;&lt;br&gt;
Augmented and virtual reality (AR and VR) are helping companies truly stand out and provide a new level of customer experience.  Here's how companies are using AR/VR to improve their customer experiences:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;contactless shopping&lt;/strong&gt; - some companies, such as Gucci and Ikea, use layers of augmented reality so that customers can experiment with their products;  they can try them on, like a new watch or makeover, or visualize the product they want to buy anywhere, like putting Ikea furniture at home to see if it fits;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;immersive experience&lt;/strong&gt; - when companies create VR/AR layers to better engage their customers in the interaction with their brand or product, for example, Coca-Cola came up with interactive features that customers play with on their smartphones;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;improved personalization&lt;/strong&gt; - customers can communicate with the brand in their own way, for example, L'Oreal invented a new men's fragrance called Only The Brave, and with the product they released a virtual reality world where users can experience how they behave in extreme conditions.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Companies are just starting to discover the potential of &lt;strong&gt;VR/AR technologies&lt;/strong&gt; to enhance brands and marketing campaigns.  However, the global augmented and virtual reality market is expected to grow by $125.19 billion between 2020-24.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Instant Apps&lt;/strong&gt;&lt;br&gt;
Instant Apps is another innovation in mobile development. This makes it easier to browse the contents of the app without having to install the app.  This allows customers to quickly decide if they want to install a particular app on their phone, and it also helps businesses more easily introduce their content to potential customers.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;As well as:&lt;br&gt;
Beacon technology&lt;br&gt;
Mobile commerce&lt;br&gt;
Artificial Intelligence (AI)&lt;br&gt;
Mobile wallets and mobile payments&lt;br&gt;
Chatbots&lt;br&gt;
Superior application security&lt;br&gt;
Predictive Analytics&lt;br&gt;
Applications on demand&lt;br&gt;
Cloud Computing Integration&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3). How important is mobile app maintenance after the first 12 months? Why?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Service and support in the first 12 months after a product launch is key, here during this period:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;application bugs that were not taken into account at the initial stage are revealed.&lt;/li&gt;
&lt;li&gt;new application features are being developed based on feedback from the first 300,000 users.&lt;/li&gt;
&lt;li&gt;the rights to the application are transferred and transferred for support to the internal divisions of the company.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>mobile</category>
      <category>developer</category>
      <category>discuss</category>
    </item>
    <item>
      <title>What is bad code and what to do about it</title>
      <dc:creator>Vadim Atamanenko</dc:creator>
      <pubDate>Sun, 15 May 2022 06:04:06 +0000</pubDate>
      <link>https://dev.to/vadimatamanenko/what-is-code-quality-how-to-improve-it-and-why-sometimes-good-code-is-bad-2dak</link>
      <guid>https://dev.to/vadimatamanenko/what-is-code-quality-how-to-improve-it-and-why-sometimes-good-code-is-bad-2dak</guid>
      <description>&lt;h2&gt;
  
  
  What is code quality, how to improve it, and why sometimes good code is bad.
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--K_n_0SrI--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/azms1vwpayexgtczhlov.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--K_n_0SrI--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/azms1vwpayexgtczhlov.jpg" alt="vlada_maestro / shutterstock" width="880" height="301"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Bad code is like bad repair. It can work and even works, but it’s bad and not for long, it looks so-so and it’s not easy to fix something in it. It is chaotic, has an incomprehensible structure, and you won’t immediately understand what the author wanted to say.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--54FIHpph--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/rs5w79aqtakkrjytbb3n.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--54FIHpph--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/rs5w79aqtakkrjytbb3n.jpeg" alt="I will not write any more bad code" width="800" height="604"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Signs of poor quality code:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;it is difficult to navigate in it;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;parts that can be written in two lines are written in ten;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;by the name of the function it is impossible to understand what it does (xyz, function, n);&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;if you add something to it, the rest will stop working.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What threatens a project with bad code
&lt;/h2&gt;

&lt;p&gt;At first glance, bad code is not a disaster. The program works, isn't that the main thing? In fact, it brings many problems, especially in the long run. And that's why:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;making changes to low-quality code takes a lot of time and is expensive, and over time, the price and duration only increase;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;adding something new is also difficult;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;code is unpredictable - you never know what will stop working and when;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;team spirit falls if people have to work with such masterpieces ("Who wrote this at all?!").&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;As a result, the development speed is reduced, the timeline is lengthened, and the cost of changes is growing. If this is critical for the consumer or customer, then bad code can bury the project.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to write good code
&lt;/h2&gt;

&lt;p&gt;To write quality code, you need to know what it is. Here are its main qualities:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;the code is easy to read, it has a clear structure, there is no confusion in it;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;it is easily maintained: small changes do not cause a desire to write it again;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;it can be expanded;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;the code has been tested;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;it is documented;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;productive.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--hMhbF0lS--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/800zkgqr5ruiq614zvrx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--hMhbF0lS--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/800zkgqr5ruiq614zvrx.png" alt="Comments in code" width="880" height="636"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Comments are really very important to make the code easy to read. This will not only help other programmers when they work on your code, but also you in the future.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Here are five actions that improve the code.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Follow coding standards.&lt;/strong&gt; This is one of the simplest and most important guidelines - when you agree with colleagues in advance how to format the code and how to act in some situations. Then the code written by different programmers will be visually similar: it will be easier for you to work with someone else's code, and vice versa. There are also generally accepted coding standards and even programming platforms that will tell you how to follow these standards. This is important both when working in a team and if you write code alone.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Refactoring.&lt;/strong&gt; This is a reworking of the program code without changing its behavior. That is, first you have a creative process: you write so that the program works, and then you “clean up after yourself”, put the code in order, to the desired look. As a bonus, refactoring helps to rethink the architectural decisions of the program.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Typing.&lt;/strong&gt; Let's explain with a real example. Players wrote to the developers of one game about problems, and then suddenly stopped. At first, the developers were delighted: everything is so cool that there are no problems. Later it turned out that the username had changed to a nickname in the game, and because of this, the feedback form stopped working: complaints were simply not sent. Typing (declaring a data type) will help avoid such errors and simplify maintenance and refactoring.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. Code review.&lt;/strong&gt; This is when you and a colleague check each other's code and give each other feedback. This practice helps to avoid stupid mistakes and thoughtlessness. In addition (and this is also important), you are aware of what the other person is doing, and you do not have to duplicate functions. A wonderful bonus - this method will help to gently adapt beginners.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5. Automatic tests&lt;/strong&gt; we will talk about them in a little more detail. These are simple programs that run code with different parameters and check against already known results. What are the tests?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Unit test individual parts of the program.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;e2e test the system as a whole.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Loaders check how well the program handles loads.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Screenshots compare before and after screenshots and react to changes.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Others: mutational, penetration…&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--tupHC76A--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/42elywlq6pjldytoun38.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--tupHC76A--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/42elywlq6pjldytoun38.png" alt="Is my code bad?" width="640" height="800"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;With tests, you really need to be careful so that it doesn’t turn out that you spend hours looking for an error in the code, but the problem is in the tests themselves. Therefore, it is useful to write tests first, and then take on the code itself, when you have a clear structure and understanding in your head of what needs to be done and what you want to get.&lt;/p&gt;

&lt;p&gt;There are other ways to improve the code (for example, pair programming). The best results can be obtained if you use several methods at once: this is more reliable.&lt;/p&gt;

&lt;h2&gt;
  
  
  When good code is bad
&lt;/h2&gt;

&lt;p&gt;We've been talking so much about how important quality code is now, and now we're saying the opposite? Yes. Sometimes good, "correct" code isn't all that great.&lt;br&gt;
The reason is very simple: in programming, unfortunately, you have to choose between quality and speed of work, and in some cases speed is more important.&lt;/p&gt;

&lt;p&gt;To understand how important speed is, imagine two developers: John and Steve. One is thorough, pedantic, and the second is its complete opposite. Both came up with the idea to make some kind of product. John sat down, came up with the architecture and started to do it well and slowly. And has been doing it for six months now. Steve did everything in a month, with errors, bugs - but immediately launched it, found customers, made the second release... As a result, six months later, when John had just completed his wonderful product, Steve already has many users and the name of the product is already well known. And he fixed some of the bugs in the second release.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Moral of the story:&lt;/strong&gt; sometimes it's more important to get to the market faster and occupy a niche than to do it perfectly.&lt;/p&gt;

&lt;p&gt;How then to be? Bad code is bad, good code is not always good either ... The point is this:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Code quality is a parameter that &lt;br&gt;
we change depending on the goal.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If you are writing an application for a bank, then you will spend a lot of time testing and developing, because a mistake can cost hundreds of thousands of dollars.&lt;/p&gt;

&lt;p&gt;If you are making a landing page that simply tells about a temporary promotion and collects emails into a database, then speed is already important here. You know that once the promotion ends, your code will no longer be needed. There is no need to refine and maintain it, and other developers will not use it either - it is enough to write quickly and check that it works, the rest is not important.&lt;/p&gt;

&lt;p&gt;These are the basic principles of creating quality code: do not forget about standards, look back at what you have already written, do not be afraid of feedback from colleagues and do not forget to test. But at the very beginning, it is worth weighing: quality is important to you now, or you need to finish development as soon as possible.&lt;/p&gt;

</description>
      <category>discuss</category>
      <category>programming</category>
      <category>startup</category>
      <category>computerscience</category>
    </item>
  </channel>
</rss>
