<?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: Kamil Wysocki</title>
    <description>The latest articles on DEV Community by Kamil Wysocki (@kamwysoc).</description>
    <link>https://dev.to/kamwysoc</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%2F39601%2F5a04060c-1f9a-45b5-a25b-9032b9fb465b.jpg</url>
      <title>DEV Community: Kamil Wysocki</title>
      <link>https://dev.to/kamwysoc</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/kamwysoc"/>
    <language>en</language>
    <item>
      <title>What's new in Swift 4.2 - my summary</title>
      <dc:creator>Kamil Wysocki</dc:creator>
      <pubDate>Wed, 06 Jun 2018 21:24:03 +0000</pubDate>
      <link>https://dev.to/kamwysoc/whats-new-in-swift-42---my-summary-31e</link>
      <guid>https://dev.to/kamwysoc/whats-new-in-swift-42---my-summary-31e</guid>
      <description>&lt;p&gt;I just have watched the What's new in Swift from WWDC 2018 and I thought it is a great motivation to write a blog post about this talk and summarize what I learned.&lt;/p&gt;

&lt;p&gt;And here are some new Swift 4.2 features that I really liked. &lt;/p&gt;

&lt;p&gt;Hope you will enjoy! 🤓&lt;/p&gt;

&lt;h2&gt;
  
  
  👉 SE-0194 Derived Collection of Enum Cases
&lt;/h2&gt;

&lt;p&gt;In case we need to print all available enum values, we had to create some helper variable that includes all enum cases. For example, a static array called &lt;code&gt;allCases&lt;/code&gt;. A big drawback in that approach is that we need to remember to update the &lt;code&gt;allCases&lt;/code&gt; array every time when we modify enum cases.&lt;/p&gt;

&lt;p&gt;Swift 4.1 approach:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;enum&lt;/span&gt; &lt;span class="kt"&gt;CarType&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="n"&gt;sedan&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="n"&gt;crossover&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="n"&gt;hothatch&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="n"&gt;muscle&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="n"&gt;miniVan&lt;/span&gt;

    &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;allCases&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sedan&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;crossover&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;hothatch&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;muscle&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;miniVan&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;in Swift 4.2 we can work with &lt;code&gt;CaseIterable&lt;/code&gt; protocol which does all the work for us! Please take a look at the below example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="c1"&gt;// CaseIterable protocol gave us a `allCases` variable, which is an array of all cases in the Enum.&lt;/span&gt;

&lt;span class="kd"&gt;enum&lt;/span&gt; &lt;span class="kt"&gt;CarType&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;CaseIterable&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="n"&gt;sedan&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="n"&gt;crossover&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="n"&gt;hothatch&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="n"&gt;muscle&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="n"&gt;miniVan&lt;/span&gt;

    &lt;span class="c1"&gt;//there is no need to add `allCases` variable. `CaseIterable` protocol do the job!&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;type&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="kt"&gt;CarType&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;allCases&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;type&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  👉 Conditional Conformance
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;arrayOfArrays&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;],[&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;],[&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;]]&lt;/span&gt;

&lt;span class="n"&gt;arrayOfArrays&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;contains&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="c1"&gt;// return false in Swift 4.1&lt;/span&gt;

&lt;span class="n"&gt;arrayOfArrays&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;contains&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="c1"&gt;// now it returns True because of fact that the elements in the array conforms to Equatable protocol&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It will work with &lt;code&gt;Optional&lt;/code&gt;, &lt;code&gt;Dictionary&lt;/code&gt; types as well.&lt;br&gt;
The conditional conformance works in the same way with &lt;code&gt;Hashable&lt;/code&gt;, &lt;code&gt;Encodable&lt;/code&gt; and &lt;code&gt;Decodable&lt;/code&gt; protocols.&lt;br&gt;
So for example, because &lt;code&gt;Int&lt;/code&gt; is &lt;code&gt;Hashable&lt;/code&gt;, which means in that case that &lt;code&gt;Int?&lt;/code&gt; is &lt;code&gt;Hashable&lt;/code&gt; too, and as a result the &lt;code&gt;[Int?]&lt;/code&gt; is &lt;code&gt;Hashable&lt;/code&gt; as well!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;s&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Set&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;?]&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;]]&lt;/span&gt;
&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;contains&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="c1"&gt;// returns true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  👉 Bool toggle
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;isTheWeatherNice&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Bool&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;isTheWeatherNice&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// prints true&lt;/span&gt;
&lt;span class="c1"&gt;//now it's starts raining&lt;/span&gt;
&lt;span class="n"&gt;isTheWeatherNice&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toggle&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="c1"&gt;// it will change the bool value.&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;isTheWeatherNice&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// prints false&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Small, but in my opinion -  very nice feature. I meet that extension for the first time while reading &lt;a href="https://www.objc.io/blog/2018/01/16/toggle-extension-on-bool/"&gt;that objc.io blog posts&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Now it's built into Swift 4.2. 🎉&lt;/p&gt;

&lt;h2&gt;
  
  
  👉 Hashable protocol
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;protocol&lt;/span&gt; &lt;span class="kt"&gt;Hashable&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;hash&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;into&lt;/span&gt; &lt;span class="nv"&gt;hasher&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;inout&lt;/span&gt; &lt;span class="kt"&gt;Hasher&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In Swift 4.2 we don't have to provide custom algorithms for &lt;code&gt;hashValue&lt;/code&gt;. Now swift handles a hash method quality with run performance. &lt;br&gt;
Important thing is that the &lt;code&gt;hashValue&lt;/code&gt; use the random per-process seed which is created at the every app starts.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;struct&lt;/span&gt; &lt;span class="kt"&gt;City&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Hashable&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;name&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;state&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;population&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="kd"&gt;extension&lt;/span&gt; &lt;span class="kt"&gt;City&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Hashable&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;hash&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;into&lt;/span&gt; &lt;span class="nv"&gt;hasher&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;inout&lt;/span&gt; &lt;span class="kt"&gt;Hasher&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;hash&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;into&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;hasher&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;hash&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;into&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;hasher&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;warsaw&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;City&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;name&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"Warsaw"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;state&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"Mazowieckie"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;warsaw&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;hashValue&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// will print hash value, using the Swift algorithms from hash function.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;⚠️&lt;br&gt;
In that approach, you should change the code that relates to the &lt;code&gt;hashValue&lt;/code&gt; as a constant. In every application run, the hash value will be different.&lt;br&gt;
⚠️&lt;/p&gt;
&lt;h2&gt;
  
  
  👉 SE-0202 Random Unification
&lt;/h2&gt;

&lt;p&gt;Swift 4.1 approach:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;randomIntFrom1to10&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;arc4random&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// return random number is the 1...6&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But in Swift 4.2 there is no need to use &lt;code&gt;arc4random()&lt;/code&gt; anymore. 🎉&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;randomIntFrom0To20&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;Int&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;random&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;in&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="o"&gt;..&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;randomFloat&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;Float&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;random&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;in&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="o"&gt;..&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Super cool thing is that we can get a random value from Collection types like &lt;code&gt;Array&lt;/code&gt; or &lt;code&gt;Dictionary&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;names&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"John"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Paul"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Peter"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Tim"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="n"&gt;names&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;randomElement&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt; 

&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;playerNumberToName&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;9&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"Lewandowski"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"Ronaldo"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="n"&gt;playerNumberToName&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;randomElement&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt; 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you might notice, the &lt;code&gt;randomElement&lt;/code&gt; function returns an Optional, because of the case where we call this function on the empty collection.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;emptyCollection&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
&lt;span class="n"&gt;emptyCollection&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;randomElement&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="c1"&gt;// retuns nil&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Another new function are &lt;code&gt;shuffle&lt;/code&gt; or &lt;code&gt;shuffled&lt;/code&gt; functions.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;names&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"John"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Paul"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Peter"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Tim"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;shuffledNames&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;names&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;shuffled&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="c1"&gt;// returns an array of names in shuffled order.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  👉 Conclusion
&lt;/h2&gt;

&lt;p&gt;It would be great to use those features in stable versions. My impressions from Xcode 10(beta) and Swift 4.2 was pretty amazing. I highly recommend you to watch What's new in Swift talk from WWDC 2018&lt;/p&gt;

&lt;p&gt;Below you can find a link to a GitHub gist with all features described above.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://gist.github.com/kamwysoc/e9322c84fd4fa051cb747ec08193dc0d"&gt;https://gist.github.com/kamwysoc/e9322c84fd4fa051cb747ec08193dc0d&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Source
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://developer.apple.com/videos/play/wwdc2018/401/"&gt;https://developer.apple.com/videos/play/wwdc2018/401/&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://swift.org/documentation/"&gt;https://swift.org/documentation/&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>ios</category>
      <category>swift</category>
      <category>wwdc</category>
    </item>
    <item>
      <title>Slack + Fastlane = ❤️. Talk about one of puzzles of Continuous Integration.</title>
      <dc:creator>Kamil Wysocki</dc:creator>
      <pubDate>Tue, 31 Oct 2017 17:52:50 +0000</pubDate>
      <link>https://dev.to/kamwysoc/slack--fastlane---talk-about-one-of-puzzles-of-continuous-integration-4l9</link>
      <guid>https://dev.to/kamwysoc/slack--fastlane---talk-about-one-of-puzzles-of-continuous-integration-4l9</guid>
      <description>

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--YU3DFIul--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://wysockikamil.com/assets/posts/slack-fastlane/puzzle.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--YU3DFIul--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://wysockikamil.com/assets/posts/slack-fastlane/puzzle.jpg" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Professional development process consists of many puzzles. Some of these puzzles can be: unit testing, choosing good architecture, clean code, continuous integration and many  more.&lt;br&gt;
In this post I will focus on one of these puzzles - Continuous Integration(CI). An integral part of CI in iOS Development process is a great tool called &lt;a href="https://fastlane.tools/"&gt;Fastlane&lt;/a&gt;.&lt;br&gt;
Fastlane is a powerful engine which handles a number of tasks like: dealing with code signing, creating &lt;code&gt;.ipa&lt;/code&gt; files, generating screenshots to AppStore and much more. One of the cool feature of Fastlane is the Slack integration - and this is what I wanted to write about.&lt;/p&gt;

&lt;h1&gt;
  
  
  💪 Motivation 💪
&lt;/h1&gt;

&lt;p&gt;At Bright Inventions, I'm working on a few projects. Every project that we start, we start with a few basic steps: create a new repository, basic application setup and most important... Continuous Integration path. On iOS applications, it starts with  installing the Fastlane, creating some lanes in Fastfile, then pushing changes to our new repository. Next step is configuring a new TeamCity(a service that we are using for CI) with a new agent machine for the project. And after that... our CI build service is ready to collect changes from the repository and trigger a build for our clients, or just build the application and run our unit/UI tests to check if everything works fine.&lt;/p&gt;

&lt;p&gt;But what if something went wrong...&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--7hdcJIWV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://wysockikamil.com/assets/posts/slack-fastlane/error.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--7hdcJIWV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://wysockikamil.com/assets/posts/slack-fastlane/error.jpg" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let's say that we were doing some code refactoring, we committed the changes and pushed into our repository. Next, our build system discovered that there were  available new commits - so it started to fetch and built them and ran unit tests. And here some tests failed.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--PrnJwigy--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://wysockikamil.com/assets/posts/slack-fastlane/test-failed.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--PrnJwigy--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://wysockikamil.com/assets/posts/slack-fastlane/test-failed.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Of course, I don't have constantly an opened browser to check on the Teamcity site if everything goes  well when I push something to the repository. I want to be informed if something goes wrong like - if  unit tests fails or timeout appears or compilation error happens. And here is the key word - INFORMED. How our build agent can inform us about an occurred error?&lt;/p&gt;

&lt;h3&gt;
  
  
  Emails
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Z5lle1NR--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://wysockikamil.com/assets/posts/slack-fastlane/email.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Z5lle1NR--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://wysockikamil.com/assets/posts/slack-fastlane/email.jpeg" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We use email service which is built-in into TeamCity. Every built lane has a rule which says 'send email to all developers when something goes wrong and build fails'. This solution works fine and it's commonly used in many projects and companies. But personally, I'm not 100% satisfied with it. If you work in several projects, you get more and more emails from clients, Jira, team etc. And let's add to that getting new emails from our TeamCity service. Of course, I can create filters and group all the  stuff(which I do), but even then it's too much for me. Besides, there is a new thing - if some builds fail - in most cases, it is important to &lt;strong&gt;fix it quick&lt;/strong&gt;. So I prefer another - quicker in my opinion - way to be notified if something bad happens.&lt;/p&gt;

&lt;h1&gt;
  
  
  ❤️ Fastlane + Slack ❤️
&lt;/h1&gt;

&lt;h2&gt;
  
  
  1. Create your Fastfile in right way
&lt;/h2&gt;

&lt;p&gt;Let's consider a simple example. One lane which compiles the project and runs the unit tests:&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;platform :ios do
    desc "Runs all the tests"
    lane :test do
        begin
            test_lane()
        rescue =&amp;gt; exception
            on_error(exception)
        end
    end
end
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;As you can see the body of &lt;code&gt;:test&lt;/code&gt; lane consists of &lt;code&gt;begin-rescue-end&lt;/code&gt; structure. It is a ruby specific construction. In &lt;code&gt;begin&lt;/code&gt; you put some code that may fail. After the &lt;code&gt;rescue =&amp;gt; exception&lt;/code&gt; line you put the code that should be executed if something goes wrong. In our case, it will be &lt;code&gt;on_error(exception)&lt;/code&gt; function. So the Fastfile should look like this:&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;platform&lt;/span&gt; &lt;span class="ss"&gt;:ios&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
   &lt;span class="n"&gt;desc&lt;/span&gt; &lt;span class="s2"&gt;"Runs all the tests"&lt;/span&gt;
   &lt;span class="n"&gt;lane&lt;/span&gt; &lt;span class="ss"&gt;:test&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
       &lt;span class="k"&gt;begin&lt;/span&gt;
           &lt;span class="n"&gt;test_lane&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
       &lt;span class="k"&gt;rescue&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;exception&lt;/span&gt;
           &lt;span class="n"&gt;on_error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;exception&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
       &lt;span class="k"&gt;end&lt;/span&gt;
   &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="c1"&gt;### Methods&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;test_lane&lt;/span&gt;
   &lt;span class="n"&gt;cocoapods&lt;/span&gt;
   &lt;span class="n"&gt;clear_derived_data&lt;/span&gt;
   &lt;span class="nb"&gt;scan&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;scheme: &lt;/span&gt;&lt;span class="s2"&gt;"YourProjectSchemeName"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;configuration: &lt;/span&gt;&lt;span class="s2"&gt;"Debug"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;on_error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;exception&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
   &lt;span class="n"&gt;slack&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
       &lt;span class="ss"&gt;message: &lt;/span&gt;&lt;span class="s2"&gt;"Some thing goes wrong"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
       &lt;span class="ss"&gt;success: &lt;/span&gt;&lt;span class="kp"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
       &lt;span class="ss"&gt;slack_url: &lt;/span&gt;&lt;span class="s2"&gt;"https://your slack incoming webhook url"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
       &lt;span class="ss"&gt;attachment_properties: &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
           &lt;span class="ss"&gt;fields: &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;
               &lt;span class="p"&gt;{&lt;/span&gt;
                   &lt;span class="ss"&gt;title: &lt;/span&gt;&lt;span class="s2"&gt;"Build number"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                   &lt;span class="ss"&gt;value: &lt;/span&gt;&lt;span class="no"&gt;ENV&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"BUILD_NUMBER"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
               &lt;span class="p"&gt;},&lt;/span&gt;
               &lt;span class="p"&gt;{&lt;/span&gt;
                   &lt;span class="ss"&gt;title: &lt;/span&gt;&lt;span class="s2"&gt;"Error message"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                   &lt;span class="ss"&gt;value: &lt;/span&gt;&lt;span class="n"&gt;exception&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;to_s&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                   &lt;span class="ss"&gt;short: &lt;/span&gt;&lt;span class="kp"&gt;false&lt;/span&gt;
               &lt;span class="p"&gt;}&lt;/span&gt;
           &lt;span class="p"&gt;]&lt;/span&gt;
       &lt;span class="p"&gt;}&lt;/span&gt;
   &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  2. Generate slack URL
&lt;/h2&gt;

&lt;p&gt;As you probably have noticed &lt;code&gt;slack&lt;/code&gt; method takes a &lt;code&gt;slack_url&lt;/code&gt; parameter. But how can I get one?&lt;/p&gt;

&lt;h3&gt;
  
  
  Create incoming webhook
&lt;/h3&gt;

&lt;p&gt;Go to &lt;a href="https://my.slack.com/services/new/incoming-webhook/"&gt;slack incoming weebhook webiste&lt;/a&gt;, log in, and after that you will be able too see screen like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--zOHZ5vqB--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://wysockikamil.com/assets/posts/slack-fastlane/webhook-slack-url.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--zOHZ5vqB--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://wysockikamil.com/assets/posts/slack-fastlane/webhook-slack-url.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Choose your channel (for test purposes, I recommend choosing a direct message to yourself). Click &lt;code&gt;Add incoming WebHooks integration&lt;/code&gt;.&lt;br&gt;
Next step is to copy the Webhook URL and use it as &lt;code&gt;slack_url&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Of course, after you learn how it works, you can generate a URL for specially created Channel in your slack team.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Y1ezc2vf--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://wysockikamil.com/assets/posts/slack-fastlane/webhook-slack-url2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Y1ezc2vf--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://wysockikamil.com/assets/posts/slack-fastlane/webhook-slack-url2.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Build Slack message in Fastfile
&lt;/h2&gt;

&lt;p&gt;First of all, &lt;a href="https://docs.fastlane.tools/actions/slack/"&gt;here&lt;/a&gt; you can find an official documentation for Slack action in Fastlane tool. In the below  section I'll try to give you a closer look at that.&lt;/p&gt;

&lt;p&gt;Code for that is really simple. Let's create a simple &lt;code&gt;slack_message&lt;/code&gt; lane to test how it works.&lt;br&gt;
Put a new lane in you Fastfile, and then just run:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;fastlane slack_message&lt;/code&gt;,&lt;/p&gt;

&lt;p&gt;or if you are using a bundler&lt;/p&gt;

&lt;p&gt;&lt;code&gt;bundle exec fastlane slack_message&lt;/code&gt;.&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;platform&lt;/span&gt; &lt;span class="ss"&gt;:ios&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
   &lt;span class="n"&gt;desc&lt;/span&gt; &lt;span class="s2"&gt;"Runs all the tests"&lt;/span&gt;
   &lt;span class="n"&gt;lane&lt;/span&gt; &lt;span class="ss"&gt;:slack_message&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
       &lt;span class="n"&gt;slack&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
           &lt;span class="ss"&gt;message: &lt;/span&gt;&lt;span class="s2"&gt;"App successfully uploaded to iTunesConnect."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
           &lt;span class="ss"&gt;success: &lt;/span&gt;&lt;span class="kp"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
           &lt;span class="ss"&gt;slack_url: &lt;/span&gt;&lt;span class="s2"&gt;"https://your slack incoming webhook url"&lt;/span&gt;
       &lt;span class="p"&gt;)&lt;/span&gt;
   &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;This is how our message looks like:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--M2XTyVE7--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://wysockikamil.com/assets/posts/slack-fastlane/basic-message.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--M2XTyVE7--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://wysockikamil.com/assets/posts/slack-fastlane/basic-message.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As you can see by default you get some information about &lt;code&gt;Git Commit&lt;/code&gt;, &lt;code&gt;Git Commit Hash&lt;/code&gt;, &lt;code&gt;Lane&lt;/code&gt;, &lt;code&gt;Result&lt;/code&gt;, &lt;code&gt;Git Author&lt;/code&gt;.&lt;/p&gt;

&lt;h1&gt;
  
  
  🔧 Customizing slack message 🔧
&lt;/h1&gt;

&lt;h4&gt;
  
  
  👉 &lt;code&gt;message&lt;/code&gt;
&lt;/h4&gt;

&lt;p&gt;Simple key for creating a message which will be display in a first row in Slack message. This can be literally everything.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;message: "App Successfully uploaded to iTunesConnect"&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;message: "All tests have been successful"&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;message: "Something went wrong"&lt;/code&gt; - My favorite error message 😉&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;but try to make your Slack message useful. As you can see above in my &lt;code&gt;Fastfile&lt;/code&gt; I use a &lt;code&gt;begin-rescue&lt;/code&gt; construction in Ruby. It is very useful because you can use an exception passed as a parameter to and create some meaningful error message.&lt;/p&gt;

&lt;p&gt;I assume that all of you use and know &lt;a href="https://cocoapods.org/"&gt;CococaPods&lt;/a&gt;. Let's imagine situation that our &lt;code&gt;Podfile&lt;/code&gt; has a typo&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;platform&lt;/span&gt; &lt;span class="ss"&gt;:ios&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'10.0'&lt;/span&gt;
&lt;span class="n"&gt;inhibit_all_warnings!&lt;/span&gt;

&lt;span class="n"&gt;target&lt;/span&gt; &lt;span class="s1"&gt;'MyAppTarget'&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
 &lt;span class="n"&gt;use_frameworks!&lt;/span&gt;

 &lt;span class="c1"&gt;# Pods for MyApp&lt;/span&gt;
 &lt;span class="n"&gt;podd&lt;/span&gt; &lt;span class="s1"&gt;'SnapKit'&lt;/span&gt; &lt;span class="c1"&gt;# &amp;lt;------- should fail because of `podd`&lt;/span&gt;
 &lt;span class="n"&gt;pod&lt;/span&gt; &lt;span class="s1"&gt;'Result'&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Now create a lane in our &lt;code&gt;Fastfile&lt;/code&gt; that will install our CocoaPods, and build the project.&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;fastlane_version&lt;/span&gt; &lt;span class="s2"&gt;"2.54.1"&lt;/span&gt;

&lt;span class="n"&gt;default_platform&lt;/span&gt; &lt;span class="ss"&gt;:ios&lt;/span&gt;

&lt;span class="n"&gt;xcode_select&lt;/span&gt; &lt;span class="no"&gt;ENV&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"XCODE_PATH"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="n"&gt;platform&lt;/span&gt; &lt;span class="ss"&gt;:ios&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
   &lt;span class="n"&gt;desc&lt;/span&gt; &lt;span class="s2"&gt;"Runs all the tests"&lt;/span&gt;
   &lt;span class="n"&gt;lane&lt;/span&gt; &lt;span class="ss"&gt;:build_and_test&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
       &lt;span class="k"&gt;begin&lt;/span&gt;
           &lt;span class="n"&gt;build_and_test_lane&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
       &lt;span class="k"&gt;rescue&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;exception&lt;/span&gt;
           &lt;span class="n"&gt;on_error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;exception&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
       &lt;span class="k"&gt;end&lt;/span&gt;
   &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;build_and_test_lane&lt;/span&gt;
   &lt;span class="n"&gt;cocoapods&lt;/span&gt;
   &lt;span class="n"&gt;clear_derived_data&lt;/span&gt;
   &lt;span class="nb"&gt;scan&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;scheme: &lt;/span&gt;&lt;span class="s2"&gt;"MyAppScheme"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;configuration: &lt;/span&gt;&lt;span class="s2"&gt;"Debug"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;on_error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;exception&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
       &lt;span class="n"&gt;slack&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
           &lt;span class="ss"&gt;message: &lt;/span&gt;&lt;span class="s2"&gt;"Lane failed with exception : &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;exception&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
           &lt;span class="ss"&gt;success: &lt;/span&gt;&lt;span class="kp"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
           &lt;span class="ss"&gt;slack_url: &lt;/span&gt;&lt;span class="s2"&gt;"https://slackurl"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
       &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;As you can see if something goes  wrong in &lt;code&gt;build_and_test_lane&lt;/code&gt; method our script will get an &lt;code&gt;exception&lt;/code&gt; and run the &lt;code&gt;on_error(exception)&lt;/code&gt; method.&lt;br&gt;
Let's try it by...&lt;/p&gt;

&lt;p&gt;&lt;code&gt;fastlane build_and_test&lt;/code&gt; or &lt;code&gt;bundle exec fastlane build_and_test&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;wait some time.... and...🔔 🔔&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--a3_LPRma--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://wysockikamil.com/assets/posts/slack-fastlane/exception.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--a3_LPRma--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://wysockikamil.com/assets/posts/slack-fastlane/exception.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now our message is meaningful and we know that our &lt;code&gt;Podfile&lt;/code&gt; has some errors.&lt;/p&gt;

&lt;h4&gt;
  
  
  👉  &lt;code&gt;deafult_payloads&lt;/code&gt;
&lt;/h4&gt;

&lt;p&gt;As we can read in the documentation:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Don't add this key or pass nil if you want all the default payloads. The available default payloads are: &lt;code&gt;lane&lt;/code&gt;, &lt;code&gt;test_result&lt;/code&gt;, &lt;code&gt;git_branch&lt;/code&gt;, &lt;code&gt;git_author&lt;/code&gt;, &lt;code&gt;last_git_commit_message&lt;/code&gt;, &lt;code&gt;last_git_commit_hash&lt;/code&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Personally, I think it is very important information, but if you want to customize the message by removing some of those - you can look at this example:&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;slack&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
   &lt;span class="ss"&gt;message: &lt;/span&gt;&lt;span class="s2"&gt;"App successfully uploaded to iTunesConnect."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
   &lt;span class="ss"&gt;success: &lt;/span&gt;&lt;span class="kp"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
   &lt;span class="ss"&gt;slack_url: &lt;/span&gt;&lt;span class="s2"&gt;"https://your slack incoming webhook url"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
   &lt;span class="ss"&gt;default_payloads: &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:git_branch&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:last_git_commit_message&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Here is how a message with customized &lt;code&gt;default_payloads&lt;/code&gt; looks like:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--_bKVSGl---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://wysockikamil.com/assets/posts/slack-fastlane/default-payload-message.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--_bKVSGl---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://wysockikamil.com/assets/posts/slack-fastlane/default-payload-message.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  👉  &lt;code&gt;success&lt;/code&gt;
&lt;/h4&gt;

&lt;p&gt;You can also define if that message will be successful or not. Among other cases, success messages can be used if your app is successfully uploaded to iTunesConnect.&lt;/p&gt;

&lt;p&gt;Second option is to set &lt;code&gt;success&lt;/code&gt; to &lt;code&gt;false&lt;/code&gt;, and then a message will look a bit different:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--4wnH1Bhs--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://wysockikamil.com/assets/posts/slack-fastlane/message-fail.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--4wnH1Bhs--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://wysockikamil.com/assets/posts/slack-fastlane/message-fail.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The red color suggests that something went wrong and you have to fix it, which is a great way to notify you about it.&lt;/p&gt;

&lt;h4&gt;
  
  
  👉  &lt;code&gt;attachment_properties&lt;/code&gt;
&lt;/h4&gt;

&lt;p&gt;Here  a real customizing process begins. By using this property you can add any field to your Slack message. Let's say that you want to add &lt;code&gt;BUILD_NUMBER&lt;/code&gt; and &lt;code&gt;URL&lt;/code&gt; to artifacts.&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;slack&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
   &lt;span class="ss"&gt;message: &lt;/span&gt;&lt;span class="s2"&gt;"App successfully uploaded to iTunesConnect."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
   &lt;span class="ss"&gt;success: &lt;/span&gt;&lt;span class="kp"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
   &lt;span class="ss"&gt;slack_url: &lt;/span&gt;&lt;span class="s2"&gt;"https://your slack incoming webhook url"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
   &lt;span class="ss"&gt;default_payloads: &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:git_branch&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:last_git_commit_message&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
   &lt;span class="ss"&gt;attachment_properties: &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
       &lt;span class="ss"&gt;fields: &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;
           &lt;span class="p"&gt;{&lt;/span&gt;
               &lt;span class="ss"&gt;title: &lt;/span&gt;&lt;span class="s2"&gt;"Build number"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
               &lt;span class="ss"&gt;value: &lt;/span&gt;&lt;span class="no"&gt;ENV&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"BUILD_NUMBER"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
           &lt;span class="p"&gt;},&lt;/span&gt;
           &lt;span class="p"&gt;{&lt;/span&gt;
               &lt;span class="ss"&gt;title: &lt;/span&gt;&lt;span class="s2"&gt;"Artifacts URL"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
               &lt;span class="ss"&gt;value: &lt;/span&gt;&lt;span class="s2"&gt;"https://url-to-your-artifacts.com"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
           &lt;span class="p"&gt;}&lt;/span&gt;
       &lt;span class="p"&gt;]&lt;/span&gt;
   &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--sDW5DGxa--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://wysockikamil.com/assets/posts/slack-fastlane/message-with-custom-fields.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--sDW5DGxa--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://wysockikamil.com/assets/posts/slack-fastlane/message-with-custom-fields.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Another example... let's modify our &lt;code&gt;on_error(exception)&lt;/code&gt; method.&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;on_error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;exception&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
       &lt;span class="n"&gt;slack&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
           &lt;span class="ss"&gt;message: &lt;/span&gt;&lt;span class="s2"&gt;"Error occured!"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
           &lt;span class="ss"&gt;success: &lt;/span&gt;&lt;span class="kp"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
           &lt;span class="ss"&gt;slack_url: &lt;/span&gt;&lt;span class="s2"&gt;"https://slackurl"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
           &lt;span class="ss"&gt;attachment_properties: &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
               &lt;span class="ss"&gt;fields: &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;
                   &lt;span class="p"&gt;{&lt;/span&gt;
                       &lt;span class="ss"&gt;title: &lt;/span&gt;&lt;span class="s2"&gt;"Error message"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                       &lt;span class="ss"&gt;value: &lt;/span&gt;&lt;span class="n"&gt;exception&lt;/span&gt;
                   &lt;span class="p"&gt;}&lt;/span&gt;
               &lt;span class="p"&gt;]&lt;/span&gt;
           &lt;span class="p"&gt;}&lt;/span&gt;
       &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;and here we've got a message 🔔🔔&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--j4ktgaWM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://wysockikamil.com/assets/posts/slack-fastlane/exception2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--j4ktgaWM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://wysockikamil.com/assets/posts/slack-fastlane/exception2.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As you can see, now the error message is custom field.&lt;/p&gt;

&lt;h4&gt;
  
  
  👉  other flags...
&lt;/h4&gt;

&lt;p&gt;In this post I have focused, in my humble opinion, on the most important keys which allow you to configure  Slack message. The others are: &lt;code&gt;channel&lt;/code&gt;, &lt;code&gt;message&lt;/code&gt;, &lt;code&gt;use_webhook_configured_username_and_icon&lt;/code&gt;, &lt;code&gt;icon_url&lt;/code&gt;, &lt;code&gt;payload&lt;/code&gt;. More information about these keys you can find on &lt;a href="https://docs.fastlane.tools/actions/slack/"&gt;official documentation&lt;/a&gt;.&lt;/p&gt;

&lt;h1&gt;
  
  
  🎉 Conclusion 🎉
&lt;/h1&gt;

&lt;p&gt;I ❤️  Fastlane tool. It helps all developers to save a lot of time during development process. I think  one of the puzzles of this process is Continuous Integration &lt;strong&gt;&lt;em&gt;in the full sense of the word&lt;/em&gt;&lt;/strong&gt;. How do I understand the Continuous Integration? As you can read about it on &lt;a href="https://en.wikipedia.org/wiki/Continuous_integration"&gt;wikipedia&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;In software engineering, continuous integration (CI) is the practice of merging all developer working copies to a shared mainline several times a day.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It is 100% true, but for me, it is also a state when I as a developer can be notified by CI agent about successes and errors without specially checking them before pushing changes to the repository. But don't get me wrong. I don't recommend committing and pushing without compiling(because our CI agent inform us when something fails). I'm talking about a situation when you have a number of projects that contain a number of tests (Yes, I assume you're writing tests 😉). And I think you don't want to run them every time before you push new changes to the repository. That's why, you configure the whole CI stuff to avoid it. Let CI agent do it for you. In most cases all the tests will succeed 😉), so you can work continuously. But if somehow tests fail - let the CI agent ping you on a Slack 😉&lt;br&gt;
Another thing is that, you can be informed about good things like: successfully uploaded &lt;code&gt;.ipa&lt;/code&gt; to TestFlight.&lt;/p&gt;

&lt;p&gt;Below you can find all links that were used in this post.&lt;/p&gt;

&lt;p&gt;👉  &lt;a href="https://cocoapods.org"&gt;CocoaPods&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;👉  &lt;a href="https://fastlane.tools/"&gt;Fastlane&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;👉  &lt;a href="https://api.slack.com/incoming-webhooks"&gt;Slack incoming webhooks&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;👉  &lt;a href="https://docs.fastlane.tools/actions/slack/"&gt;Fastlane Slack action&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;👉  &lt;a href="https://www.google.com/search?q=continuous+integration"&gt;Continuous Integration&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;👉  &lt;a href="https://www.jetbrains.com/teamcity/"&gt;TeamCity&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This post was primarly posted on my company &lt;a href="https://brightinventions.pl/blog/slack-fastlane/"&gt;blog&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  About me
&lt;/h2&gt;

&lt;p&gt;I’m software developer in Gdansk, Poland. Mostly working with iOS but I’m open minded for any other technologies, frameworks and challenges. If you like my post feel free to &lt;a href="https://twitter.com/kamwysoc"&gt;follow me on twitter&lt;/a&gt; and read &lt;a href="https://wysockikamil.com"&gt;my personal blog&lt;/a&gt;.&lt;/p&gt;


</description>
      <category>ios</category>
      <category>swift</category>
      <category>slack</category>
      <category>ci</category>
    </item>
  </channel>
</rss>
