<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Vinh Nguyen's Blog</title>
    <description>Learn and share to become better
</description>
    <link>http://blog.vinhis.me/</link>
    <atom:link href="http://blog.vinhis.me/feed.xml" rel="self" type="application/rss+xml"/>
    <pubDate>Sun, 18 Jul 2021 13:49:50 +0000</pubDate>
    <lastBuildDate>Sun, 18 Jul 2021 13:49:50 +0000</lastBuildDate>
    <generator>Jekyll v3.9.0</generator>
    
      <item>
        <title>How to ignore/hide changes from Git</title>
        <description>&lt;p&gt;Git is a popular distributed version control system, which helps keeping track of changes less hassle. In some scenarios, we might want Git to ignore some changes or hide them from Git. In this post, we’ll explore a couple of ways to do so.&lt;/p&gt;

&lt;h1 id=&quot;basics&quot;&gt;Basics&lt;/h1&gt;

&lt;p&gt;Let’s go back basics first. There’re 3 states in Git, namely modified, staged and committed. These states apply to files on which Git has an eye. For those Git doesn’t track yet, we have another state named &lt;em&gt;untracked&lt;/em&gt;—they are listed under &lt;em&gt;Untracked files&lt;/em&gt; when &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git status&lt;/code&gt;. Files are either modified, staged or committed can be seen as &lt;em&gt;tracked&lt;/em&gt; ones.&lt;/p&gt;

&lt;p&gt;We human only see &lt;em&gt;working directory&lt;/em&gt; and files in it just like what we see when &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ls&lt;/code&gt;. &lt;em&gt;Working directory&lt;/em&gt; is nothing but a directory created when we clone a Git repo, it’s an ordinary directory in a filesystem. Whenever we modify, add or remove files in &lt;em&gt;working directory&lt;/em&gt;, we see only one version of them at that moment. If another person looks at &lt;em&gt;working directory&lt;/em&gt; later, they can’t tell what changes we made. That another person is Git. Git wouldn’t be so useful, if it sorely relied on &lt;em&gt;working directory&lt;/em&gt;. Therefore, Git adds another place called &lt;em&gt;index&lt;/em&gt; which aids in detecting differences. &lt;em&gt;Index&lt;/em&gt; is a version of &lt;em&gt;working directory&lt;/em&gt;, any changes we make in &lt;em&gt;working directory&lt;/em&gt; are compared to &lt;em&gt;index&lt;/em&gt;, and from there Git can keep track of changes.&lt;/p&gt;

&lt;p&gt;Connect this to states above, we can think of &lt;em&gt;tracked files&lt;/em&gt; are &lt;em&gt;indexed files&lt;/em&gt;—files are added to &lt;em&gt;index&lt;/em&gt;—and vice versa.&lt;/p&gt;

&lt;h1 id=&quot;untracked-files&quot;&gt;Untracked files&lt;/h1&gt;

&lt;p&gt;A common example for untracked files—if you’re using macOS—is the metadata file &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.DS_Store&lt;/code&gt;. We usually put this file in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.gitignore&lt;/code&gt;. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.gitingore&lt;/code&gt; is used when we want to share ignored files with other people since it’s always committed in a Git repo.&lt;/p&gt;

&lt;p&gt;How about if we want to ignore some locally only, and not to share or modify &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.gitignore&lt;/code&gt;? &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;$GIT_DIR/info/exclude&lt;/code&gt; has the same effect as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.gitignore&lt;/code&gt;, except it’s only applicable locally in a specific repo. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;$GIT_DIR&lt;/code&gt; is actually &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.git&lt;/code&gt; folder in a working directory after we clone from a Git repo. All things behind the scene of Git are stored in this folder, and we can call it the Git repo itself.&lt;/p&gt;

&lt;p&gt;To make these files observable again from Git, we simply remove them from &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.gitignore&lt;/code&gt; or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;$GIT_DIR/info/exclude&lt;/code&gt;.&lt;/p&gt;

&lt;h1 id=&quot;tracked-files&quot;&gt;Tracked files&lt;/h1&gt;

&lt;p&gt;Now the fun part comes. How do we temporarily hide tracked files from Git? A use case for it could be a shared configuration file. Usually, it’s committed and shared among people, but we need to change some of its values while tinkering and also don’t want the noise when &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git status&lt;/code&gt;—the file will be listed in &lt;em&gt;Changes not staged for commit&lt;/em&gt;. We can use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git update-index --skip-worktree &amp;lt;files&amp;gt;&lt;/code&gt; for this purpose. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git update-index&lt;/code&gt; is a low-level command, a plumbing one in Git parlance, which allows us to manipulate Git &lt;em&gt;index&lt;/em&gt;. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;--skip-worktree&lt;/code&gt; option tells Git to pretend that a file in &lt;em&gt;working directory&lt;/em&gt; isn’t changed—even it’s in fact—so that the file is treated as &lt;em&gt;unmodified&lt;/em&gt; on comparing to &lt;em&gt;index&lt;/em&gt;. As a result, we won’t see the file in &lt;em&gt;Changes not staged for commit&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;To undo, we use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git update-index --no-skip-worktree &amp;lt;files&amp;gt;&lt;/code&gt;. It’s straightforward if we remember files, otherwise it would be not so obvious to find out. Luckily, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git ls-files -v&lt;/code&gt; comes to rescue. Files start &lt;strong&gt;S&lt;/strong&gt; tag are ones we skipped.&lt;/p&gt;

&lt;h1 id=&quot;summary&quot;&gt;Summary&lt;/h1&gt;

&lt;p&gt;For untracked files, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.gitignore&lt;/code&gt; or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;$GIT_DIR/info/exclude&lt;/code&gt; depends on whether or not we want to shared these ignore files respectively.&lt;/p&gt;

&lt;p&gt;For tracked files, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git update-index --skip-worktree &amp;lt;files&amp;gt;&lt;/code&gt; will do the job, and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git ls-files-v&lt;/code&gt; is nice to help when we need to undo.&lt;/p&gt;
</description>
        <pubDate>Wed, 17 Mar 2021 00:00:00 +0000</pubDate>
        <link>http://blog.vinhis.me/2021/03/17/how-to-ignore-hide-changes-from-Git.html</link>
        <guid isPermaLink="true">http://blog.vinhis.me/2021/03/17/how-to-ignore-hide-changes-from-Git.html</guid>
        
        
      </item>
    
      <item>
        <title>The Essentials of Essential Front-end Tools, ESLint</title>
        <description>&lt;p&gt;Recently, I’ve been getting more involved in front-end development. The more I do, the more my mind and my soul get lost in its chaotic world. Even a simple To–Do–List app can easily require a bunch of tools—&lt;a href=&quot;https://eslint.org&quot;&gt;ESLint&lt;/a&gt;, &lt;a href=&quot;https://babeljs.io/&quot;&gt;Babel&lt;/a&gt;, &lt;a href=&quot;https://webpack.js.org/&quot;&gt;Webpack&lt;/a&gt;, to name a few—and packages just to get started. Fortunately, there’re many starter kits out there so we don’t have to do from the ground up. With them, everything is already set up so we can start writing the first line of code right away. It saves time on repetitive, boring tasks, which can be great for experienced developers. However, this benefit comes with a price for beginners. Since everything works out of the box, it seems like magic, and they might not know what’s really happening under the hood, which is important to understand at some level. Although the learning curve is not as steep as others—try to compare with some tools you’ve been learning and using, you’ll get what I mean—in the chaotic world, we need a survival guide for the journey.&lt;/p&gt;

&lt;p&gt;This series will cover fundamental tools of front-end development and what essential we need to know—to rule the tools instead of being controlled by them. In it, we’ll focus on the developer experience of each one of these tools so the goal of this series is to act as a survival guide and to give a high-level overview of each tool, not to serve as a documentation.&lt;/p&gt;

&lt;p&gt;What will be included:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://eslint.org&quot;&gt;ESLint&lt;/a&gt; &amp;lt;- We are here&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://babeljs.io/&quot;&gt;Babel&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://webpack.js.org/&quot;&gt;Webpack&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://flow.org&quot;&gt;Flow&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.typescriptlang.org/&quot;&gt;TypesScript&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://jestjs.io&quot;&gt;Jest&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Enough of preface, let’s get started with the first tool, ESLint.&lt;/p&gt;

&lt;h1 id=&quot;what-is-eslint-and-why&quot;&gt;What is ESLint and Why?&lt;/h1&gt;

&lt;p&gt;ESLint is, as the name implies, a linter for &lt;a href=&quot;http://www.ecma-international.org/publications/standards/Ecma-262.htm&quot;&gt;ECMAScript&lt;/a&gt;. And, the definition of a linter is:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;a machine for removing the short fibers from cotton seeds after ginning.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Although code and cotton seeds don’t have any relationship, regardless of code or cotton seeds, a linter will help make things cleaner and more consistent. We don’t want to see the code like this:&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;count&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;message&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;Hello, ESLint&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;count&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;It both looks ugly and has a mistake. Here’s when ESLint steps in to help with that. Instead of letting the error be dumped out to the browser console when we run the code, ESLint will catch it as we’re typing—not really, we’ll need editor or IDE extensions for this, which will be covered later. Obviously, this error isn’t difficult to figure out, but wouldn’t it be nicer to have an assistant reminding us every time we’re about to make a mistake and perhaps auto-correcting it for us? Although ESLint can’t catch all kinds of errors, it at least spares us some effort so we can spend on other things that matter and need human attention.&lt;/p&gt;

&lt;h1 id=&quot;how-does-eslint-work&quot;&gt;How does ESLint work?&lt;/h1&gt;

&lt;p&gt;Now that we know what ESLint is and why we need it, let’s go a bit deeper and check out how it works. In essence, we can break it down to three big steps.&lt;/p&gt;

&lt;h2 id=&quot;parser&quot;&gt;Parser&lt;/h2&gt;

&lt;p&gt;The code that we write is nothing more than a sequence of characters. However, this sequence isn’t just random characters, they need to follow a set of rules or conventions that is the grammar forming a language. For a human, going from reading text or code to understanding it conceptually takes us little effort. For a computer, this is much more difficult to accomplish. For example:&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;tool&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;ESLint&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// 1&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;tool&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;ESLint&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// 2&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;As we read the two lines above, we immediately know that they are identical, and can be read as “there’s a constant named &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tool&lt;/code&gt; with the value of ESLint”. For a computer, which doesn’t understand the meaning, these two lines look quite different. As a result, if we feed in raw code to ESLint, it’s nearly impossible to do anything. When things get complicated and hard to communicate—think of how we can have a computer to understand what we do—abstraction can be an escape. By abstracting a thing, we hide all unnecessary details, reduce noise, and keep everyone on the same page, which eases the communication. In the above example, one space or two spaces don’t matter, neither do single quotes or double quotes.&lt;/p&gt;

&lt;p&gt;In other words, that’s what a parser does. It converts raw code to an Abstract Syntax Tree (AST), and this AST is used as the medium for lint rules to base on. There are still many steps a parser need to do in order to create an AST—if you’re interested in learning more about how an AST is generated, &lt;a href=&quot;https://the-super-tiny-compiler.glitch.me/&quot;&gt;this tutorial&lt;/a&gt; has a good overview.&lt;/p&gt;

&lt;h2 id=&quot;rules&quot;&gt;Rules&lt;/h2&gt;

&lt;p&gt;The next step in the process is to run the AST through a list of rules. A rule is a logic of how to figure out potential existing issues in the code from the AST. Issues here aren’t necessary syntactic or semantic errors but might be stylistic ones as well. The output given out from a rule will include some useful information for later use like lines of code, positions, and informative messages about the issue.&lt;/p&gt;

&lt;p&gt;In addition to catching issues, a rule can even auto-correct code if possible. For example, when &lt;a href=&quot;https://eslint.org/docs/rules/no-multi-spaces&quot;&gt;no-multi-spaces&lt;/a&gt; is applied to the code above, it will trim all redundant spaces, which makes the code look clean and consistent.&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;tool&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;ESLint&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// 2&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// becomes&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;tool&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;ESLint&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// 2&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;In different scenarios, a rule can be used at different levels—opted-out, warning only, or strict error—and have various options, which gives us control on how to use the rule.&lt;/p&gt;

&lt;h2 id=&quot;result&quot;&gt;Result&lt;/h2&gt;

&lt;p&gt;Here comes the end of the process. With the output from a rule, it’s just the matter of how we display it in a human friendly manner, thanks to all the useful information we mentioned earlier. Then from the result, we can quickly point out the issue, where it is, and make a fix, or maybe not.&lt;/p&gt;

&lt;h1 id=&quot;integration&quot;&gt;Integration&lt;/h1&gt;

&lt;p&gt;ESLint can be used as a standalone tool with its robust CLI, but that’s a bare-bones way to use ESLint. We don’t want to type in a command every time we want to lint code, especially in a development environment. The solution for this is to integrate ESLint into our development environment so we can write code and see issues caught by ESLint all in one place.&lt;/p&gt;

&lt;p&gt;This kind of integration comes from extensions specific to IDEs or editors. These extensions require ESLint to work since they run ESLint behind the scene—no wonder that we still need to install ESLint along with them, they are nothing without ESLint. This principle applies to other IDE or editor extensions we are using daily.&lt;/p&gt;

&lt;p&gt;Remember the output from a rule we talked above? An extension will use it to display in the IDE or editor. How exactly the output is displayed depends on how the extension is implemented and how the IDE or editor is open to its extensions. Some extensions also take advantage of the abilities of issue correction from rules to change code on save if we enable it.&lt;/p&gt;

&lt;h1 id=&quot;configuration&quot;&gt;Configuration&lt;/h1&gt;

&lt;p&gt;Configuration is the main power that gives the versatility to a tool. ESLint is not different from that, except it has the most comprehensive configuration among other tools. In general, we need a file or a place to put the configuration, and there’s a couple of options of us. All of them boil down to two main ways, either we have a separate configuration file for each tool or bundle them all in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;package.json&lt;/code&gt;. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.eslintrc.js&lt;/code&gt; is one of the files that ESLint will be looking for its configuration, and also the one with the highest priority.&lt;/p&gt;

&lt;p&gt;The next thing we need to know about configuration is its hierarchy and cascading behavior. Thanks to these features, we don’t need to have a configuration file in every single folder in the project. If a configuration file doesn’t exist in a folder, ESLint simply looks up the folder’s parent for one until it can’t find anyone, then it’ll fall back to the user–wide default configuration in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;~/.eslintrc&lt;/code&gt;. Otherwise, the configuration file will add up or override the ones at upper levels.&lt;/p&gt;

&lt;p&gt;There’s, however, a special tweak on this. If we specify &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;root: true&lt;/code&gt; in a configuration file, the lookup will stop at that file instead of going up like before. Besides, ESLint will use that configuration file as the root configuration, all child configurations will base on this one.&lt;/p&gt;

&lt;p&gt;Not only limited to ESLint, but these things are common for other tools. Let’s talk about ESLint specific configuration.&lt;/p&gt;

&lt;h2 id=&quot;parser-1&quot;&gt;Parser&lt;/h2&gt;

&lt;p&gt;The role of parser in ESLint has been discussed above. By default, ESLint uses &lt;a href=&quot;https://github.com/eslint/espree&quot;&gt;Espree&lt;/a&gt; as its parser. We can change this parser to another compatible one like &lt;a href=&quot;https://www.npmjs.com/package/babel-eslint&quot;&gt;babel-eslint&lt;/a&gt; or &lt;a href=&quot;https://www.npmjs.com/package/@typescript-eslint/parser&quot;&gt;@typescript-eslint/parser&lt;/a&gt; if we use Babel or Typescript respectively.&lt;/p&gt;

&lt;p&gt;To configure the parser, we use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;parserOptions&lt;/code&gt;. Among options supported by Espree, here are some we often use and need to pay attention.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ecmaVersion&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We need to specify the appropriate ECMA version to features we want to use. For example, if &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;emcaVersion: 5&lt;/code&gt;, the code below will give some errors.&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;javascript let a = [1, 2, 3, 4] // error due to `let` keyword var b = [...a, 5] // error due to spread syntax&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;The parser can’t parse the code because both &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;let&lt;/code&gt; keyword and spread syntax are just introduced in ES6. Changing &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;emcaVersion&lt;/code&gt; to 6 or above will simply resolve the errors.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sourceType&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Nowadays, we mostly write everything in modules, then bundle them together so this option, most the time, should be &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;module&lt;/code&gt;. Another value we can use—as well as the default—is &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;script&lt;/code&gt;. The difference is whether we can use &lt;a href=&quot;https://v8.dev/features/modules&quot;&gt;JS modules&lt;/a&gt; or not, i.e., use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;import&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;export&lt;/code&gt; keyword. The next time we get this error message &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Parsing error: 'import' and 'export' may appear only with 'sourceType: module'&lt;/code&gt;, we know where to look at.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ecmaFeatures.jsx&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There might be additional ES features we want to use, for example &lt;a href=&quot;https://facebook.github.io/jsx/&quot;&gt;JSX&lt;/a&gt; syntax. We use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ecmaFeatures.jsx: true&lt;/code&gt; to enable this feature. Note that, JSX support from Espree isn’t the same as JSX in React so if we want React specific JSX, we should use &lt;a href=&quot;https://github.com/yannickcr/eslint-plugin-react&quot;&gt;eslint-plugin-react&lt;/a&gt; for better result.&lt;/p&gt;

&lt;p&gt;If we use another parser, these options are more or less the same. Some might have fewer options, others might have more, but they’re all defined under &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;parserOptions&lt;/code&gt;.&lt;/p&gt;

&lt;h2 id=&quot;environment&quot;&gt;Environment&lt;/h2&gt;

&lt;p&gt;Depends on where the code is running, there are different predefined global variables, we have &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;window&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;document&lt;/code&gt; in browser for example. It would be irritating if &lt;a href=&quot;https://eslint.org/docs/rules/no-undef&quot;&gt;no-undef&lt;/a&gt; rule is enabled, and ESLint keeps telling us &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;window&lt;/code&gt; or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;document&lt;/code&gt; is not defined.&lt;/p&gt;

&lt;p&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;env&lt;/code&gt; option is here to help. By specifying a list of environments, ESLint will know about global variables in these environments, and let us use them without a word.&lt;/p&gt;

&lt;p&gt;There’s a special environment needed to note, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;es6&lt;/code&gt;. It’ll implicitly set &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;parserOptions.ecmaVersion&lt;/code&gt; to 6, and enable all ES6 features except for modules which we still need to use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;parserOptions.sourceType: &quot;module&quot;&lt;/code&gt; separately.&lt;/p&gt;

&lt;h1 id=&quot;plugins-and-shareable-configs&quot;&gt;Plugins and Shareable Configs&lt;/h1&gt;

&lt;p&gt;Having the same configuration for rules over and over again across different projects might be tiresome. Luckily, we can reuse a configuration, and only override rules as needed with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;extends&lt;/code&gt;. We call this type of configs, shareable configs, and ESLint already has two for us, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;eslint:recommended&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;eslint:all&lt;/code&gt;. Conventionally, ESLint’s shareable configs have &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;eslint-config&lt;/code&gt; prefix so we can easily find them via NPM with &lt;a href=&quot;https://www.npmjs.com/search?q=keywords:eslint-config&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;eslint-config&lt;/code&gt;&lt;/a&gt; keyword. Among hundreds of results, there’re some popular ones, like &lt;a href=&quot;https://github.com/airbnb/javascript/tree/master/packages/eslint-config-airbnb&quot;&gt;eslint-config-airbnb&lt;/a&gt; or &lt;a href=&quot;https://github.com/google/eslint-config-google&quot;&gt;eslint-config-google&lt;/a&gt;, you name it.&lt;/p&gt;

&lt;p&gt;Out of the box, ESLint has a bunch of rules to serve different purposes from possible errors, best practices, ES6 to stylistic issues. Moreover, to supercharge its ability, ESLint has a great number of 3rd-party rules provided by almost a thousand of plugins. Similar to shareable configs, ESLint’s plugins are prefixed with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;eslint-plugin&lt;/code&gt;, and available on NPM with &lt;a href=&quot;https://www.npmjs.com/search?q=keywords:eslint-plugin&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;eslint-plugin&lt;/code&gt;&lt;/a&gt; keyword.&lt;/p&gt;

&lt;p&gt;What a plugin does is to define a set of new rules, and in most cases to expose its own some handy configs. For example, &lt;a href=&quot;https://github.com/yannickcr/eslint-plugin-react&quot;&gt;eslint-plugin-react&lt;/a&gt; gives us two shareable configs, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;eslint-plugin-react:recommended&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;eslint-plugin-react:all&lt;/code&gt; just like &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;eslint:recommended&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;eslint:all&lt;/code&gt;. To use one of them, we need to, firstly, define the plugin name, secondly extend the config.&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;nl&quot;&gt;plugins&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;react&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
  &lt;span class=&quot;kd&quot;&gt;extends&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;plugin:react/recommended&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// Note that we need to prefix the config by `plugin:react`&lt;/span&gt;

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

&lt;p&gt;One common question to ask is what plugins or configs to use. While it largely depends on our needs, we can use &lt;a href=&quot;https://github.com/dustinspecker/awesome-eslint&quot;&gt;Awesome ESLint&lt;/a&gt; as a reference to find useful plugins as well as configs.&lt;/p&gt;

&lt;h1 id=&quot;prettier&quot;&gt;Prettier&lt;/h1&gt;

&lt;p&gt;We’re almost there, we almost go to the end. Last but not least, we’ll discuss a popular pair of ESLint, &lt;a href=&quot;https://github.com/prettier/prettier&quot;&gt;Prettier&lt;/a&gt;. In short, Prettier is an opinionated code formatter. Though Prettier can be used alone, integrating it to ESLint enhances the experience a lot, and &lt;a href=&quot;https://github.com/prettier/eslint-plugin-prettier&quot;&gt;eslint-plugin-prettier&lt;/a&gt; does this job.&lt;/p&gt;

&lt;p&gt;The difference between the usage of Prettier alone and Prettier with ESLint can be summarized to code formatting as an issue. Instead of giving format issues separately, running Prettier with ESLint will treat format issues just like other issues. However, these issues are always fixable, which is equivalent to formatting the code. That’s how &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;eslint-plugin-prettier&lt;/code&gt; works. It runs Prettier, as a rule, behind the scene and compares the code before and after being run through Prettier. Finally, it reports differences as individual ESLint issues. To fix these issues, the plugin simply uses the formatted code from Prettier.&lt;/p&gt;

&lt;p&gt;To have this integration, we need to install both &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;prettier&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;eslint-plugin-prettier&lt;/code&gt;. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;eslint-plugin-prettier&lt;/code&gt; also comes with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;eslint-plugin-prettier:recommended&lt;/code&gt; config—extends &lt;a href=&quot;https://github.com/prettier/eslint-config-prettier&quot;&gt;eslint-config-prettier&lt;/a&gt;, therefore we also need to install &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;eslint-config-prettier&lt;/code&gt;—to use.&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;plugins&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;prettier&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
  &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;extends&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;plugin:prettier/recommended&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h1 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h1&gt;

&lt;p&gt;Code linter or formatter has become de facto standard in software development in general, and ESLint, specifically in front-end development. Its benefit is far beyond what it does technically, it helps developers focus on more important matters. Thanks to delegating code styling to machine, we can avoid opinionated styles on code review, and use that time instead for more meaningful code review. Code quality also benefits from there, more consistent and less error-prone code.&lt;/p&gt;
</description>
        <pubDate>Sat, 03 Aug 2019 00:00:00 +0000</pubDate>
        <link>http://blog.vinhis.me/2019/08/03/the-essentials-of-essential-frontend-tools-eslint.html</link>
        <guid isPermaLink="true">http://blog.vinhis.me/2019/08/03/the-essentials-of-essential-frontend-tools-eslint.html</guid>
        
        
      </item>
    
      <item>
        <title>ReSwift, a weird use case</title>
        <description>&lt;h1 id=&quot;reswift-a-weird-use-case&quot;&gt;ReSwift, a weird use case&lt;/h1&gt;

&lt;p&gt;ReSwift is a library helping you construct unidirectional data flow architecture in your application. If you’ve already known &lt;a href=&quot;https://github.com/reactjs/redux&quot;&gt;Redux&lt;/a&gt;, think of ReSwift as a Swift implementation of it. I’ve tried ReSwift in my project, and I love it. It’s lean, easy to understand and easy to write. As always, however, practical use is far more than theory or the introduction at first glance. The more I use, the more problem I explore and need to deal with them. In this post, I’ll discuss my use case of ReSwift.&lt;/p&gt;

&lt;h2 id=&quot;reswift-in-brief&quot;&gt;ReSwift in brief&lt;/h2&gt;

&lt;p&gt;Before discussing the use case, let’s give ReSwift a quick rewind. Here, I recall a few principles on which ReSwift relies (from its &lt;a href=&quot;https://github.com/ReSwift/ReSwift#about-reswift&quot;&gt;README&lt;/a&gt;):&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;The Store&lt;/strong&gt; stores your entire app state in the form of a single data structure. This state can only be modified by dispatching Actions to the store. Whenever the state in the store changes, the store will notify all observers.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Actions&lt;/strong&gt; are a declarative way of describing a state change. Actions don’t contain any code, they are consumed by the store and forwarded to reducers. Reducers will handle the actions by implementing a different state change for each action.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Reducers&lt;/strong&gt; provide pure functions, that based on the current action and the current app state, create a new app state.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;img src=&quot;/figures/20170812-0.png&quot; alt=&quot;ReSwift concept&quot; /&gt;&lt;/p&gt;

&lt;p&gt;The above is just high-level description about store, actions, and reducers. In practical use, you might want break one big app state down into many smaller states to work with easily. So are reducers, each reducer will take care of an appropriate state. Action is simply a structure to encapsulate information needed to change the state.&lt;/p&gt;

&lt;h2 id=&quot;the-use-case-first-introduction&quot;&gt;The use case, first introduction&lt;/h2&gt;

&lt;p&gt;Now, let’s talk about the use case. To keep it short and simple, what I want is visualized below.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/figures/20170812-1.png&quot; alt=&quot;Hierarchy&quot; /&gt;&lt;/p&gt;

&lt;p&gt;There’re 3 main components: canvas, block, and object. The relationship between them is described as: Only one canvas contains one or many blocks; Each block contains one or many objects. Based on this relationship, I can define the appropriate basic state for each.&lt;/p&gt;

&lt;div class=&quot;language-swift highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;CanvasState&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;StateType&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;blockStates&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;BlockState&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;BlockState&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;StateType&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;frame&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;CGRect&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;objectStates&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;ObjectState&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;ObjectState&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;StateType&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;frame&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;CGRect&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;I have &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CanvasView&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;BlockView&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ObjectView&lt;/code&gt; corresponding these components, and each will display its state.&lt;/p&gt;

&lt;div class=&quot;language-swift highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;CanvasView&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;StoreSubscriber&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;newState&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;state&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;CanvasState&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;BlockView&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;StoreSubscriber&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;newState&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;state&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;BlockState&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;ObjectView&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;StoreSubscriber&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;newState&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;state&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;ObjectState&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;So far, I have the skeleton for the project, how about functionalities? Basically, I want to have these ones:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Display components based on their state.&lt;/li&gt;
  &lt;li&gt;Remove block.&lt;/li&gt;
  &lt;li&gt;Update object, it can be position, size, or other attributes.&lt;/li&gt;
  &lt;li&gt;Remove object.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In fact, there are more than this, but for the sake of brevity and simplicity, that’s enough.&lt;/p&gt;

&lt;h2 id=&quot;display&quot;&gt;Display&lt;/h2&gt;

&lt;p&gt;In the hierarchy, canvas is the highest level component and manages immediate lower level component, block. Block manages objects in turn. Therefore, to display all components, canvas and block need to traverse their child states, and add them to the view hierarchy.&lt;/p&gt;

&lt;div class=&quot;language-swift highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;CanvasView&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;StoreSubscriber&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;newState&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;state&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;CanvasState&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;blockState&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;state&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;blockStates&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;where&lt;/span&gt; &lt;span class=&quot;cm&quot;&gt;/* `blockState` isn't yet added */&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;blockView&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;BlockView&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
            &lt;span class=&quot;nf&quot;&gt;addSubview&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;blockView&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;BlockView&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;StoreSubscriber&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;newState&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;state&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;BlockState&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;objectState&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;state&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;objectStates&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;where&lt;/span&gt; &lt;span class=&quot;cm&quot;&gt;/* `objectState` isn't yet added */&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;objectView&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;ObjectView&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
            &lt;span class=&quot;nf&quot;&gt;addSubview&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;objectView&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;ObjectView&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;StoreSubscriber&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;newState&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;state&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;ObjectState&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Since &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;newState(state:)&lt;/code&gt; is called every time the state changes, and I don’t want to duplicate views if they’re already added, the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;where&lt;/code&gt; condition in the loop does the job. However, the detail implementation won’t be discussed in this post. The display part is straightforward, let’s move to functions.&lt;/p&gt;

&lt;h2 id=&quot;functions&quot;&gt;Functions&lt;/h2&gt;

&lt;p&gt;Having the advantage of unidirectional flow from state to view, functions can be represented by actions in ReSwift. On the other hand, if I want to have a function, I need to do the following:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Declare an appropriate action which packs information needed by the function. For example, moving a block requires the block index, so there’ll be &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;BlockActionRemove&lt;/code&gt; action.&lt;/li&gt;
&lt;/ul&gt;

&lt;div class=&quot;language-swift highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;BlockActionRemove&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Action&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;index&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Int&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;ul&gt;
  &lt;li&gt;Update the reducer to handle &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;BlockActionRemove&lt;/code&gt; action.&lt;/li&gt;
  &lt;li&gt;Then, whenever I want to remove a block at a particular index, a simple action dispatch call suffices.&lt;/li&gt;
&lt;/ul&gt;

&lt;div class=&quot;language-swift highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;store&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;dispatch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;BlockActionRemove&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;index&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;index&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;display-revisit&quot;&gt;Display, revisit&lt;/h2&gt;

&lt;p&gt;I talked about display and functions, and so far so good, everything’s typical and goes well. However, when the number of objects increases, performance becomes an issue. Since every object subscribes to the store, even a small change in one object causes all get re-displayed. The performance, therefore, is the sum of the display costs of objects. One obvious solution for this is to re-display the only objects with changes, and this leads to diffing the state. There’re few diffing strategies I can consider.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Object level: Still loop through all object states, but only call &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;newState(state:)&lt;/code&gt; with ones have been changed. This’s an out-of-box feature in ReSwift 4.&lt;/li&gt;
  &lt;li&gt;Block level: At this level, the loop is limited to only block states. Block only re-displays its changed objects based on the diff result. This’s equivalent to that subscribers now are just canvas and blocks.&lt;/li&gt;
  &lt;li&gt;Canvas level: This’s the highest possible level. The principle is identical to block level.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In my use case, the number of objects is far larger than the number of blocks, and the number of blocks is reasonable small for traversing all without overhead. Clearly, diffing at block level is the most suitable choice because it offers the balance between having more control on state delegation and utilizing ReSwift’s. I need to make some updates to accommodate this. Firstly, let’s define diff result.&lt;/p&gt;

&lt;div class=&quot;language-swift highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;enum&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Diff&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;initial&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;add&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;indices&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;Int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;change&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;indices&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;Int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;remove&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;indices&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;Int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This diff result needs to be in block state so that when the block view displays its state, it will use the result to display objects.&lt;/p&gt;

&lt;div class=&quot;language-swift highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;BlockView&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;StoreSubscriber&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;diffResult&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Diff&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;?&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;newState&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;state&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;BlockState&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;switch&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;diffResult&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;initial&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// Add all objects.&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;add&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;indices&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// Add objects with index in `indices`.&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;change&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;indices&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// Update objects with index in `indices`.&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;remove&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;indices&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// Remove objects with index in `indices`.&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;diffResult&lt;/code&gt; will be &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;nil&lt;/code&gt; if there’s no change for objects in the block. Note that objects don’t subscribe to the store anymore, but they still have the same interface as a subscriber.&lt;/p&gt;

&lt;div class=&quot;language-swift highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;ObjectView&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;newState&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;state&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;ObjectState&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;the-weird-thing&quot;&gt;The weird thing&lt;/h2&gt;

&lt;p&gt;As for functions, normally, we dispatch an action when the state delegation is settled which means every subscriber gets its new state and update corresponding to the state. What if we disrupt the state delegation, i.e., dispatch an action while the delegation’s happening? Here’s when the weird thing comes. The following diagram will describe best the problem.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/figures/20170812-2.png&quot; alt=&quot;The weird thing&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Whenever there’s an object dispatching an action during state delegation, i.e., dispatch in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;newState(state)&lt;/code&gt;, blocks after the block containing the object don’t update their objects. There’re factors causing this:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;The diffing, it helps improve performance, but also increase the complexity when working with ReSwift. However, even if objects are displayed not based on diff result, there’s still another problem, and I’ll talk about it in the next point.&lt;/li&gt;
  &lt;li&gt;ReSwift works in a synchronous manner and has one single store. If we make store change in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;newState(state)&lt;/code&gt; which equals to calling another &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;newState(state)&lt;/code&gt; inside a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;newState(state)&lt;/code&gt;, eventually we’ll end up with recursive &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;newState(state)&lt;/code&gt; calls or nested state delegation, and that’s another problem I just mentioned earlier. Additionally, because of one single store, regardless iteration of the state delegation, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;newState(state)&lt;/code&gt; always gets the latest state. That’s the reason why block 2 to n don’t have a chance to display &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;State #1&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;State #2&lt;/code&gt; in the diagram.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In essence, I have two problems. The first one is that objects don’t get updated under discussed circumstance. The second one is nested state delegation which doesn’t affect the visual result but harms the performance.&lt;/p&gt;

&lt;h2 id=&quot;solution&quot;&gt;Solution&lt;/h2&gt;

&lt;p&gt;Now I know the causes, finding solutions would be easier. Eliminating the diffing may solve the first problem, but the second problem’s still there, worse it’ll double slow down performance. Taking snapshot of the store so that each iteration of the state delegation has the correct state to display seems promising. Though it’ll break original idea, also philosophy of unidirectional data flow from ReSwift, Redux or even their ancestor, Flux, so let’s move on. I also won’t break synchronous ReSwift, and try to make it asynchronous since the problem isn’t about asynchronous so far. Ideally, what I want is whenever an action dispatched from &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;newState(state)&lt;/code&gt;, it should be queued in and performed after the state delegation finishes. By that way, I can keep ReSwift works synchronous and make it happy with the diffing. Surprisingly, it’s not a big deal to achieve that.&lt;/p&gt;

&lt;div class=&quot;language-swift highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;ObjectView&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;newState&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;state&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;ObjectState&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;// If needed to dispatch an action.&lt;/span&gt;
        &lt;span class=&quot;kt&quot;&gt;DispatchQueue&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;store&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;dispatch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;Action&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;())&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;main&lt;/code&gt; is a serial queue and ReSwift already works on it, so it’s the perfect way to synchronize the state delegation and action dispatch in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;newState(state)&lt;/code&gt;.&lt;/p&gt;

&lt;h2 id=&quot;alternatives&quot;&gt;Alternatives&lt;/h2&gt;

&lt;p&gt;Apart from the above solution, we can use a conductor to orchestrate action dispatch in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;newState(state)&lt;/code&gt;. Instead of dispatching directly to the store from object, we delegate the action to the conductor. The conductor, then, will batch actions and dispatch once to the store after all blocks get their new state.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/figures/20170812-3.png&quot; alt=&quot;Using conductor&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Another option is action creator. Action creator can create either synchronous or asynchronous action, and the latter one is what we need. However, this solution comes with a caveat. Let’s examine two scenarios.&lt;/p&gt;

&lt;div class=&quot;language-swift highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;ObjectView&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;StoreSubscriber&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;newState&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;state&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;ObjectState&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;size&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;zero&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;store&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;dispatch&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;callback&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;in&lt;/span&gt;
                &lt;span class=&quot;n&quot;&gt;callback&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;in&lt;/span&gt;
                    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Action&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
                &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;div class=&quot;language-swift highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;ObjectView&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;StoreSubscriber&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;newState&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;state&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;ObjectState&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;size&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;zero&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;store&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;dispatch&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;callback&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;in&lt;/span&gt;
                &lt;span class=&quot;k&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;viewModel&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fetch&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;in&lt;/span&gt;
                    &lt;span class=&quot;n&quot;&gt;callback&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;in&lt;/span&gt;
                        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Action&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
                    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
                &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The action in the former scenario is created outright if a certain condition is met, i.e., the action is created synchronously. In this case, to use action creator we need to know when the state delegation is done to call &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;callback&lt;/code&gt; to create the action, that creates extra work. Maybe, we can call &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;callback&lt;/code&gt; in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;DispatchQueue.main&lt;/code&gt;, it turns to the above simpler solution though. In contrast, the latter one fits perfectly to use action creator.&lt;/p&gt;

&lt;h2 id=&quot;when-to-go-from-here&quot;&gt;When to go from here?&lt;/h2&gt;

&lt;p&gt;The discussion on a weird use case of ReSwift is to demonstrate a practical application of ReSwift and overcome obstacles in real world usage. Though mentioned asynchronous action dispatch in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;newState(state)&lt;/code&gt;, it’s just the surface of an iceberg. In the consideration of the whole project, there’re many corners to have a look on, improve and deal with, e.g., the diff algorithm, flattening the state, state changes in between of asynchronous action dispatches, etc. Moreover, this post is written limited to abilities and features of ReSwift 3, ReSwift 4 is already out there for few months though. Finally, unidirectional data flow in iOS opens new opportunities and perspectives, and in conjunction with reactive programming, architectures, they’ll create a thriving playground for writing better code.&lt;/p&gt;
</description>
        <pubDate>Sat, 12 Aug 2017 00:00:00 +0000</pubDate>
        <link>http://blog.vinhis.me/2017/08/12/ReSwift-a-weird-use-case.html</link>
        <guid isPermaLink="true">http://blog.vinhis.me/2017/08/12/ReSwift-a-weird-use-case.html</guid>
        
        
      </item>
    
      <item>
        <title>Concurrent programming with semaphore</title>
        <description>&lt;p&gt;Writing an iOS app nowadays is pretty simple, however, a performant one requires more effort in many aspects from algorithm optimization to system related actions. The rule of thumb for most of cases is to keep heavy, time-consuming jobs away from main thread yet ensure that calls to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;UIKit&lt;/code&gt; or UI-related happen in the main thread. That helps the app be responsive and avoid sluggishness while using to bring a better experience to users.&lt;/p&gt;

&lt;p&gt;Dispatching jobs to the corresponding thread is actually dealing with concurrent programming, a challenging topic as always. Thanks to supports from high-level programming languages, libraries, and frameworks, it becomes more friendly and less error prone to work with. Depends on the complexity of the app, different techniques are used to solve appropriate problems, and one of them is using semaphore to synchronize asynchronous jobs or orchestrate them among threads. Which will be discussed in detail in this post.&lt;/p&gt;

&lt;h2 id=&quot;whats-semaphore&quot;&gt;What’s semaphore?&lt;/h2&gt;

&lt;p&gt;You can see analogies of semaphore in the real world in many places. If you’ve watched a chess contest, you probably know that each player will press a common timer before their turn in a match. There’s only one chess board and only one person can make a move at a given time. Another example is checkout counters in shopping malls. Usually, there’s a limited number of counters. If any of them is free, you can just go check out right away. In most cases, however, they’re all occupied and there’ll be long queues of people waiting to check out. Those two examples have a similarity which is a limited shared resource, the chess board and counters respectively.&lt;/p&gt;

&lt;p&gt;Now thinking of semaphore, semaphore is a mechanism to manage shared resources and guarantee access without congestion. The resource may be a concrete thing like a variable or more abstract one like a job pool. There’re two types of semaphore, binary and counting semaphore. The former can be used to implement a lock since its value is either 0 or 1 representing unlocked or locked state, while the latter allows a resource count which indicates the availability of the resource.&lt;/p&gt;

&lt;p&gt;In Grand Central Dispatch (GCD), semaphore is an instance of &lt;a href=&quot;https://developer.apple.com/documentation/dispatch/dispatchsemaphore&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;DispatchSemaphore&lt;/code&gt;&lt;/a&gt;. Its API is tiny with one initializer &lt;a href=&quot;https://developer.apple.com/documentation/dispatch/dispatchsemaphore/1452955-init&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;init(value:)&lt;/code&gt;&lt;/a&gt; and two primary methods &lt;a href=&quot;https://developer.apple.com/documentation/dispatch/dispatchsemaphore/1452919-signal&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;signal()&lt;/code&gt;&lt;/a&gt; and &lt;a href=&quot;https://developer.apple.com/documentation/dispatch/dispatchsemaphore/2016071-wait&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;wait()&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;&lt;strong&gt;Note:&lt;/strong&gt; Calls to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;signal()&lt;/code&gt; must be balanced with calls to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;wait()&lt;/code&gt;, otherwise an &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;EXC_BAD_INSTRUCTION&lt;/code&gt; exception will be raised.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;value&lt;/code&gt; param in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;init(value:)&lt;/code&gt; specifies the starting value for the semaphore, we’ll talk about this later on. The principle of using semaphore is quite simple, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;wait()&lt;/code&gt; will return outright if the value of the semaphore after decrementing is greater than or equal 0, otherwise, it will await a signal. To signal, we use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;signal()&lt;/code&gt; obviously, it will increment the value, then pending &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;wait()&lt;/code&gt; callers have the chance to continue execution. The following illustration helps you understand better.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/figures/20170617-1.png&quot; alt=&quot;Semaphore&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Now we know how to use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;DispatchSemaphore&lt;/code&gt;, let’s apply it in some use cases.&lt;/p&gt;

&lt;h2 id=&quot;use-case-1&quot;&gt;Use case 1&lt;/h2&gt;

&lt;p&gt;In this use case, we’ll synchronize two asynchronous jobs in a concurrent queue. Besides, we also examine the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;value&lt;/code&gt; param in the initializer with the value of 0.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;&lt;strong&gt;Context:&lt;/strong&gt; We have one concurrent queue with two asynchronous jobs, Download Image and Download Frame, dispatched to it. We want to simultaneously download the image and the frame, then combine them in either job, Download Frame for instance.&lt;/em&gt;&lt;/p&gt;

&lt;div class=&quot;language-swift highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;queue&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;DispatchQueue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;label&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;queue&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;attributes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;concurrent&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;semaphore&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;DispatchSemaphore&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// Download Image job.&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;queue&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;kt&quot;&gt;Thread&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;sleep&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;forTimeInterval&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;0.5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;nf&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Downloaded image.&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;signal&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;semaphore&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;signal&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
    &lt;span class=&quot;nf&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Signal:&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;signal&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// Download Frame job.&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;queue&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;kt&quot;&gt;Thread&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;sleep&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;forTimeInterval&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;0.9&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;nf&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Downloaded frame.&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// Await Download Image job to complete.&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;semaphore&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;wait&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
    &lt;span class=&quot;nf&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Combine image and frame.&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// Downloaded frame.&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// Downloaded image.&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// Combine image and frame.&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// Signal: 1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;We created a semaphore with 0 as the initial value which means that for any first &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;wait()&lt;/code&gt; call, it’ll hang there until there’s a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;signal()&lt;/code&gt; call. This is useful when you want to use semaphore as a lock or a synchronization flag since you don’t know or have a finite pool of resources. Back to our code above, the two &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Thread.sleep(forTimeInterval:)&lt;/code&gt; are just simulating the download process which may take an arbitrary time to complete. Even though the Download Frame job finishes first, it needs to wait for the Download Image job to be done before doing the next step. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;semaphore.wait()&lt;/code&gt; will decrement the value of the semaphore, from 0 to -1, and start waiting. In contrast, when &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;semaphore.signal()&lt;/code&gt; is called, it increments the semaphore back to 0 and signals the Download Frame job to continue its execution.&lt;/p&gt;

&lt;p&gt;An interesting thing is if we swap the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Thread.sleep(forTimeInterval:)&lt;/code&gt; between two jobs to let the Download Image job finishes first, everything will still work well, except a small difference.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;// Downloaded image.
// Signal: 0
// Downloaded frame.
// Combine image and frame.
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Can you figure it out? It’s the value of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;signal&lt;/code&gt;. In the earlier scenario, the value is 1, whilst 0 in the latter. What does it mean? The order of calls of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;signal()&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;wait()&lt;/code&gt; doesn’t matter as long as you keep them balanced. If there’s a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;wait()&lt;/code&gt; call before &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;signal()&lt;/code&gt; and there’s something waiting for a signal, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;signal()&lt;/code&gt; will return a non-zero value to indicate that. In reverse, it just returns zero so that you understand there’s no job waiting to execute, then the corresponding &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;wait()&lt;/code&gt; call returns immediately.&lt;/p&gt;

&lt;p&gt;Again illustration is the best way to explain.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/figures/20170617-2.png&quot; alt=&quot;Use case 1&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;use-case-2&quot;&gt;Use case 2&lt;/h2&gt;

&lt;p&gt;In some cases, we want to limit the number of concurrent jobs. For example, we need to download a bunch of images but want only 2 of them at the same time. This actually can be done by using higher level API &lt;a href=&quot;https://developer.apple.com/documentation/foundation/operationqueue&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;OperationQueue&lt;/code&gt;&lt;/a&gt;. Here is when we use semaphore as a resource pool.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;&lt;strong&gt;Context:&lt;/strong&gt; We have one concurrent queue. We dispatch many Download Image jobs to that queue and maximum 2 of them should be run simultaneously.&lt;/em&gt;&lt;/p&gt;

&lt;div class=&quot;language-swift highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;queue&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;DispatchQueue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;label&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;queue&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;attributes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;concurrent&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;semaphore&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;DispatchSemaphore&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;..&amp;lt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;10&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;queue&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;semaphore&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;wait&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
        &lt;span class=&quot;nf&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Downloading image&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;timeInterval&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;TimeInterval&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;0.5&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;arc4random_uniform&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;1.0&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;1.0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;1.0&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Double&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;arc4random_uniform&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;kt&quot;&gt;Thread&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;sleep&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;forTimeInterval&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;timeInterval&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;nf&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Downloaded image&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;semaphore&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;signal&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// Downloading image 0&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// Downloading image 1&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// Downloaded image 0&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// Downloading image 2&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// Downloaded image 2&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// Downloading image 3&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// Downloaded image 1&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// Downloading image 4&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// Downloaded image 4&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// Downloading image 5&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// Downloaded image 3&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// Downloading image 6&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// Downloaded image 5&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// Downloading image 7&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// Downloaded image 6&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// Downloading image 8&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// Downloaded image 7&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// Downloading image 9&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// Downloaded image 9&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// Downloaded image 8&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;In this example, I randomized the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;timeInterval&lt;/code&gt; to simulate the download time. Looking at the log, you’ll see that initial only the image 0 and 1 are downloaded simultaneously. When image 0 is done, image 2 gets started, and the number of concurrent downloads still stays at 2. It keeps doing so until all images are downloaded.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/figures/20170617-3.png&quot; alt=&quot;Use case 2&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;Semaphore is a simple yet useful tool to solve concurrency problems. In conjunction with other APIs in GCD, and higher level APIs like &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;OperationQueue&lt;/code&gt;, you can create solutions for more complex problems.&lt;/p&gt;
</description>
        <pubDate>Sat, 17 Jun 2017 00:00:00 +0000</pubDate>
        <link>http://blog.vinhis.me/2017/06/17/concurrent-programing-with-semaphore.html</link>
        <guid isPermaLink="true">http://blog.vinhis.me/2017/06/17/concurrent-programing-with-semaphore.html</guid>
        
        
      </item>
    
      <item>
        <title>Bullet list on iOS with TextKit</title>
        <description>&lt;p&gt;In a recent project, I needed to display and edit bullet lists on iOS, i.e. as part of a rich text editor. After rounds of searching on Google and Stack Overflow, I could not find any satisfying answers. The most common solution is adding a bullet character right in front of each item in the list, which is good enough in most of cases, but not in mine. So what exactly are my requirements? Quite straightforward, just few things:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;First, of course, display a bullet list.&lt;/li&gt;
  &lt;li&gt;When changing text alignment, bullets are still aligned nicely on the left side, regardless of the alignment which can be left, center or right.&lt;/li&gt;
  &lt;li&gt;Last but not least, the ability to edit the list, i.e. edit, add or remove list items without the hassle of handling characters manually.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;With that in mind, I will go from the common solution mentioned earlier to the final one in this post.&lt;/p&gt;

&lt;h2 id=&quot;the-common-solution&quot;&gt;The common solution&lt;/h2&gt;

&lt;p&gt;To be fair, this solution is simple yet efficient in simple use cases. The idea is prepending a bullet character (•) to every new item which leads to the following.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/figures/20170416-1.png&quot; alt=&quot;1st solution left alignment&quot; /&gt;&lt;/p&gt;

&lt;p&gt;To display the above list, the string underneath would be:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;• Bullet list\n• on iOS\n• with TextKit
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This looks great when left aligned and easy to make, so no complaints at the moment. Let’s go ahead and change to center alignment.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/figures/20170416-2.png&quot; alt=&quot;1st solution center alignment&quot; /&gt;&lt;/p&gt;

&lt;p&gt;And right alignment.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/figures/20170416-3.png&quot; alt=&quot;1st solution right alignment&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Wait, the bullets should vertically align each other, shouldn’t they? Nice catch, and they should keep intact on the left side as well. Because we include the bullet in the item and treat it as the item’s content, no wonder why this happens. Another problem that does not show itself visually: when we edit an item, we can actually remove the bullet character and the space between it and the text. Moreover, when we add an item, the bullet does not come for free, we need to prepend it again to the new item’s content. That being said, it is solvable by manually handling the editing action, both for adding a new item and removing an item, which does not appeal to me. There must be a better way.&lt;/p&gt;

&lt;p&gt;So far, we have a nice way to display a bullet list on left alignment, with limitations on other alignments and tedious editing approach.&lt;/p&gt;

&lt;h2 id=&quot;first-attempt-draw-bullets&quot;&gt;First attempt, draw bullets&lt;/h2&gt;

&lt;p&gt;Usually, we should address problems one by one, divide and conquer. However, in this situation, we can kill two birds with one stone as they boil down to one actual problem. Should we consider the bullet character as the item’s content? That is the root question for this problem. Undoubtedly, the answer would be a big no. Since we analyzed it earlier, if the bullet character is a part of an item’s content, more effort is needed to handle it properly and this process is error-prone. Better to let the system do its job unless we have a really special need. With that said, we have already eliminated one problem which is to manually handling editing, and direct all focus to the other problem.&lt;/p&gt;

&lt;p&gt;You might think: too many words, too much explanation, where is the code, how to use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;TextKit&lt;/code&gt;?&lt;/p&gt;

&lt;p&gt;Wait for it, here we go. For the sake of brevity, I will not introduce &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;TextKit&lt;/code&gt; and its components, but will explain it with usage and only the parts used to solve the problem. However, it is worth to quote the following statement from &lt;a href=&quot;https://developer.apple.com/library/content/documentation/StringsTextFonts/Conceptual/TextAndWebiPhoneOS/CustomTextProcessing/CustomTextProcessing.html&quot;&gt;Apple’s documentation&lt;/a&gt; to understand the concept of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;TextKit&lt;/code&gt;.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;In Text Kit, an &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;NSTextStorage&lt;/code&gt; object stores the text that is displayed by a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;UITextView&lt;/code&gt; object and laid out by an &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;NSLayoutManager&lt;/code&gt; object into an area defined by &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;NSTextContainer&lt;/code&gt; object.
And here is the relationship between them.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;img src=&quot;/figures/20170416-4.png&quot; alt=&quot;TextKit components relationship&quot; /&gt;&lt;/p&gt;

&lt;p&gt;What we are trying to do is drawing a bullet in each item. We have three candidates to look into: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;UITextView&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;NSLayoutManager&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;NSTextContainer&lt;/code&gt;. Among these, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;NSLayoutManager&lt;/code&gt; is the most promising one. We pass on &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;NSTextStorage&lt;/code&gt; because its name implies its job is related to text storage and we do not touch the text in any way. There are a bunch of methods in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;NSLayoutManager&lt;/code&gt;, we do not know which one to use to achieve our goal. Most of them have &lt;em&gt;glyph&lt;/em&gt; or &lt;em&gt;line fragment&lt;/em&gt; in their name. &lt;em&gt;In typography, a glyph is an elemental symbol within an agreed set of symbols, intended to represent a readable character for the purposes of writing&lt;/em&gt; (&lt;a href=&quot;https://en.m.wikipedia.org/wiki/Glyph&quot;&gt;Wikipedia&lt;/a&gt;). Line fragment is the extent in which a line is drawn. To draw our bullets, we need to know where to draw it and line fragment could be a hint. We will draw it on the left side of each line fragment. Fortunately, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;NSLayoutManager&lt;/code&gt; allows us to do both of these, doing custom drawing and obtaining line fragments via.&lt;/p&gt;

&lt;div class=&quot;language-swift highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nf&quot;&gt;drawGlyphs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;forGlyphRange&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;at&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;blockquote&gt;
  &lt;p&gt;Draws the glyphs in the given glyph range, which must lie completely within a single text container.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class=&quot;language-swift highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nf&quot;&gt;enumerateLineFragments&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;forGlyphRange&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;using&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;blockquote&gt;
  &lt;p&gt;Enumerates line fragments intersecting with the given glyph range.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;We will subclass &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;NSLayoutManager&lt;/code&gt; to override these two methods and bring the bullets to life.&lt;/p&gt;

&lt;div class=&quot;language-swift highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;BulletListLayoutManager&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;NSLayoutManager&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;bulletSize&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;CGSize&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;width&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;height&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;bulletColor&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;UIColor&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;red&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;0.14&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;green&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;0.48&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;blue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;0.63&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;alpha&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;1.0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;override&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;drawGlyphs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;forGlyphRange&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;glyphsToShow&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;NSRange&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;at&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;origin&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;CGPoint&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;super&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;drawGlyphs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;forGlyphRange&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;glyphsToShow&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;at&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;origin&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

        &lt;span class=&quot;nf&quot;&gt;enumerateLineFragments&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;forGlyphRange&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;glyphsToShow&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;rect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;usedRect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;textContainer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;glyphRange&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;in&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;origin&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;CGPoint&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;usedRect&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;origin&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;y&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;usedRect&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;size&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;height&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;bulletSize&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;height&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

            &lt;span class=&quot;k&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;bulletColor&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
            &lt;span class=&quot;kt&quot;&gt;UIBezierPath&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;ovalIn&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;CGRect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;origin&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;origin&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                                        &lt;span class=&quot;nv&quot;&gt;size&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;bulletSize&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;fill&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Pretty simple, right? One thing to note here is the calculation of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;y&lt;/code&gt; of the bullet since we want it vertically aligned to the item’s content. Another thing worth mentioning is &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;super.drawGlyphs(forGlyphRange: glyphsToShow, at: origin)&lt;/code&gt;, make sure we do not forget to call it or nothing gets drawn at all.&lt;/p&gt;

&lt;p&gt;Now we create &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;NSTextView&lt;/code&gt; with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;BulletListLayoutManager&lt;/code&gt; instead of default &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;NSLayoutManager&lt;/code&gt;.&lt;/p&gt;

&lt;div class=&quot;language-swift highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;textStorage&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;NSTextStorage&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;layoutManager&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;BulletListLayoutManager&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;textStorage&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;addLayoutManager&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;layoutManager&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;textContainer&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;NSTextContainer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;size&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;zero&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;layoutManager&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;addTextContainer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;textContainer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;textView&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;UITextView&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;frame&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;CGRect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;width&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;400&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;height&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;200&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
                          &lt;span class=&quot;nv&quot;&gt;textContainer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;textContainer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The relationship between these components guides us to create and assemble them to create an &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;NSTextView&lt;/code&gt; with the underlying &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;BulletListLayoutManager&lt;/code&gt; which again is used to draw bullets. Up to this point, we have our first result.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/figures/20170416-5.png&quot; alt=&quot;Draw bullets result&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;indentation&quot;&gt;Indentation&lt;/h2&gt;

&lt;p&gt;We have drawn bullets and have them beautifully in place without any additional characters added to the item’s content, but we are not done yet. Look at the result above, you will probably notice that the bullets are overlapping the item’s content, not what we want. On the bright side, just a small adjustment can fix this. Did you know that we have control of the indent of the first line and other lines in a same paragraph by just using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;attributedText&lt;/code&gt; of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;UITextView&lt;/code&gt;? With this great support from &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;TextKit&lt;/code&gt;, it is easy to shift the right item’s content and leave a consistent space between it and the bullet.&lt;/p&gt;

&lt;div class=&quot;language-swift highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;style&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;NSMutableParagraphStyle&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;Bullet list&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;on iOS&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;with TextKit. Bullet list on iOS with TextKit.&quot;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;attributedString&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;NSMutableAttributedString&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;range&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;NSRange&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;location&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;length&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;attributedString&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;length&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;style&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;firstLineHeadIndent&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;20&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;style&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;headIndent&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;20&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;attributedString&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;addAttribute&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;NSParagraphStyleAttributeName&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                              &lt;span class=&quot;nv&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;style&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                              &lt;span class=&quot;nv&quot;&gt;range&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;range&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;textView&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;attributedText&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;attributedString&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Here we set the same indent for the first line and other lines onwards, and apply this style to the whole list to ensure we have all lines left aligned.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/figures/20170416-6.png&quot; alt=&quot;Indentation result&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Let’s test with center and right alignment.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/figures/20170416-7.png&quot; alt=&quot;Indentation center alignment result&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/figures/20170416-8.png&quot; alt=&quot;Indentation right alignment result&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;wrapped-item&quot;&gt;Wrapped item&lt;/h2&gt;

&lt;p&gt;We are almost there, just one final step. Again, look at the result we have previously, could you find anything weird? &lt;em&gt;Hint: We have only three items in the list.&lt;/em&gt; “So where is the fourth bullet come from?”, you asked. Bingo, you got it. The thing is the last item is wrapped to two lines and due to the way we draw bullets, there is one corresponding bullet for each line. Ideally, each item should only have one bullet, regardless how many lines it contains, thus we only have to draw one bullet for the first line, a.k.a the line fragment of each item. Sounds simple but how do we determine whether or not a line is the first one or second in an item? &lt;em&gt;Hint: Using the new line character.&lt;/em&gt; Let me recall the underlying string of the list.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;Bullet list\non iOS\nwith TextKit. Bullet list on iOS with TextKit.
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;From the second item, its first line is the one with the new line character &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;\n&lt;/code&gt; immediately before its content. Now we can update the previous code to adapt to this scenario.&lt;/p&gt;

&lt;div class=&quot;language-swift highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;BulletListLayoutManager&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;NSLayoutManager&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;bulletSize&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;CGSize&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;width&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;height&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;bulletColor&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;UIColor&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;red&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;0.14&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;green&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;0.48&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;blue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;0.63&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;alpha&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;1.0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;override&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;drawGlyphs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;forGlyphRange&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;glyphsToShow&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;NSRange&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;at&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;origin&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;CGPoint&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;super&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;drawGlyphs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;forGlyphRange&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;glyphsToShow&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;at&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;origin&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;guard&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;textStorage&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;textStorage&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;nf&quot;&gt;enumerateLineFragments&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;forGlyphRange&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;glyphsToShow&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;rect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;usedRect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;textContainer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;glyphRange&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;in&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;origin&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;CGPoint&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;usedRect&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;origin&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;y&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;usedRect&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;size&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;height&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;bulletSize&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;height&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;newLineRange&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;NSRange&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;location&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;length&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;glyphRange&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;location&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
                &lt;span class=&quot;n&quot;&gt;newLineRange&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;location&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;glyphRange&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;location&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;
                &lt;span class=&quot;n&quot;&gt;newLineRange&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;length&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;isNewLine&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;newLineRange&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;length&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
                &lt;span class=&quot;n&quot;&gt;isNewLine&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;textStorage&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;substring&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;with&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;newLineRange&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;isNewLine&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
                &lt;span class=&quot;k&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;bulletColor&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
                &lt;span class=&quot;kt&quot;&gt;UIBezierPath&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;ovalIn&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;CGRect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;origin&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;origin&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                                            &lt;span class=&quot;nv&quot;&gt;size&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;bulletSize&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;fill&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;We treat the first line fragment as a new line by default. For the rest lines, we get the character right in front of the content of that line, then check if it is &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;\n&lt;/code&gt;. Here we are, our final result.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/figures/20170416-9.png&quot; alt=&quot;Final result&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;I have walked you through the whole process, from thinking, making decision to implementation that was exactly in my mind while I was doing it. This is, however, just the beginning, there are still lots of room for you explore &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;TextKit&lt;/code&gt;, tweak it and make it your own solution to your problem. I can name some remaining things to improve and leave them as exercises for you.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Change bullets size according to font size.&lt;/li&gt;
  &lt;li&gt;When we change line height, content does not align to the bullet anymore, we need a fix for this.&lt;/li&gt;
  &lt;li&gt;Instead of black dot bullets, can we make other types of bullet?&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;behind-the-scene&quot;&gt;Behind the scene&lt;/h2&gt;

&lt;p&gt;I obscured some of the code to keep the post focused on what matters. However, it is a two-bladed knife, while it is short, it may perplex you, so it is better to uncover everything. There are two things I did not mention throughout the post. The first one is the text view and the style have been preconfigured as below to simplify the implementation of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;BulletListLayoutManager&lt;/code&gt;.&lt;/p&gt;

&lt;div class=&quot;language-swift highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;textView&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;textContainerInset&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;zero&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;textView&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;textContainer&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;lineFragmentPadding&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;textView&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;layoutManager&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;usesFontLeading&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;false&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;style&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;minimumLineHeight&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;fontSize&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;style&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;maximumLineHeight&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;fontSize&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;And if you notice, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;string.substring()&lt;/code&gt; only accepts &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Range&amp;lt;String.Index&amp;gt;&lt;/code&gt; as parameter, not &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;NSRange&lt;/code&gt;. I created an extension of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;String&lt;/code&gt; with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;NSRange&lt;/code&gt; support so that the method works seamlessly with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;NSRange&lt;/code&gt;.&lt;/p&gt;

&lt;div class=&quot;language-swift highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;extension&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;

    &lt;span class=&quot;kd&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;substring&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;with&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;range&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;NSRange&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;startIndex&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;index&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;startIndex&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;offsetBy&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;range&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;location&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;endIndex&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;index&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;startIndex&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;offsetBy&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;range&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;length&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;substring&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;with&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;startIndex&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;..&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;endIndex&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;references&quot;&gt;References&lt;/h2&gt;

&lt;p&gt;I recommend you to go through the following references, they are great resources, talks and libraries that helped me a lot to realize this idea.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://realm.io/news/tryswift-katsumi-kishikawa-mastering-textkit-swift-ios/&quot;&gt;Mastering TextKit&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://realm.io/news/altconf-zev-eisenberg-easy-beautiful-typography-bonmot-library-ios-swift/&quot;&gt;Easy, Beautiful Typography with BonMot&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.objc.io/issues/5-ios7/getting-to-know-textkit/&quot;&gt;Getting to Know TextKit&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.objc.io/issues/9-strings/string-rendering/&quot;&gt;String Rendering&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/ibireme/YYText&quot;&gt;YYText&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/Raizlabs/BonMot&quot;&gt;BonMot&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</description>
        <pubDate>Sun, 16 Apr 2017 00:00:00 +0000</pubDate>
        <link>http://blog.vinhis.me/2017/04/16/bullet-list-on-ios-with-textkit.html</link>
        <guid isPermaLink="true">http://blog.vinhis.me/2017/04/16/bullet-list-on-ios-with-textkit.html</guid>
        
        
      </item>
    
      <item>
        <title>Bump version with PlistBuddy</title>
        <description>&lt;p&gt;Either you are an iOS, macOS developer or developing something in Apple ecosystem, you must be familiar with one file called &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Info.plist&lt;/code&gt;. At some point in development, for sure you want to release a new version of your app and increase that version number. With the recent find of the existence of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;PlistBuddy&lt;/code&gt;, it would be interesting to give it a try and also a small exercise for my shell scripting skill. As so this post will be about to create a simple shell script to bump version with help &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;PlistBuddy&lt;/code&gt;. Let’s kick started.&lt;/p&gt;

&lt;h2 id=&quot;whats-plist&quot;&gt;What’s plist?&lt;/h2&gt;

&lt;p&gt;In short, plist is filename extension of property list files. Usually, these files are used to store settings, they may be either user’s settings or all kinds of settings you need. In iOS,  &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Info.plist&lt;/code&gt; stores some information like bundle identifier, version, supported orientation and more.&lt;/p&gt;

&lt;p&gt;In a nutshell, plist file is a XML file, on the other hand, it is stored in XML format with a specific document type definition (DTD) defined by Apple. As described in &lt;a href=&quot;http://www.apple.com/DTDs/PropertyList-1.0.dtd&quot;&gt;http://www.apple.com/DTDs/PropertyList-1.0.dtd&lt;/a&gt;,&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-XML&quot;&gt;&amp;lt;!ENTITY % plistObject &quot;(array | data | date | dict | real | integer | string | true | false )&quot; &amp;gt;
&amp;lt;!ELEMENT plist %plistObject;&amp;gt;
&amp;lt;!ATTLIST plist version CDATA &quot;1.0&quot; &amp;gt;

&amp;lt;!-- Collections --&amp;gt;
&amp;lt;!ELEMENT array (%plistObject;)*&amp;gt;
&amp;lt;!ELEMENT dict (key, %plistObject;)*&amp;gt;
&amp;lt;!ELEMENT key (#PCDATA)&amp;gt;

&amp;lt;!--- Primitive types --&amp;gt;
&amp;lt;!ELEMENT string (#PCDATA)&amp;gt;
&amp;lt;!ELEMENT data (#PCDATA)&amp;gt; &amp;lt;!-- Contents interpreted as Base-64 encoded --&amp;gt;
&amp;lt;!ELEMENT date (#PCDATA)&amp;gt; &amp;lt;!-- Contents should conform to a subset of ISO 8601 (in particular, YYYY '-' MM '-' DD 'T' HH ':' MM ':' SS 'Z'.  Smaller units may be omitted with a loss of precision) --&amp;gt;

&amp;lt;!-- Numerical primitives --&amp;gt;
&amp;lt;!ELEMENT true EMPTY&amp;gt;  &amp;lt;!-- Boolean constant true --&amp;gt;
&amp;lt;!ELEMENT false EMPTY&amp;gt; &amp;lt;!-- Boolean constant false --&amp;gt;
&amp;lt;!ELEMENT real (#PCDATA)&amp;gt; &amp;lt;!-- Contents should represent a floating point number matching (&quot;+&quot; | &quot;-&quot;)? d+ (&quot;.&quot;d*)? (&quot;E&quot; (&quot;+&quot; | &quot;-&quot;) d+)? where d is a digit 0-9.  --&amp;gt;
&amp;lt;!ELEMENT integer (#PCDATA)&amp;gt; &amp;lt;!-- Contents should represent a (possibly signed) integer number in base 10 --&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;plist defines 10 elements, they are &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;plist&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;array&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;data&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;date&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dict&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;real&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;integer&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;string&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;true&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;false&lt;/code&gt;, corresponding to 9 supported data types. The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;plist&lt;/code&gt;, in fact, is a special one, used as the root element of a document, and follow by &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;plist&lt;/code&gt;, it must be one of the rest elements. In case of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Info.plist&lt;/code&gt;, we often see it is followed by a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dict&lt;/code&gt;, for example.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-XML&quot;&gt;&amp;lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&amp;gt;
&amp;lt;!DOCTYPE plist PUBLIC &quot;-//Apple//DTD PLIST 1.0//EN&quot; &quot;http://www.apple.com/DTDs/PropertyList-1.0.dtd&quot;&amp;gt;
&amp;lt;plist version=&quot;1.0&quot;&amp;gt;
&amp;lt;dict&amp;gt;
    &amp;lt;key&amp;gt;CFBundleDevelopmentRegion&amp;lt;/key&amp;gt;
    &amp;lt;string&amp;gt;en&amp;lt;/string&amp;gt;
&amp;lt;/dict&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dict&lt;/code&gt; receives pairs of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;key&lt;/code&gt; of other elements as its children and we can interpret it as key and value. Obviously, we can have multiple nested &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dict&lt;/code&gt; elements, just need to follow its definition &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;!ELEMENT dict (key, %plistObject;)*&amp;gt;&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;array&lt;/code&gt; is another one that needs to take note. Unlike &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dict&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;array&lt;/code&gt; does not require &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;key&lt;/code&gt;, it allows any other elements, include itself but except &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;plist&lt;/code&gt; to be its children instead. It can be nested as well as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dict&lt;/code&gt;.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-XML&quot;&gt;&amp;lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&amp;gt;
&amp;lt;!DOCTYPE plist PUBLIC &quot;-//Apple//DTD PLIST 1.0//EN&quot; &quot;http://www.apple.com/DTDs/PropertyList-1.0.dtd&quot;&amp;gt;
&amp;lt;plist version=&quot;1.0&quot;&amp;gt;
&amp;lt;dict&amp;gt;
    &amp;lt;key&amp;gt;UISupportedInterfaceOrientations&amp;lt;/key&amp;gt;
    &amp;lt;array&amp;gt;
        &amp;lt;string&amp;gt;UIInterfaceOrientationPortrait&amp;lt;/string&amp;gt;
        &amp;lt;string&amp;gt;UIInterfaceOrientationLandscapeLeft&amp;lt;/string&amp;gt;
        &amp;lt;string&amp;gt;UIInterfaceOrientationLandscapeRight&amp;lt;/string&amp;gt;
    &amp;lt;/array&amp;gt;
&amp;lt;/dict&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;In the combination of 9 elements and nested ability of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dict&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;array&lt;/code&gt;, we can create complex data structures to persist almost necessary settings and information.&lt;/p&gt;

&lt;h2 id=&quot;whats-plistbuddy&quot;&gt;What’s PlistBuddy?&lt;/h2&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;PlistBuddy&lt;/code&gt; is a command line tool to manipulate plist file. It can be run in interactive mode or execute and exit mode. In interactive mode, we can write commands and their parameters, then save our work with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Save&lt;/code&gt; command. Likewise, in execute and exit mode, we stringifies commands and parameters, and pass these strings as values of option &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;-c&lt;/code&gt;. For example, we want to read the version in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Info.plist&lt;/code&gt;, the complete command will look like this.&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;/usr/libexec/PlistBuddy &lt;span class=&quot;nt&quot;&gt;-c&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'Print CFBundleShortVersionString'&lt;/span&gt; Info.plist
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;em&gt;&lt;strong&gt;Note:&lt;/strong&gt; &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;PlistBuddy&lt;/code&gt; is not in the path like &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/usr/bin&lt;/code&gt;, therefore we need to use the full path or we need to add &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/usr/libexec/&lt;/code&gt; to the environment variable &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;PATH&lt;/code&gt;&lt;/em&gt;.&lt;/p&gt;

&lt;h2 id=&quot;bump-version&quot;&gt;Bump version&lt;/h2&gt;

&lt;p&gt;Bump version is action to update the version of an app, a library or anything having a version tagged to it, to a higher number. If you are using &lt;a href=&quot;https://semver.org&quot;&gt;semver&lt;/a&gt;, the version number will consist of 3 components: major, minor and patch, in the format of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;major&amp;gt;.&amp;lt;minor&amp;gt;.&amp;lt;patch&amp;gt;&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;We do bump version quite frequently so it is a good idea to automate this action instead of manually changing it, through Xcode for example.&lt;/p&gt;

&lt;p&gt;You might be thinking of using &lt;a href=&quot;https://fastlane.tools&quot;&gt;Fastlane&lt;/a&gt; to do this. Yeah, it is a great tool for automation and if you haven’t heard or used it, I highly recommend to give it a try, it is worth and would save you plenty of time. &lt;a href=&quot;https://developer.apple.com/legacy/library/documentation/Darwin/Reference/ManPages/man1/agvtool.1.html&quot;&gt;agvtool&lt;/a&gt; is an another alternative to do this. Version-related actions in Fastlane, like &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;increment_version_number&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;get_version_number&lt;/code&gt;, boil down to use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;avgtool&lt;/code&gt; themselves.&lt;/p&gt;

&lt;p&gt;However, for the sake of shell script exercise, I will walk you through everything from ground, of course, with the use of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;PlistBuddy&lt;/code&gt; I have just introduced above.&lt;/p&gt;

&lt;p&gt;The idea is pretty simple, we will go step by step as below:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Read the current version from &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Info.plist&lt;/code&gt;.&lt;/li&gt;
  &lt;li&gt;Extract the version component.&lt;/li&gt;
  &lt;li&gt;Increase the version.&lt;/li&gt;
  &lt;li&gt;Write the new version to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Info.plist&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3 id=&quot;read-the-current-version&quot;&gt;Read the current version&lt;/h3&gt;

&lt;p&gt;Actually, this step is already revealed so here I just recall and modify it a bit to store the result in a variable.&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;version&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;$(&lt;/span&gt;/usr/libexec/PlistBuddy &lt;span class=&quot;nt&quot;&gt;-c&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'Print CFBundleShortVersionString'&lt;/span&gt; Info.plist&lt;span class=&quot;si&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Now we have the current version stored in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;version&lt;/code&gt;.&lt;/p&gt;

&lt;h3 id=&quot;extract-the-version-component&quot;&gt;Extract the version component&lt;/h3&gt;

&lt;p&gt;Next step is to separate the version to components and increase them according to our need.&lt;/p&gt;

&lt;p&gt;As mentioned earlier, we have 3 components: major, minor and patch. Except for patch, change of major or minor will reset its subsidiary component(s) to zero. For instance, we have &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;1.0.5&lt;/code&gt; and we want to increase the minor so the result will be &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;1.1.0&lt;/code&gt;, the patch is reset to zero.&lt;/p&gt;

&lt;p&gt;To break out the version, we can simply use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;read&lt;/code&gt; and change the internal field separator (IFS) to dot character &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.&lt;/code&gt;.&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;IFS&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;.&quot;&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;read &lt;/span&gt;major minor patch &lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$version&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;_&lt;strong&gt;Note:&lt;/strong&gt; An alternative is to replace &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.&lt;/code&gt; by space character ` &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;, doing so, we do not need to change &lt;/code&gt;IFS`.&lt;/p&gt;

&lt;p&gt;With the major, minor and patch in hand, we proceed to the next step.&lt;/p&gt;

&lt;h3 id=&quot;increase-the-version&quot;&gt;Increase the version&lt;/h3&gt;

&lt;p&gt;To increase the version, firstly, we need to know which component to increase, it may be either major, minor or patch. We use an argument to determine this by introducing three ones: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;major&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;minor&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;patch&lt;/code&gt; to change the major, minor and patch respectively.&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;component&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$1&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[[&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$component&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'major'&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;]]&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;then&lt;/span&gt;
    // Increase major
    // Reset minor and patch
&lt;span class=&quot;k&quot;&gt;elif&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[[&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$component&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'minor'&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;]]&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;then&lt;/span&gt;
    // Increase minor
    // Reset patch
&lt;span class=&quot;k&quot;&gt;elif&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[[&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$component&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'patch'&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;]]&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;then&lt;/span&gt;
    // Increase patch
&lt;span class=&quot;k&quot;&gt;fi&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;That is the boilerplate for checking the argument, and if the argument is other than &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;major&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;minor&lt;/code&gt; or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;patch&lt;/code&gt;, we do nothing.&lt;/p&gt;

&lt;p&gt;The rest of work in this step is just doing simple mathematics.&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[[&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$component&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'major'&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;]]&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;then
    &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;major&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;$((&lt;/span&gt;major &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;))&lt;/span&gt;
    &lt;span class=&quot;nv&quot;&gt;minor&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;0
    &lt;span class=&quot;nv&quot;&gt;patch&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;0
&lt;span class=&quot;k&quot;&gt;elif&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[[&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$component&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'minor'&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;]]&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;then
    &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;minor&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;$((&lt;/span&gt;minor &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;))&lt;/span&gt;
    &lt;span class=&quot;nv&quot;&gt;patch&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;0
&lt;span class=&quot;k&quot;&gt;elif&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[[&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$component&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'patch'&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;]]&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;then
    &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;patch&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;$((&lt;/span&gt;patch &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;))&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;fi&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Now, compose the major, minor and patch to create the new version.&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;version&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;major&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;minor&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;patch&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;write-the-new-version&quot;&gt;Write the new version&lt;/h3&gt;

&lt;p&gt;We are almost there. The final step is to write back the new version to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Info.plist&lt;/code&gt;.&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;/usr/libexec/PlistBuddy &lt;span class=&quot;nt&quot;&gt;-c&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Set CFBundleShortVersionString &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;version&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt; NVActivityIndicatorView/Info.plist
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;sum-up&quot;&gt;Sum up&lt;/h2&gt;

&lt;p&gt;Assemble everything, we have the complete shell script to bump version according which component we pass in. The gist of this complete script is also available &lt;a href=&quot;https://gist.github.com/ninjaprox/71628f262616e15cc1dcca235299e0eb&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;#!/bin/bash&lt;/span&gt;

&lt;span class=&quot;nv&quot;&gt;component&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$1&lt;/span&gt;

&lt;span class=&quot;nv&quot;&gt;version&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;$(&lt;/span&gt;/usr/libexec/PlistBuddy &lt;span class=&quot;nt&quot;&gt;-c&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'Print CFBundleShortVersionString'&lt;/span&gt; Info.plist&lt;span class=&quot;si&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;IFS&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;.&quot;&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;read &lt;/span&gt;major minor patch &lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$version&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;

&lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$version&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[[&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$component&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'major'&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;]]&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;then
    &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;major&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;$((&lt;/span&gt;major &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;))&lt;/span&gt;
    &lt;span class=&quot;nv&quot;&gt;minor&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;0
    &lt;span class=&quot;nv&quot;&gt;patch&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;0
&lt;span class=&quot;k&quot;&gt;elif&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[[&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$component&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'minor'&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;]]&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;then
    &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;minor&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;$((&lt;/span&gt;minor &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;))&lt;/span&gt;
    &lt;span class=&quot;nv&quot;&gt;patch&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;0
&lt;span class=&quot;k&quot;&gt;elif&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[[&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$component&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'patch'&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;]]&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;then
    &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;patch&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;$((&lt;/span&gt;patch &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;))&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;fi

&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;version&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;major&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;minor&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;patch&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;

&lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$version&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;

/usr/libexec/PlistBuddy &lt;span class=&quot;nt&quot;&gt;-c&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Set CFBundleShortVersionString &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;version&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt; Info.plist
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;You can add things like to create a new commit after bump version, tag the commit with the new version, it is totally open to your requirements.&lt;/p&gt;

&lt;p&gt;Bump version is just one simple example what we can do with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;PlistBuddy&lt;/code&gt;. Now we can add PlistBuddy to our toolbelt and use it anytime we need to manipulate a plist file.&lt;/p&gt;

&lt;h2 id=&quot;reference&quot;&gt;Reference&lt;/h2&gt;

&lt;p&gt;I recommend to read &lt;a href=&quot;http://neurocline.github.io/dev/2016/04/16/xcode-xcworkspace-and-xcodeproj.html&quot;&gt;Xcode - xcworkspace and xcodeproj&lt;/a&gt; to understand the structure of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;xcworkspace&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;xcodeproj&lt;/code&gt;, it is especially helpful when you need to do complex tasks. In the article, you can find other resources to dig deeper as you want.&lt;/p&gt;
</description>
        <pubDate>Sun, 26 Feb 2017 00:00:00 +0000</pubDate>
        <link>http://blog.vinhis.me/2017/02/26/bump-version-with-plistbuddy.html</link>
        <guid isPermaLink="true">http://blog.vinhis.me/2017/02/26/bump-version-with-plistbuddy.html</guid>
        
        
      </item>
    
      <item>
        <title>Should I use struct in Swift?</title>
        <description>&lt;p&gt;“Should I use struct or class?” is a common question of Swift developer. There may be something you also hear over and over again like: struct is value-semantic, struct is faster. Is it really as it being said or is there anything hidden behind? Let’s find out!&lt;/p&gt;

&lt;h2 id=&quot;value-semantic&quot;&gt;Value-semantic&lt;/h2&gt;

&lt;p&gt;It is obvious to say that struct is a value type. That means you don’t need to worry about unintended changes of value when passing around variables. For example:&lt;/p&gt;

&lt;div class=&quot;language-swift highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Backpack&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;numberOfCompartments&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Int&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;myBackpack&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Backpack&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;numberOfCompartments&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;yourBackpack&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;myBackpack&lt;/span&gt;
&lt;span class=&quot;nf&quot;&gt;assert&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;myBackpack&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;numberOfCompartments&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;yourBackpack&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;numberOfCompartments&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;
&lt;span class=&quot;nf&quot;&gt;assert&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;myBackpack&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;numberOfCompartments&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;nf&quot;&gt;assert&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;yourBackpack&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;numberOfCompartments&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Why will this help? Well, passing objects around is very common and so is mutating objects. Speaking of immutability and mutability, it is another discussion and I won’t cover it in this post. Changes on other instances in the result of changes on one is good sometimes as that may be what you want. However, more often, it is not your intention and it causes much more hassle than help. By assuring these accidental changes not happen, you are free of worry and save time for development.&lt;/p&gt;

&lt;p&gt;Even with reference type data inside struct, it will behave the same.&lt;/p&gt;

&lt;div class=&quot;language-swift highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Compartment&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; 
  &lt;span class=&quot;k&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;object&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;AnyObject&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;?&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Backpack&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;compartment&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Compartment&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;myBackpack&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Backpack&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;compartment&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Compartment&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;())&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;yourBackpack&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;myBackpack&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;yourBackpack&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;compartment&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Compartment&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;nf&quot;&gt;assert&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;myBackpack&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;compartment&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!==&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;yourBackpack&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;compartment&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;If we change from struct to class, after changing &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;compartment&lt;/code&gt; property, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;myBackpack.compartment&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;yourBackpack.compartment&lt;/code&gt; both still point to the same instance.&lt;/p&gt;

&lt;div class=&quot;language-swift highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Backpack&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;compartment&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Compartment&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// Assume that we already have proper initializer&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;myBackpack&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Backpack&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;compartment&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Compartment&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;())&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;yourBackpack&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;myBackpack&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;yourBackpack&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;compartment&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Compartment&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;nf&quot;&gt;assert&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;myBackpack&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;compartment&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;yourBackpack&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;compartment&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h4 id=&quot;copy-on-write&quot;&gt;Copy-on-write&lt;/h4&gt;

&lt;p&gt;However, one question comes up with reference type data in struct, do changes on a property of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;yourBackpack.compartment&lt;/code&gt; cause changes on &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;myBackpack.compartment&lt;/code&gt;? Yes, it does, for short answer. It is easy to understand because as mentioned above, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;yourBackpack.compartment&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;myBackpack.compartment&lt;/code&gt; are referencing to the same instance. But wait, it violates value-semantic, doesn’t it? It does surely. Luckily, there is a solution for this, or just call as a workaround.&lt;/p&gt;

&lt;p&gt;The idea is that for any change on a property of reference type data, make a copy of it first then do the change. For reading, it is not needed to do anything. If doing so, other issue raises, that is every time you change reference type data, a new copy of it will be created, this is overhead and should be avoided. Swift standard library provides a function called &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;isKnownUniquelyReferenced(_:)&lt;/code&gt; to check whether the given object is a class instance known to have a single strong reference. By using this, you can get rid of creating redundancy.&lt;/p&gt;

&lt;div class=&quot;language-swift highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;extension&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Compartment&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;NSCopying&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;copy&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;with&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;zone&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;NSZone&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;nil&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Any&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Compartment&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// Just for demo purpose&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Backpack&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;_compartment&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Compartment&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;identity&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Int&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;compartmentForReading&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Compartment&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_compartment&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;compartmentForWriting&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Compartment&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;mutating&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;get&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;isKnownUniquelyReferenced&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_compartment&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
                &lt;span class=&quot;n&quot;&gt;_compartment&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_compartment&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;copy&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;as!&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Compartment&lt;/span&gt;
                &lt;span class=&quot;nf&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;copying&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_compartment&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_compartment&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;mutating&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;set&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;_compartment&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;newValue&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    
    &lt;span class=&quot;nf&quot;&gt;init&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;compartment&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Compartment&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;identity&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_compartment&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;compartment&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;identity&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;identity&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;myBackpack&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Backpack&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;compartment&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Compartment&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(),&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;identity&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;yourBackpack&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;myBackpack&lt;/span&gt;
&lt;span class=&quot;nf&quot;&gt;assert&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;myBackpack&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;compartmentForReading&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;yourBackpack&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;compartmentForReading&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;yourBackpack&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;compartmentForWriting&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;object&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;banana&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;yourBackpack&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;identity&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;20&lt;/span&gt;
&lt;span class=&quot;nf&quot;&gt;assert&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;myBackpack&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;compartmentForReading&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!==&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;yourBackpack&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;compartmentForReading&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;nf&quot;&gt;assert&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;myBackpack&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;compartmentForReading&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;object&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;yourBackpack&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;compartmentForReading&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;object&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The indirect storage called &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;_compartment&lt;/code&gt; is used to actually store reference type data, other two computed properties &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;compartmentForReading&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;compartmentForWriting&lt;/code&gt; are for reading and writing purpose respectively. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;compartmentForReading&lt;/code&gt; simply returns the indirect storage. On the other hand, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;compartmentForWriting&lt;/code&gt;’s job is more complex. On getting, it checks if &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;_compartment&lt;/code&gt; is uniquely referenced, otherwise, it creates a new copy of the indirect storage then assign back to itself. On setting, straightforwardly, it sets a new value to the indirect storage. The consequence of this is we have separate instances and prevent unintended changes.&lt;/p&gt;

&lt;p&gt;&lt;del&gt;&lt;em&gt;&lt;strong&gt;Note:&lt;/strong&gt; You may ask why &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;(yourBackpack.compartmentForWriting).object&lt;/code&gt; instead of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;yourBackpack.compartmentForWriting.object&lt;/code&gt;? Using the later invokes getter twice and I still don’t understand this behavior in Swift, will update if finding anything.&lt;/em&gt;&lt;/del&gt; This happened because I ran it on playground. I also asked on &lt;a href=&quot;http://stackoverflow.com/questions/40316929/getter-of-computed-property-called-twice?noredirect=1##comment67891599_40316929&quot;&gt;StackOverflow&lt;/a&gt; and found a reasonable explanation for this.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;&lt;strong&gt;Caution:&lt;/strong&gt; This code doesn’t work as I expected. In fact, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;isKnownUniquelyReferenced(&amp;amp;_compartment)&lt;/code&gt; always returns &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;false&lt;/code&gt;, that results in copying every time there is a change on &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;_compartment&lt;/code&gt;’s property and it is inefficient. Same as above, will update if finding anything.&lt;/em&gt;&lt;/p&gt;

&lt;h2 id=&quot;faster&quot;&gt;Faster&lt;/h2&gt;

&lt;p&gt;There are two factors, also myths, that impacts the performance of struct, they are memory allocation and reference counting. Let’s talk about memory allocation first.&lt;/p&gt;

&lt;h4 id=&quot;memory-allocation&quot;&gt;Memory allocation&lt;/h4&gt;

&lt;p&gt;Because struct is a value type, it is stored in stack. Storing in stack is fast as stack is simple data structure with only one end to push and pop data to and from. To keep track of these actions, only one pointer is needed and it is incremented or decremented according to the action.&lt;/p&gt;

&lt;p&gt;On the contrary, storing in heap requires more effort. At first, it needs to look up for sufficient space in memory, then stores data in there. However, the whole process is not that simple, to deal with multiple access, it also needs to do lock mechanism to make it thread-safe. As a result, storing in heap is more expensive than in stack.&lt;/p&gt;

&lt;p&gt;Hmm, it seems to be true, especially when struct contains all value type data. In real world, things are more complicated and you want not only value type data but also reference type. How does struct handle this? Look at this example.&lt;/p&gt;

&lt;div class=&quot;language-swift highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Weapon&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Unicorn&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;weapon&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Weapon&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;numberOfHorns&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Int&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;numberOfHorns&lt;/code&gt; is stored in stack and it is fast. However, as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;weapon&lt;/code&gt; is reference-type, only its pointer is stored in stack but its actual data is stored in heap and it is not as fast as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;numberOfHorns&lt;/code&gt;. Therefore, struct is not really as fast as it looks at the first glare in memory allocation manner. Okay, one myth is demystified, let’s move onto the next one.&lt;/p&gt;

&lt;h4 id=&quot;reference-counting&quot;&gt;Reference counting&lt;/h4&gt;

&lt;p&gt;Working with heap requires more effort and consciousness in comparison with stack. You need to manually deallocate everything after use if memory leak is not your friend, unless there is a garbage collector or other mechanism lifting it for you under the hood. Fortunately, you don’t have to do it yourself in iOS, macOS development, the OS is smart enough to detect unused chunk of data in memory and deallocate it and the OS does that by counting references to an instance. Every time a new reference created, the reference count of corresponding instance increments, the similar thing happens on removing a reference, the count decrements. When the count is zero, the OS knows this instance is not used anymore, then deallocates it from heap and save memory for later use. No wonder, this whole process is costly.&lt;/p&gt;

&lt;p&gt;Taking advantage of not using reference counting, pure value type struct, i.e. struct has only value type data, has better performance than class. It won’t be true anymore in case of reference type struct, i.e. struct has reference type data.&lt;/p&gt;

&lt;p&gt;Let’s add few more to the above example.&lt;/p&gt;

&lt;div class=&quot;language-swift highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Shield&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Unicorn&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;weapon&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Weapon&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;shield&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Shield&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;numberOfHorns&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Int&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;tom&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Unicorn&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;weapon&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Weapon&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(),&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;shield&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Shield&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(),&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;numberOfHorns&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;There are two reference counts in the example above, one of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;weapon&lt;/code&gt; instance and one of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;shield&lt;/code&gt; instance, each is set to 1. Now we will create a new variable &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;jerry&lt;/code&gt;, then assign &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tom&lt;/code&gt; to this new one.&lt;/p&gt;

&lt;div class=&quot;language-swift highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;jerry&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;tom&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The number of references here is 4. What? Because there are 2 references to each of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;weapon&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;shield&lt;/code&gt; instance, the reference count of each is set to 2. Better understand by looking at the following illustration.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;            stack

   tom +----------------+
       | weapon         +------+
       +----------------+      |       heap
       | shield         +---+  |
       +----------------+   |  |  +-------------+
       | numberOfHorns  |   |  +--+ weapon      +--+
       +----------------+   |     +-------------+  |
                            +-----+ shield      +-----+
 jerry +----------------+         +-------------+  |  |
       | weapon         +--------------------------+  |
       +----------------+                             |
       | shield         +-----------------------------+
       +----------------+
       | numberOfHorns  |
       +----------------+
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;You may notice something turning not good. Let’s examine the same use case with class.&lt;/p&gt;

&lt;div class=&quot;language-swift highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Unicorn&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;weapon&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Weapon&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;shield&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Shield&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;numberOfHorns&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Int&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// Assume that we already have proper initializer&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;tom&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Unicorn&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;weapon&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Weapon&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(),&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;shield&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Shield&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(),&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;numberOfHorns&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;jerry&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;tom&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Now see the graph.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;     stack                    heap

+-------------+          +----------------+
| tom         +----------+ weapon         |
+-------------+          +----------------+
| jerry       +----------+ shield         |
+-------------+          +----------------+
                         | numberOfHorns  |
                         +----------------+
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;There are only 2 references and clearly, class outperforms in this scenario. Myth number 2, solved!&lt;/p&gt;

&lt;p&gt;With new things introduced in Foundation framework, using proper data type will help avoid these problems whilst taking advantage of struct.&lt;/p&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;At the first glare, we all seem to be dazzled by struct. Only after having a closer look, we discover many things hidden behind, these don’t discourage us from using struct but give us better understanding and help make better decision. Ultimately, there is no silver bullet at all, everything is devised with purpose and should be used with awareness.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;It’s not the fault of the tool, it’s he doesn’t learn it more.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2 id=&quot;reference&quot;&gt;Reference&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://developer.apple.com/videos/play/wwdc2015/414&quot;&gt;Building Better Apps with Value Types in Swift (WWDC 2015 - Session 414)&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://developer.apple.com/videos/play/wwdc2016/416&quot;&gt;Understanding Swift Performance (WWDC 2016 - Session 416)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</description>
        <pubDate>Fri, 28 Oct 2016 00:00:00 +0000</pubDate>
        <link>http://blog.vinhis.me/2016/10/28/should-i-use-struct-in-swift.html</link>
        <guid isPermaLink="true">http://blog.vinhis.me/2016/10/28/should-i-use-struct-in-swift.html</guid>
        
        
      </item>
    
      <item>
        <title>Understanding UIView’s transform property (final)</title>
        <description>&lt;p&gt;In previous part, we talked about 4 properties of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;UIView&lt;/code&gt; and relationships between them. This part we cover operations with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;transform&lt;/code&gt; and how to persist &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;UIView&lt;/code&gt; information. Let’s go!&lt;/p&gt;

&lt;h2 id=&quot;transform-operations&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;transform&lt;/code&gt; operations&lt;/h2&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;transform&lt;/code&gt; is type of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CGAffineTransform&lt;/code&gt; and it represents a matrix used for affine transformation. Speaking of the matrix and and affine transformation, it is beyond context of this article, but if you wonder and want to learn more, this &lt;a href=&quot;https://en.wikipedia.org/wiki/Affine_transformation&quot;&gt;wiki&lt;/a&gt; would be a good start.&lt;/p&gt;

&lt;p&gt;In brief, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;transform&lt;/code&gt; includes 6 matter values &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;a&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;b&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;c&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;d&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;x&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;y&lt;/code&gt; as the figure below.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://developer.apple.com/library/content/documentation/GraphicsImaging/Conceptual/drawingwithquartz2d/Art/equation01.gif&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;a&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;d&lt;/code&gt; are for scale, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;x&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;y&lt;/code&gt; are for translation and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;a&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;b&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;c&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;d&lt;/code&gt; are for rotation. However, usually, we use only scale and rotation of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;transform&lt;/code&gt; as for translation, we can simply use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;center&lt;/code&gt; property to position a view in its superview.&lt;/p&gt;

&lt;p&gt;When &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;transform&lt;/code&gt; is used for only one transformation, it is straightforward to extract that information, e.g. factor of scale or angle of rotation. In most of cases, however, we use combination of scale and rotation, that makes transformation extraction more tangled.  Thanks to mathematics, we already have equations for this and only need to convert to code.&lt;/p&gt;

&lt;hr /&gt;

&lt;h4 id=&quot;extract&quot;&gt;Extract&lt;/h4&gt;

&lt;p&gt;Right below is snippet for scale extraction&lt;/p&gt;

&lt;div class=&quot;language-swift highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;scaleOf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;transform&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;CGAffineTransform&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;CGPoint&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;xScale&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;sqrt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;transform&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;transform&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;transform&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;c&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;transform&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;yScale&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;sqrt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;transform&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;b&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;transform&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;b&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;transform&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;d&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;transform&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;d&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;CGPoint&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;xScale&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;yScale&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;and for rotation.&lt;/p&gt;

&lt;div class=&quot;language-swift highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;rotationOf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;transform&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;CGAffineTransform&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;CGFloat&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;CGFloat&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;atan2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;transform&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;transform&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h4 id=&quot;restore&quot;&gt;Restore&lt;/h4&gt;

&lt;p&gt;In reverse, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CoreGraphics&lt;/code&gt; provides handy functions to create &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CGAffineTransform&lt;/code&gt; from transformation information.&lt;/p&gt;

&lt;div class=&quot;language-swift highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;view&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;transform&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;CGAffineTransformMakeRotation&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;angle_in_radian&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// Create CGAffineTransform of rotation transformation &lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;view&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;transform&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;CGAffineTransformMakeScale&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;xScale&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;yScale&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// Create CGAffineTransform of scale transformation&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Because order of transformation matters, in case of combination of scale and rotation, we should persist the whole &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;transform&lt;/code&gt;, i.e., &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;a&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;b&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;c&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;d&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;x&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;y&lt;/code&gt; values, and use it to restore itself.&lt;/p&gt;

&lt;div class=&quot;language-swift highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;view&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;transform&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;CGAffineTransform&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;d&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;d&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;tx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;ty&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;persistence&quot;&gt;Persistence&lt;/h2&gt;

&lt;p&gt;When comes with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;UIView&lt;/code&gt; information persistence, especially with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;transform&lt;/code&gt; is applied, note following things:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;frame&lt;/code&gt; is invalid so we shouldn’t use it to position or measure view.&lt;/li&gt;
  &lt;li&gt;Though &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;frame&lt;/code&gt; is invalid, there is way to calculate actual values and use them for positioning or sizing of view.&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;center&lt;/code&gt; is recommended to position view.&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bounds.size&lt;/code&gt; is recommended to measure view.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So what information we need to persist? They are position in superview, size and transformation. With transformation, we can persist &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;transform&lt;/code&gt; as a whole or individual one.&lt;/p&gt;

&lt;h4 id=&quot;position&quot;&gt;Position&lt;/h4&gt;

&lt;p&gt;The best way is to persist &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;center&lt;/code&gt;, as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;center&lt;/code&gt; is independent of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;transform&lt;/code&gt;, it is safe to position view regardless of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;transform&lt;/code&gt;.&lt;/p&gt;

&lt;div class=&quot;language-swift highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;persistedCenter&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;view&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;center&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;However, in some scenarios, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;frame.origin&lt;/code&gt; may be useful, then we need calculation on restoration to convert &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;frame.origin&lt;/code&gt; back to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;center&lt;/code&gt;. It will be there later.&lt;/p&gt;

&lt;div class=&quot;language-swift highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;persistedPosition&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;frame&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;origin&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h4 id=&quot;size&quot;&gt;Size&lt;/h4&gt;

&lt;p&gt;Both &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bounds.size&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;frame.size&lt;/code&gt; cannot be used for size persistence, because they do not reflect correct view’s size. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bounds.size&lt;/code&gt; is original value before transformation. And &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;frame.size&lt;/code&gt; is size of boundary view, not actual view.&lt;/p&gt;

&lt;p&gt;So how? The answer is to use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bounds.size&lt;/code&gt; and scale transformation and it is pretty simple.&lt;/p&gt;

&lt;div class=&quot;language-swift highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;scale&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;scaleOf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;view&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;transform&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;persistedSize&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;CGSize&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;width&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;view&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;bounds&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;size&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;width&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;scale&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;height&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;view&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;bounds&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;size&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;height&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;scale&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;If we count actual view’s size in persistence, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;transform&lt;/code&gt; we persist should contain only rotation transformation. This is due of restore phrase later. Otherwise, restoration will get unnecessary calculation, now or later is of your choice. Then I choose now and it also makes more sense to persist real view’s size than its original one.&lt;/p&gt;

&lt;h4 id=&quot;transformation&quot;&gt;Transformation&lt;/h4&gt;

&lt;p&gt;How to persist position and size affects how to do with transformation, actually, only size does. As stated right above, if we persist actual view’s size, rotation is the only thing we need for transformation.&lt;/p&gt;

&lt;div class=&quot;language-swift highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;persistedRotation&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;rotationOf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;view&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;transform&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;How about original view’s size? So we have to persist the whole &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;transform&lt;/code&gt; by using its values.&lt;/p&gt;

&lt;div class=&quot;language-swift highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;view&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;transform&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;b&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;view&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;transform&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;c&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;view&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;transform&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;c&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;d&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;view&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;transform&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;d&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;With these values, it is easy to restore &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;transform&lt;/code&gt; as talked above.&lt;/p&gt;

&lt;h4 id=&quot;restore-1&quot;&gt;Restore&lt;/h4&gt;

&lt;p&gt;Make assumption that we are persisting actual view’s size, its rotation and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;center&lt;/code&gt;, now it is time to restore the view from that.&lt;/p&gt;

&lt;div class=&quot;language-swift highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;view&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;UIView&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;frame&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;CGRect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;width&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;persistedSize&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;width&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;height&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;persistedSize&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;height&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;view&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;transform&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;CGAffineTransformMakeRotation&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;persistedRotation&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;view&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;center&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;persistedCenter&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;How about &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;frame.origin&lt;/code&gt; for position? Here we are.&lt;/p&gt;

&lt;div class=&quot;language-swift highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;view&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;UIView&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;frame&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;CGRect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;width&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;persistedSize&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;width&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;height&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;persistedSize&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;height&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;view&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;transform&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;CGAffineTransformMakeRotation&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;persistedRotation&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;view&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;center&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;CGPoint&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;persistedPosition&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;view&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;frame&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;size&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;width&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;persistedPosition&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;y&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;view&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;frame&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;size&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;height&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;There are still many more to talk about &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;UIView&lt;/code&gt;, however, with this article, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;transform&lt;/code&gt; property is not scary anymore, huh? From here, we can keep learning &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;layer.anchorPoint&lt;/code&gt; which is also relevant to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;transform&lt;/code&gt;, animation with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;transform&lt;/code&gt; and other 3 properties, etc. Happy learning!&lt;/p&gt;
</description>
        <pubDate>Sat, 27 Aug 2016 00:00:00 +0000</pubDate>
        <link>http://blog.vinhis.me/2016/08/27/understand-uiview-transformation-property-final.html</link>
        <guid isPermaLink="true">http://blog.vinhis.me/2016/08/27/understand-uiview-transformation-property-final.html</guid>
        
        
      </item>
    
      <item>
        <title>Understanding UIView’s transform property (part 1)</title>
        <description>&lt;p&gt;Working with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;transform&lt;/code&gt; property of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;UIView&lt;/code&gt; might be frustrated at the first time. Confusion of using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;transform&lt;/code&gt; leads to difficulty in controlling &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;UIView&lt;/code&gt; as well as persisting &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;UIView&lt;/code&gt; information. This article helps demystify this.&lt;/p&gt;

&lt;h2 id=&quot;basics&quot;&gt;Basics&lt;/h2&gt;

&lt;p&gt;Before going clarify &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;transform&lt;/code&gt; property and how it works, let’s remind some basics. With a bunch of properties and methods in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;UIView&lt;/code&gt;, there are only four that we need in context of this article and the rest of it focuses only these four properties to try to explain how &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;transform&lt;/code&gt; works.&lt;/p&gt;

&lt;dl&gt;
  &lt;dt&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;frame&lt;/code&gt;&lt;/dt&gt;
  &lt;dd&gt;The frame rectangle, which describes the view’s location and size in its &lt;strong&gt;superview’s coordinate system&lt;/strong&gt;.&lt;/dd&gt;
  &lt;dt&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bounds&lt;/code&gt;&lt;/dt&gt;
  &lt;dd&gt;The bounds rectangle, which describes the view’s location and size in its &lt;strong&gt;own coordinate system&lt;/strong&gt;.&lt;/dd&gt;
  &lt;dt&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;center&lt;/code&gt;&lt;/dt&gt;
  &lt;dd&gt;The center of the frame, i.e., it is location of the view’s center point in its &lt;strong&gt;superview’s coordinate system&lt;/strong&gt;.&lt;/dd&gt;
  &lt;dt&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;transform&lt;/code&gt;&lt;/dt&gt;
  &lt;dd&gt;Specifies the transform applied to the receiver, &lt;strong&gt;relative to the center of its bounds&lt;/strong&gt;.
    &lt;blockquote&gt;
      &lt;p&gt;&lt;strong&gt;WARNING&lt;/strong&gt;
If this property is not the identity transform, the value of the frame property is undefined and therefore should be ignored.&lt;/p&gt;
    &lt;/blockquote&gt;
  &lt;/dd&gt;
&lt;/dl&gt;

&lt;p&gt;These four properties have binding of each other, changes on one cause changes mostly on others. Simplest, for example, changes on &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;center&lt;/code&gt; modify &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;frame&lt;/code&gt;, and vise versa. We talk more about these relationships right below.&lt;/p&gt;

&lt;h2 id=&quot;relationships&quot;&gt;Relationships&lt;/h2&gt;

&lt;h4 id=&quot;frame-changes&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;frame&lt;/code&gt; changes&lt;/h4&gt;

&lt;p&gt;When &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;frame&lt;/code&gt; changes, obviously, it causes change of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bounds&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;center&lt;/code&gt; but remains &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;transform&lt;/code&gt;.  Changes on &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;frame.origin&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;frame.size&lt;/code&gt; result in changes on &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;center&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bounds.size&lt;/code&gt; respectively.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;frame.origin&lt;/code&gt; &lt;em&gt;changes&lt;/em&gt; &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;center&lt;/code&gt;
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;frame.size&lt;/code&gt; &lt;em&gt;changes&lt;/em&gt; &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bounds.size&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h4 id=&quot;bounds-changes&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bounds&lt;/code&gt; changes&lt;/h4&gt;

&lt;p&gt;As &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bounds.size&lt;/code&gt; changes, the whole &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;frame&lt;/code&gt; changes, I mean both &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;frame.origin&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;frame.size&lt;/code&gt;. The reason is this change is relative to the view’s center point, the center point keeps the same while 4 corners move inward or outward depending on decreasing or increasing the size. System now reflects these changes to the view’s superview’s coordinate by change the view’s &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;frame&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/figures/20160823-1.png&quot; alt=&quot;`bounds.size` changes&quot; /&gt;&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bounds.size&lt;/code&gt; &lt;em&gt;changes&lt;/em&gt; &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;frame.origin&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;frame.size&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;frame.size&lt;/code&gt; is always equal to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bounds.size&lt;/code&gt; on the other hand.&lt;/p&gt;

&lt;p&gt;How about &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bounds.origin&lt;/code&gt;? It does not affect &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;frame&lt;/code&gt; at all. It just shifts the view’s content, like the way you see in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;UIScrollView&lt;/code&gt;.&lt;/p&gt;

&lt;h4 id=&quot;center-changes&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;center&lt;/code&gt; changes&lt;/h4&gt;

&lt;p&gt;Because &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;center&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;frame&lt;/code&gt; are both determined in superview ‘s coordinate system, i.e., they are in the same coordinate system, no wonder that they affect each other.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;center&lt;/code&gt; &lt;em&gt;changes&lt;/em&gt; &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;frame.origin&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h4 id=&quot;transform-changes&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;transform&lt;/code&gt; changes&lt;/h4&gt;

&lt;p&gt;Now here is the most confusing of 4 properties. Don’t panic. It is purely mathematics. What, mathematics? It is even more scary. No, even if you are not math genius, understanding it must not be hard.&lt;/p&gt;

&lt;p&gt;The idea is that &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;transform&lt;/code&gt; is, simplified-explanation, a calculation being applied to a view to convert every single point inside the view to new position in the same coordinate system of the view’s superview. Keeping superview’s coordinate system untouched helps diminish effort to work with other views that do not use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;transform&lt;/code&gt;, i.e., &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;transform&lt;/code&gt; is identity.&lt;/p&gt;

&lt;dl&gt;
  &lt;dt&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;transform&lt;/code&gt;&lt;/dt&gt;
  &lt;dd&gt;input [some calculations happen here]=&amp;gt; output&lt;/dd&gt;
&lt;/dl&gt;

&lt;p&gt;As superview needs a straight rectangle to determine position and size of its child view, in case child view does not have one, e.g. it is rotated,  superview uses a boundary to do this job. The boundary is the smallest straight rectangle that encloses completely the view.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/figures/20160823-2.png&quot; alt=&quot;View's boundary&quot; /&gt;&lt;/p&gt;

&lt;h6 id=&quot;scale&quot;&gt;Scale&lt;/h6&gt;

&lt;p&gt;Now let’s scale up and down a view. Recall the earlier explanation of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;transform&lt;/code&gt;, when scaling a view, in fact &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;transform&lt;/code&gt; does not change real view’s size but only do conversion the size to new size in view’s superview and display it. This conversion, easy to guess, has effect on view’s &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;frame&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/figures/20160823-3.png&quot; alt=&quot;Scale&quot; /&gt;&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;transform&lt;/code&gt; &lt;em&gt;changes&lt;/em&gt; &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;frame&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;What if we change &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;frame&lt;/code&gt; after applied scale? Good question. Remember &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;frame.size&lt;/code&gt; is always equal to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bounds.size&lt;/code&gt; said earlier? New &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;frame.size&lt;/code&gt; comes from old &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;frame.size&lt;/code&gt;, actually comes from &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bounds.size&lt;/code&gt;.  On forward way, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bounds.size&lt;/code&gt; is as input and new &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;frame.size&lt;/code&gt; is as output. And &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;frame.size&lt;/code&gt; is as input and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bounds.size&lt;/code&gt; is as output in reverse.&lt;/p&gt;

&lt;p&gt;It is supposed to be but it is not unfortunately. As warning in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;transform&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;frame&lt;/code&gt; should be ignored. In fact, we still can use it to new &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;frame&lt;/code&gt; value after scaled, as well as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;frame&lt;/code&gt; of boundary being mentioned right below, but it is not recommended to set value, even with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;frame.origin&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Therefore the answer is shouldn’t do.&lt;/p&gt;

&lt;h6 id=&quot;rotation&quot;&gt;Rotation&lt;/h6&gt;

&lt;p&gt;Now it is time for rotation. As in earlier figure, when a view is rotated, it does not longer have a straight rectangle to represent in its superview. This comes to superview needs a boundary to position and measure the view. The view’s &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;frame&lt;/code&gt; now is actually the boundary’s &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;frame&lt;/code&gt; and it does not literally reflect view’s position and size anymore.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;transform&lt;/code&gt; &lt;em&gt;changes&lt;/em&gt; &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;frame&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h6 id=&quot;combination&quot;&gt;Combination&lt;/h6&gt;

&lt;p&gt;In combination of scale and rotation, the same principle is applied.&lt;/p&gt;

&lt;p&gt; &lt;/p&gt;

&lt;p&gt;In this part, we have better idea of 4 properties and their relationship. In the next one, we will talk more about &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;transform&lt;/code&gt;, how to use it and applications, especially on persistence.&lt;/p&gt;
</description>
        <pubDate>Tue, 23 Aug 2016 00:00:00 +0000</pubDate>
        <link>http://blog.vinhis.me/2016/08/23/understand-uiview-transformation-property-part1.html</link>
        <guid isPermaLink="true">http://blog.vinhis.me/2016/08/23/understand-uiview-transformation-property-part1.html</guid>
        
        
      </item>
    
  </channel>
</rss>
