<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Raul Riera</title>
    <description>The latest articles on DEV Community by Raul Riera (@raulriera).</description>
    <link>https://dev.to/raulriera</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F83495%2Fbc484b49-126a-4fc7-93d7-50b7268d61bb.jpg</url>
      <title>DEV Community: Raul Riera</title>
      <link>https://dev.to/raulriera</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/raulriera"/>
    <language>en</language>
    <item>
      <title>UserInterfaceLevel, the future of floating apps?</title>
      <dc:creator>Raul Riera</dc:creator>
      <pubDate>Sun, 07 Jun 2020 23:03:34 +0000</pubDate>
      <link>https://dev.to/raulriera/userinterfacelevel-the-future-of-floating-apps-5ee</link>
      <guid>https://dev.to/raulriera/userinterfacelevel-the-future-of-floating-apps-5ee</guid>
      <description>&lt;p&gt;Last year Shopify started developing the All-new POS application. There was a small problem, given that all screens are presented as full screen to the user we needed the ability to distinguish a modal screen vs the rest. iOS 13 had a great answer to this.&lt;/p&gt;

&lt;p&gt;It feels like every new iOS version adds something to &lt;code&gt;UITraitCollection&lt;/code&gt; or &lt;code&gt;UIUserActivity&lt;/code&gt;. iOS 13 was no different. There was an handy small addition to &lt;code&gt;UITraitCollection&lt;/code&gt; for apps with floating windows. That addition was &lt;a href="https://developer.apple.com/documentation/uikit/uitraitcollection/3238085-userinterfacelevel" rel="noopener noreferrer"&gt;userInterfaceLevel&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is UserInterfaceLevel?
&lt;/h2&gt;

&lt;p&gt;Apple describes it as the visual level for content in a window.  The possible values are &lt;code&gt;base&lt;/code&gt;, &lt;code&gt;elevated&lt;/code&gt;, and &lt;code&gt;unspecified&lt;/code&gt;. The first one being the window’s main content and the last one anything above it. This will be the perfect match for our need of modal windows having a dedicated background colour.&lt;/p&gt;

&lt;h2&gt;
  
  
  Using it to meet our requirement
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;import&lt;/span&gt; &lt;span class="kt"&gt;UIKit&lt;/span&gt;

&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;struct&lt;/span&gt; &lt;span class="kt"&gt;AdaptiveColor&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;/// See [UserInterfaceLevel](https://developer.apple.com/documentation/uikit/uiuserinterfacelevel) for more info.&lt;/span&gt;
    &lt;span class="kd"&gt;private(set)&lt;/span&gt; &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;base&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;light&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;UIColor&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;dark&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;UIColor&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="c1"&gt;/// The color used for content visually above your window's main content. If none is specified, the `base` color is used instead.&lt;/span&gt;
    &lt;span class="c1"&gt;///&lt;/span&gt;
    &lt;span class="c1"&gt;/// See [UserInterfaceLevel](https://developer.apple.com/documentation/uikit/uiuserinterfacelevel) for more info.&lt;/span&gt;
    &lt;span class="kd"&gt;private(set)&lt;/span&gt; &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;elevated&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;light&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;UIColor&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;dark&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;UIColor&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;init&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;light&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;UIColor&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;dark&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;UIColor&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;base&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;light&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;light&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;dark&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;dark&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;elevated&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;base&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;init&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;base&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;light&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;UIColor&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;dark&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;UIColor&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nv"&gt;elevated&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;light&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;UIColor&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;dark&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;UIColor&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;base&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;base&lt;/span&gt;
        &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;elevated&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;elevated&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;UIColor&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="k"&gt;#available&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;iOSApplicationExtension&lt;/span&gt; &lt;span class="mf"&gt;13.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kt"&gt;UIColor&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;traitCollection&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt;
                &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;isElevated&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;traitCollection&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;userInterfaceLevel&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;elevated&lt;/span&gt;
                &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;traitCollection&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;userInterfaceStyle&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dark&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;isElevated&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;elevated&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;dark&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dark&lt;/span&gt;
                &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;isElevated&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;elevated&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;light&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;light&lt;/span&gt;
                &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;light&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The previous snippet is how Shopify’s &lt;a href="https://shopify.com/pos" rel="noopener noreferrer"&gt;Point of Sale application&lt;/a&gt; is handling dynamic colours. You should focus on line #24, we detect the current elevation of the user interface and decide which of the two colour sets to use for this particular colour.&lt;/p&gt;

&lt;p&gt;Now, let’s say we want to change the background colour of a view all we need to do is:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="n"&gt;view&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;backgroundColor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;AdaptiveColor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;base&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;light&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;white&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;dark&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;black&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nv"&gt;elevated&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;light&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;lightGray&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;dark&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;gray&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;And thanks to the excellent &lt;a href="https://developer.apple.com/documentation/uikit/uiappearance" rel="noopener noreferrer"&gt;UIAppearance&lt;/a&gt; we can style our &lt;code&gt;UINavigationController&lt;/code&gt; similarly how we styled the background view, and all our screens will be displayed with the correct colour.&lt;/p&gt;

&lt;p&gt;Putting everything together into a project, it looks something like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Ftkyknud0l3rfcoop2vgu.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Ftkyknud0l3rfcoop2vgu.gif" alt="Demo"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Further reading
&lt;/h2&gt;

&lt;p&gt;That is all!, as always you can find the full source code on GitHub&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/raulriera" rel="noopener noreferrer"&gt;
        raulriera
      &lt;/a&gt; / &lt;a href="https://github.com/raulriera/technical-articles" rel="noopener noreferrer"&gt;
        technical-articles
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Just a place where I can store demo projects for my technical articles.
    &lt;/h3&gt;
  &lt;/div&gt;
&lt;/div&gt;



</description>
      <category>swift</category>
      <category>ios</category>
      <category>programming</category>
    </item>
    <item>
      <title>Undo and Redo support to iOS apps</title>
      <dc:creator>Raul Riera</dc:creator>
      <pubDate>Sun, 27 Jan 2019 19:31:00 +0000</pubDate>
      <link>https://dev.to/raulriera/undo-and-redo-support-to-ios-apps-keg</link>
      <guid>https://dev.to/raulriera/undo-and-redo-support-to-ios-apps-keg</guid>
      <description>&lt;h3&gt;
  
  
  Adding Undo and Redo support to iOS
&lt;/h3&gt;

&lt;h4&gt;
  
  
  People make mistakes. Let’s use allow undoing.
&lt;/h4&gt;

&lt;p&gt;You have accidentally shaken your phone and noticed that little alert screen that says “Undo [something]”. In this story we are going to implement Undo and Redo actions in an iOS app.&lt;/p&gt;

&lt;p&gt;By now you are making all your screens using a declarative and functional approach, right? 😉 If not, &lt;a href="https://medium.com/@raulriera/building-apps-with-functionaltabledata-c99bfaa7e2e5"&gt;you can read all about it&lt;/a&gt;. Expanding on that approach, we can easily implement undo actions into our app if all our View Controller state is encapsulated like it was demostrated in that article.&lt;/p&gt;

&lt;h4&gt;
  
  
  Looking at the documentation
&lt;/h4&gt;

&lt;p&gt;When I looked at &lt;a href="https://developer.apple.com/documentation/foundation/undomanager"&gt;Undo Manager&lt;/a&gt; it appeared like I was going to be dealing with Selectors, old Objective-C API, and whatever else was lurking underneath. I tried to get around this by creating a wrapper struct with some syntactic sugar.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;struct&lt;/span&gt; &lt;span class="kt"&gt;Undoer&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;undoManager&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;UndoManager&lt;/span&gt;
  &lt;span class="o"&gt;...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Thankfully, &lt;a href="https://medium.com/u/b52ce6710722"&gt;Geoffrey Foster&lt;/a&gt; talked me out of it and I end up choosing a better approach. By simply extending UndoManager to include one more function. Now, taking everything I had in the previous wrapper, all I was left with was this.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s---VvIyb9Y--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/1%2AT5LLjgfZ4nroHj1qT07lTw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s---VvIyb9Y--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/1%2AT5LLjgfZ4nroHj1qT07lTw.png" alt=""&gt;&lt;/a&gt;Pretty simple right?&lt;/p&gt;

&lt;p&gt;Pretty simple right? To be honest, the biggest issue with writing this short function was embracing the fact that you want to capture your variables inside the registerUndo closure, while also having it call itself.&lt;/p&gt;

&lt;h4&gt;
  
  
  Exploring the code
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://developer.apple.com/documentation/foundation/undomanager"&gt;UndoManager&lt;/a&gt; works exactly like that. It retains a copy of the data in the closure so you can revert any changes by calling undoManager.undo() or redo() for that matter. Doing so, executes our handler callback and recursively calls itself again, but this time with the values inverted. Creating that loop of undo and redo actions that we desire.&lt;/p&gt;

&lt;h4&gt;
  
  
  Fixing the bug 🙃
&lt;/h4&gt;

&lt;p&gt;There is one issue that you probably spotted by now. If we use reference types, we won’t be maintaining the previous data. Thankfully that is why we have the Codable constraint in the generic type T.&lt;/p&gt;

&lt;p&gt;By leveraging Codable, we can implement a quick and dirty version of copy to serialize and deserialze the content of the data, so we can maintain the state.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--1_jaO8Sj--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/1%2A_HfcaJ7OXOrsrWDbRa2iEA.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--1_jaO8Sj--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/1%2A_HfcaJ7OXOrsrWDbRa2iEA.png" alt=""&gt;&lt;/a&gt;Don’t @ me 🙈&lt;/p&gt;

&lt;p&gt;This is more like it, now our UndoManager can store and restore the state of any class or struct, and we barely even had to break a sweat writing this.&lt;/p&gt;

&lt;p&gt;You can find the source code of this function with a quick implementation into a View Controller in the following link.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/raulriera/technical-articles/tree/master/Adding-Undo-and-Redo%20support-to-iOS"&gt;raulriera/technical-articles&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Did I miss anything? Get in touch on Twitter: &lt;a href="https://twitter.com/raulriera"&gt;@raulriera&lt;/a&gt;&lt;/p&gt;

</description>
      <category>swift</category>
      <category>swiftprogramming</category>
      <category>userexperience</category>
      <category>ios</category>
    </item>
  </channel>
</rss>
