<?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: Piotr Sochalewski</title>
    <description>The latest articles on DEV Community by Piotr Sochalewski (@sochalewski).</description>
    <link>https://dev.to/sochalewski</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%2F209461%2F38547e24-f236-4c83-a2b7-7ff8df76b2a6.jpeg</url>
      <title>DEV Community: Piotr Sochalewski</title>
      <link>https://dev.to/sochalewski</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/sochalewski"/>
    <language>en</language>
    <item>
      <title>Handling Enormous Collection Types in Swift</title>
      <dc:creator>Piotr Sochalewski</dc:creator>
      <pubDate>Wed, 14 Aug 2019 07:49:43 +0000</pubDate>
      <link>https://dev.to/netguru/handling-enormous-collection-types-in-swift-dfj</link>
      <guid>https://dev.to/netguru/handling-enormous-collection-types-in-swift-dfj</guid>
      <description>&lt;p&gt;Usually there is no difference when you choose Array or Set. You take Set if you want a collection type with unique unordered elements. But you do not care about performance or RAM usage, because they are often similar. Have you ever asked yourself what happens if your collection has to store almost 3 millions of elements like strings?&lt;/p&gt;

&lt;p&gt;I have, because I am an author of unofficial iOS Scrabble dictionary – &lt;a href="https://itunes.apple.com/us/app/scrabbdict/id687530221?mt=8"&gt;Scrabbdict&lt;/a&gt;. There is no problem with 3 of 4 available dictionaries: two English (SOWPODS and TWL) and French dictionaries are quite small, they contain from 178,691 to 386,264 words. Polish dictionary contains 2,964,259 words. And there is no simple solution to handle that big collection.&lt;/p&gt;

&lt;p&gt;It was my first iOS app and I wrote it in 2013 in Objective-C. I remember it was working perfectly on iOS simulator, but when I bought my first developer license it was crashing a lot on a real device, because of too high memory usage. I resolved it by splitting Polish dictionary into multiple files:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;a basic one that was persistent in memory and contained words up to eight characters,&lt;/li&gt;
&lt;li&gt;additional files where each contains words that has 9, 10, 11, 12, 13, 14 or 15 letters, loaded when necessary.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ySqhahg1--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.netguru.com/hs-fs/hubfs/scrabbdict_files.png%3Fwidth%3D300%26height%3D200%26name%3Dscrabbdict_files.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ySqhahg1--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.netguru.com/hs-fs/hubfs/scrabbdict_files.png%3Fwidth%3D300%26height%3D200%26name%3Dscrabbdict_files.png" alt="scrabbdict_files"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It was reasonable and really fast especially for short words. Furthermore memory usage was acceptable.&lt;/p&gt;

&lt;p&gt;I used Array and loading a dictionary was as simple as this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight objective_c"&gt;&lt;code&gt;&lt;span class="n"&gt;NSString&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;langCode&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;NSArray&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;dictArray&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;NSString&lt;/span&gt; &lt;span class="nf"&gt;stringWithContentsOfFile&lt;/span&gt;&lt;span class="p"&gt;:[[&lt;/span&gt;&lt;span class="n"&gt;NSBundle&lt;/span&gt; &lt;span class="nf"&gt;mainBundle&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="nf"&gt;pathForResource&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;langCode&lt;/span&gt; &lt;span class="nf"&gt;ofType&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s"&gt;@"txt"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="n"&gt;encoding&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;NSUTF8StringEncoding&lt;/span&gt; &lt;span class="n"&gt;error&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="nb"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="n"&gt;componentsSeparatedByCharactersInSet&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;NSCharacterSet&lt;/span&gt; &lt;span class="nf"&gt;whitespaceAndNewlineCharacterSet&lt;/span&gt;&lt;span class="p"&gt;]];&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;But handling this was inconvenient and limited possibilities.&lt;/p&gt;

&lt;p&gt;When working on 3.0 update I decided to implement more complex features like points for all words and simple regex (blanks) support. I knew that a key to this is better performance. Now I want to share with you different solutions to the problem and let you know what technique Scrabbdict actually uses.&lt;/p&gt;

&lt;h2&gt;
  
  
  Collection types
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Arrays&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Standard &lt;code&gt;Array&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;Array&lt;/code&gt; with reserved capacity that equals a count of strings&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;ContiguousArray&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;ContiguousArray&lt;/code&gt; with reserved capacity that equals a count of strings&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;CleverArray&lt;/code&gt; that is standard two-dimensional &lt;code&gt;Array&lt;/code&gt; where arrays inside contains words with letters count that equals an index of array&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Sets&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Standard &lt;code&gt;Set&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;CleverSet&lt;/code&gt; that is standard &lt;code&gt;Array&lt;/code&gt; of standard &lt;code&gt;Sets&lt;/code&gt; where sets inside contains words with letters count that equals an index of set&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Tries&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Modified &lt;code&gt;Trie&lt;/code&gt; from &lt;a href="https://github.com/mauriciosantos/Buckets-Swift"&gt;Buckets-Swift&lt;/a&gt; by Mauricio Santos&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Realm&lt;/strong&gt; database&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Standard &lt;code&gt;Realm&lt;/code&gt; database with &lt;code&gt;List&lt;/code&gt; of &lt;code&gt;StringObject&lt;/code&gt;s&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;CleverRealm&lt;/code&gt; database with multiple &lt;code&gt;Lists&lt;/code&gt; of &lt;code&gt;StringObject&lt;/code&gt;s where each list contains words with different letters count&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Standard vs clever collection
&lt;/h3&gt;

&lt;p&gt;To show the difference between "standard" and "clever" collection type objects I created this graphic:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ECdCDNSQ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.netguru.com/hs-fs/hubfs/standard-clever.png%3Fwidth%3D500%26height%3D300%26name%3Dstandard-clever.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ECdCDNSQ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.netguru.com/hs-fs/hubfs/standard-clever.png%3Fwidth%3D500%26height%3D300%26name%3Dstandard-clever.png" alt="standard-clever"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So when we discuss Array, then standard is &lt;code&gt;Array&amp;lt;String&amp;gt;&lt;/code&gt; and clever is &lt;code&gt;Array&amp;lt;Array&amp;lt;String&amp;gt;&amp;gt;&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Source code&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Disclaimer:&lt;/strong&gt; I am not going to post here all source code, but you can take a look at &lt;a href="https://github.com/netguru/swift-collections-performance"&gt;the repository&lt;/a&gt;, which I strongly advise!&lt;/p&gt;




&lt;p&gt;Each one of mentioned collection type implements &lt;code&gt;Validator&lt;/code&gt; protocol:&lt;br&gt;
&lt;/p&gt;

&lt;div class="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;Validator&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;init&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="c1"&gt;/// Returns a Boolean value indicating whether&lt;/span&gt;
    &lt;span class="c1"&gt;/// the Polish dictionary contains the given word.&lt;/span&gt;
    &lt;span class="c1"&gt;/// - parameter word: The word to validate.&lt;/span&gt;
    &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;validate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;word&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;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Bool&lt;/span&gt;

    &lt;span class="c1"&gt;/// Returns an array of words that can be made from the given letters.&lt;/span&gt;
    &lt;span class="c1"&gt;/// - parameter letters: The letters.&lt;/span&gt;
    &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;words&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;from&lt;/span&gt; &lt;span class="nv"&gt;letters&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;-&amp;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="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;More advanced collections (which equal &lt;em&gt;faster&lt;/em&gt;) implement &lt;code&gt;CleverValidator&lt;/code&gt;protocol, which allows the same, but it adds simple regex query.&lt;br&gt;
&lt;/p&gt;

&lt;div class="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;CleverValidator&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Validator&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="cm"&gt;/**
     Returns an array of words that fit the given regex query.

     An example of correct query:
     regex(phrase: "pr??lem") // ["preclem", "problem"]

     - parameter phrase: The simple regex query.
         Only letters and blanks (`?`) are allowed.
     */&lt;/span&gt;
    &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;regex&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;phrase&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;-&amp;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="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;I believe these are clear.&lt;/p&gt;

&lt;p&gt;Before I'll let you see the results, I'd like you to see the most basic validator class:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="c1"&gt;/// Simple word validator based on array of strings.&lt;/span&gt;
&lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="kt"&gt;ArrayWordValidator&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Validator&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="c1"&gt;/// An array of strings.&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;words&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="nf"&gt;init&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;string&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;try!&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;contentsOf&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;fileURL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;encoding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;utf8&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;words&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;components&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;separatedBy&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;newlines&lt;/span&gt;&lt;span class="p"&gt;)&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;validate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;word&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;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Bool&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;words&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="n"&gt;word&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;lowercased&lt;/span&gt;&lt;span class="p"&gt;())&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;words&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;from&lt;/span&gt; &lt;span class="nv"&gt;letters&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;-&amp;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="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;permutes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;letters&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;lowercased&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;map&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="nv"&gt;$0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;permute&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;predicate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;NSPredicate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;format&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"SELF IN %@"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;permutes&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;words&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;filter&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;predicate&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;evaluate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;with&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;$0&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;The initialization and validation function are self-explanatory. The function that returns words that can be made from given letters may be not.&lt;/p&gt;

&lt;p&gt;First, it gets all possible permutes from given letters. To make it faster minimum length of permute is 2 characters, because single letter words are not valid in Scrabble. Then, creates a somewhat forgotten &lt;code&gt;NSPredicate&lt;/code&gt;object. You may ask why and that is a very good question.&lt;/p&gt;

&lt;p&gt;The same result can be achieved in at least two ways here:&lt;br&gt;
&lt;/p&gt;

&lt;div class="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;a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;permutes&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;filter&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;words&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="nv"&gt;$0&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;b&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;words&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;filter&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;predicate&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;evaluate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;with&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;$0&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;Unfortunately the first solution is extremely slow. When permutes counts 86 strings (that happens for five letters query) and the first solution is used, it takes around 170 seconds to return results. The latter solution needs less than eight seconds (sic!). The more permutes, the difference is bigger.&lt;/p&gt;

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

&lt;p&gt;I'd like to present you results of multiple performance tests for different collection types.&lt;/p&gt;

&lt;p&gt;Let's start from something simple, but important…&lt;/p&gt;

&lt;h3&gt;
  
  
  Initialization time
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--zVQqqe4B--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.netguru.com/hs-fs/hubfs/init.png%3Fwidth%3D400%26height%3D400%26name%3Dinit.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--zVQqqe4B--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.netguru.com/hs-fs/hubfs/init.png%3Fwidth%3D400%26height%3D400%26name%3Dinit.png" alt="init"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;There is no big difference between the first four arrays, but &lt;code&gt;CleverSet&lt;/code&gt; and &lt;code&gt;Trie&lt;/code&gt; initialization time is simply unacceptable. Both &lt;code&gt;Realm&lt;/code&gt; and &lt;code&gt;CleverRealm&lt;/code&gt; initialization time is unnoticeable, because of Realm laziness.&lt;/p&gt;

&lt;h3&gt;
  
  
  Word validation
&lt;/h3&gt;

&lt;p&gt;Just simple word validation – the result is a boolean value that determines if a word is correct or not. Each validator validates 15 words one by one in this test.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--PURO1RcH--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.netguru.com/hs-fs/hubfs/search.png%3Fwidth%3D450%26height%3D450%26name%3Dsearch.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--PURO1RcH--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.netguru.com/hs-fs/hubfs/search.png%3Fwidth%3D450%26height%3D450%26name%3Dsearch.png" alt="search"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Again, there is no big difference between the first four arrays. Sets and trie are extremely fast. Set because of object uniqueness and trie because of its structure. Standard arrays are simply slowest, but clever objects look really good. Especially &lt;code&gt;CleverRealm&lt;/code&gt; when count init time in.&lt;/p&gt;

&lt;h3&gt;
  
  
  Words made from given letters
&lt;/h3&gt;

&lt;p&gt;That's really interesting!&lt;/p&gt;

&lt;p&gt;Imagine that I give letters &lt;em&gt;I&lt;/em&gt;, &lt;em&gt;T&lt;/em&gt; and &lt;em&gt;L&lt;/em&gt;, and expect words that can be made from them. So &lt;em&gt;lit&lt;/em&gt;, &lt;em&gt;til&lt;/em&gt;, &lt;em&gt;it&lt;/em&gt;, &lt;em&gt;li&lt;/em&gt; and &lt;em&gt;ti&lt;/em&gt; should be returned. So it's the same, but in Polish :)&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Vi5mp2F7--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.netguru.com/hs-fs/hubfs/letters.png%3Fwidth%3D450%26height%3D450%26name%3Dletters.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Vi5mp2F7--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.netguru.com/hs-fs/hubfs/letters.png%3Fwidth%3D450%26height%3D450%26name%3Dletters.png" alt="letters"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The results are a bit surprising. There is a huge difference between 4 and 5 letters for standard Realm database. Sets, trie, &lt;code&gt;CleverArray&lt;/code&gt; and &lt;code&gt;CleverRealm&lt;/code&gt; are really fast in this test, so I decided to run more tests for the fastest four of them.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--rUZtNmFO--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.netguru.com/hs-fs/hubfs/letters-2.png%3Fwidth%3D450%26height%3D340%26name%3Dletters-2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--rUZtNmFO--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.netguru.com/hs-fs/hubfs/letters-2.png%3Fwidth%3D450%26height%3D340%26name%3Dletters-2.png" alt="letters-2"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This chart has logarithmic scale with power trend line.&lt;/p&gt;

&lt;p&gt;Sets and trie growth when more letters is reasonable, but &lt;code&gt;CleverRealm&lt;/code&gt; is useless for more than six letters!&lt;/p&gt;

&lt;h3&gt;
  
  
  Simple regex
&lt;/h3&gt;

&lt;p&gt;This test results with a time time needed to find words that fit these simple blank regex one by one: &lt;em&gt;p?z?a&lt;/em&gt;, &lt;em&gt;???&lt;/em&gt;, &lt;em&gt;po??r&lt;/em&gt;, &lt;em&gt;pap????&lt;/em&gt;, &lt;em&gt;???????&lt;/em&gt;, &lt;em&gt;tele???&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;In example: &lt;em&gt;&lt;strong&gt;po&lt;/strong&gt;??&lt;strong&gt;r&lt;/strong&gt;&lt;/em&gt; should return &lt;em&gt;&lt;strong&gt;po&lt;/strong&gt;bó&lt;strong&gt;r&lt;/strong&gt;&lt;/em&gt;, &lt;em&gt;&lt;strong&gt;po&lt;/strong&gt;de*&lt;em&gt;r&lt;/em&gt;*&lt;/em&gt;, &lt;em&gt;&lt;strong&gt;po&lt;/strong&gt;ke*&lt;em&gt;r&lt;/em&gt;*&lt;/em&gt;, &lt;em&gt;&lt;strong&gt;po&lt;/strong&gt;kó&lt;strong&gt;r&lt;/strong&gt;&lt;/em&gt;, &lt;em&gt;&lt;strong&gt;po&lt;/strong&gt;la*&lt;em&gt;r&lt;/em&gt;*&lt;/em&gt;, &lt;em&gt;&lt;strong&gt;po&lt;/strong&gt;le*&lt;em&gt;r&lt;/em&gt;*&lt;/em&gt;, &lt;em&gt;&lt;strong&gt;po&lt;/strong&gt;lo*&lt;em&gt;r&lt;/em&gt;*&lt;/em&gt;, &lt;em&gt;&lt;strong&gt;po&lt;/strong&gt;mó&lt;strong&gt;r&lt;/strong&gt;&lt;/em&gt;, &lt;em&gt;&lt;strong&gt;po&lt;/strong&gt;no&lt;/em&gt;&lt;strong&gt;r&lt;/strong&gt;, &lt;em&gt;&lt;strong&gt;po&lt;/strong&gt;nu*&lt;em&gt;r&lt;/em&gt;*&lt;/em&gt;, &lt;em&gt;&lt;strong&gt;po&lt;/strong&gt;ti&lt;/em&gt;&lt;strong&gt;r&lt;/strong&gt;, &lt;em&gt;&lt;strong&gt;po&lt;/strong&gt;we*&lt;em&gt;r&lt;/em&gt;*&lt;/em&gt;, &lt;em&gt;&lt;strong&gt;po&lt;/strong&gt;ze*&lt;em&gt;r&lt;/em&gt;*&lt;/em&gt;, &lt;em&gt;&lt;strong&gt;po&lt;/strong&gt;zó&lt;strong&gt;r&lt;/strong&gt;&lt;/em&gt;, &lt;em&gt;&lt;strong&gt;po&lt;/strong&gt;ża*&lt;em&gt;r&lt;/em&gt;*&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Snvm8qZh--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.netguru.com/hs-fs/hubfs/regex.png%3Fwidth%3D450%26height%3D340%26name%3Dregex.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Snvm8qZh--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.netguru.com/hs-fs/hubfs/regex.png%3Fwidth%3D450%26height%3D340%26name%3Dregex.png" alt="regex"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is possible in reasonable time only for &lt;code&gt;CleverArray&lt;/code&gt;, &lt;code&gt;CleverSet&lt;/code&gt;, &lt;code&gt;Trie&lt;/code&gt;, &lt;code&gt;Realm&lt;/code&gt; and &lt;code&gt;CleverRealm&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;CleverRealm&lt;/code&gt; is the fastest, while &lt;code&gt;Realm&lt;/code&gt; is the slowest. Important thing is that &lt;code&gt;Trie&lt;/code&gt; is faster than standard Swift collection types.&lt;/p&gt;

&lt;h3&gt;
  
  
  RAM Usage
&lt;/h3&gt;

&lt;p&gt;Last, but not least – it eventually makes some types useless.&lt;/p&gt;

&lt;p&gt;RAM usage measured by Xcode profiler on a real device running example app:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;RAM Usage is RAM usage just after initialization.&lt;/li&gt;
&lt;li&gt;Highest RAM Usage is the highest RAM usage noticed during initialization.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--kSWkP7l9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.netguru.com/hs-fs/hubfs/ram.png%3Fwidth%3D450%26height%3D450%26name%3Dram.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--kSWkP7l9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.netguru.com/hs-fs/hubfs/ram.png%3Fwidth%3D450%26height%3D450%26name%3Dram.png" alt="ram"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As you can see trie and sets RAM usage is unacceptable high, because it may cause crashes especially on older devices. Arrays RAM usage is high, but acceptable – unfortunately their performance is not satisfactory. &lt;code&gt;Realm&lt;/code&gt; RAM usage is close to null.&lt;/p&gt;

&lt;h2&gt;
  
  
  Judgment
&lt;/h2&gt;

&lt;p&gt;It's really hard to say which collection type is the best. No one is perfect and the same applies here.&lt;/p&gt;

&lt;p&gt;I believe that the best solution is to use more than one technique at once and that's how Scrabbdict works. Normally it uses solution similar to &lt;code&gt;CleverRealm&lt;/code&gt;database – it's fast for word validation and simple regexes. But when the app is started, in background it creates a trie with words up to 8 letters and uses it to find words made from given letters. In Scrabble you can't have more than seven tiles on your hand, so eight letters limit is still fine and a trie is really fast.&lt;/p&gt;

&lt;p&gt;Such limited trie (there are &lt;em&gt;just&lt;/em&gt; less than half a million words up to 8 letters in Polish) initializes quite fast (but it really doesn't matter so much, because it happens in background) and is one the fastest solutions.&lt;/p&gt;

</description>
      <category>ios</category>
      <category>performance</category>
    </item>
    <item>
      <title>5 steps to make your iOS app more secure</title>
      <dc:creator>Piotr Sochalewski</dc:creator>
      <pubDate>Fri, 09 Aug 2019 07:36:16 +0000</pubDate>
      <link>https://dev.to/netguru/5-steps-to-make-your-ios-app-more-secure-5a8d</link>
      <guid>https://dev.to/netguru/5-steps-to-make-your-ios-app-more-secure-5a8d</guid>
      <description>&lt;p&gt;Security is an important thing. Not only for financial apps, but for all. You should always keep it in mind. I'd like to introduce you 5 steps that are easy to do, but make your iOS app more secure.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Store confidential data in a secure place
&lt;/h2&gt;

&lt;p&gt;Speaking in terms of storing confidential values, &lt;strong&gt;Keychain is the only right answer&lt;/strong&gt;. User Defaults are fine, when you're dealing with preferences, but you should never store credentials or personal data in them. Keychain may seem to be more difficult, but using a wrapper make it much easier. I personally recommend &lt;a href="https://github.com/matthewpalmer/Locksmith"&gt;Locksmith&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Keep in mind that Keychain is &lt;strong&gt;secured using a hardware module&lt;/strong&gt; (on modern devices, A7 and newer chips) and is backed up to iCloud (that's really cool side effect).&lt;/p&gt;

&lt;p&gt;If you want to encrypt your database it's also possible. A bit difficult for Core Data, but really simple for Realm.&lt;/p&gt;

&lt;p&gt;You can also write your files using &lt;strong&gt;four different levels of protection&lt;/strong&gt;. Default level is fine, but you can easily make your files more secure. You can read more about it &lt;a href="https://developer.apple.com/documentation/uikit/core_app/protecting_the_user_s_privacy/encrypting_your_app_s_files"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Make networking layer invulnerable
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;HTTP is strongly not recommended&lt;/strong&gt;. Since iOS 9.0 App Transport Security (ATS) is enabled by default, so you have to use HTTPS instead of not encrypted HTTP. Unfortunately ATS can be easily disabled. That's fine if the app is during development and your server doesn't offer SSL yet, but an App Store build should never call HTTP requests and ATS should be enabled.&lt;/p&gt;

&lt;p&gt;According to &lt;a href="https://www.nowsecure.com/blog/2016/12/29/enable-ios-app-transport-security-ats/"&gt;NowSecure&lt;/a&gt;  80% of 201 of the most downloaded free iOS apps did opt out of ATS in December 2016. I sincerely hope that it's much better today.&lt;/p&gt;

&lt;p&gt;HTTPS is effective, but doesn't protect you from an attack called &lt;em&gt;Man in the Middle&lt;/em&gt;. &lt;strong&gt;SSL Pinning&lt;/strong&gt; does. It's really easy technique, especially if you're using &lt;a href="https://github.com/Alamofire/Alamofire/blob/master/Documentation/AdvancedUsage.md#security"&gt;Alamofire&lt;/a&gt; for networking. The only disadvantage is the app must be updated whenever the server’s SSL key is changed.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Think about your secret (like API) keys
&lt;/h2&gt;

&lt;p&gt;They &lt;strong&gt;shouldn't be stored in the repository&lt;/strong&gt;. Instead you can use &lt;a href="https://github.com/orta/cocoapods-keys"&gt;cocoapods-keys&lt;/a&gt; that also obfuscates them. An &lt;strong&gt;obfuscation&lt;/strong&gt; is probably not a big deal for a professional app cracker, but at least your raw secret values are not a part of Git history.&lt;/p&gt;

&lt;p&gt;A &lt;a href="https://github.com/search?q=client_secret&amp;amp;type=Commits"&gt;search for &lt;em&gt;client_secret&lt;/em&gt;&lt;/a&gt; on GitHub revealed that there are over 40,000 commits that potentially expose an API key and secret. Don't push one of these.&lt;/p&gt;

&lt;p&gt;Now you know that it's extremely important for public repositories, but the same applies to private ones.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Be careful with 3rd party integration
&lt;/h2&gt;

&lt;p&gt;It's difficult, but you should do your best to ensure that 3rd party frameworks aren't vulnerable. The easiest, but not 100% effective way is to &lt;strong&gt;keep them updated&lt;/strong&gt; to the latest stable version. You should, in particular, make sure that ad libraries you use (if any) are safe. Don't ever disable ATS for them, even if they ask politely.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Keep learning
&lt;/h2&gt;

&lt;p&gt;Of course that's not all. You should still learn about new vulnerabilities to be up to date. This &lt;a href="https://github.com/felixgr/secure-ios-app-dev"&gt;repository&lt;/a&gt; can be helpful as it contains a list of the most common vulnerabilities in iOS apps.&lt;/p&gt;

&lt;p&gt;Before the summary, I'd like to share with you two more tips.&lt;/p&gt;

&lt;p&gt;I strongly believe that your production app should not print (or log in Obj-C nomenclature) important statements. They're designed for debugging, but hacker/cracker can easily see them.&lt;/p&gt;

&lt;p&gt;Also you shouldn't forget about Xcode's static analysis report. You can get it by pressing ⇧⌘B. This tool helps to reveal logic flaws, memory leaks, unused variables and other bugs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Sum up
&lt;/h2&gt;

&lt;p&gt;Even following these steps doesn't mean your app is 100% invulnerable. There is an eternal war between developers and crackers. I hope this blog post could be a useful weapon.&lt;/p&gt;

</description>
      <category>ios</category>
      <category>security</category>
    </item>
  </channel>
</rss>
