<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:cc="http://cyber.law.harvard.edu/rss/creativeCommonsRssModule.html">
    <channel>
        <title><![CDATA[Stories by Aron Balog on Medium]]></title>
        <description><![CDATA[Stories by Aron Balog on Medium]]></description>
        <link>https://medium.com/@aronbalog?source=rss-589f1681fc5f------2</link>
        <image>
            <url>https://cdn-images-1.medium.com/fit/c/150/150/1*AAcMW0VQX3a6-ejcTQ7PNQ.jpeg</url>
            <title>Stories by Aron Balog on Medium</title>
            <link>https://medium.com/@aronbalog?source=rss-589f1681fc5f------2</link>
        </image>
        <generator>Medium</generator>
        <lastBuildDate>Tue, 19 May 2026 06:57:02 GMT</lastBuildDate>
        <atom:link href="https://medium.com/@aronbalog/feed" rel="self" type="application/rss+xml"/>
        <webMaster><![CDATA[yourfriends@medium.com]]></webMaster>
        <atom:link href="http://medium.superfeedr.com" rel="hub"/>
        <item>
            <title><![CDATA[Spring Boot + Kotlin + GraphQL + MongoDB — Part 2: Mutations]]></title>
            <link>https://medium.com/@aronbalog/spring-boot-kotlin-graphql-mongodb-part-2-mutations-f825033bbfd3?source=rss-589f1681fc5f------2</link>
            <guid isPermaLink="false">https://medium.com/p/f825033bbfd3</guid>
            <category><![CDATA[kotlin]]></category>
            <category><![CDATA[mutation]]></category>
            <category><![CDATA[spring-boot]]></category>
            <category><![CDATA[mongodb]]></category>
            <category><![CDATA[graphql]]></category>
            <dc:creator><![CDATA[Aron Balog]]></dc:creator>
            <pubDate>Tue, 08 May 2018 21:43:31 GMT</pubDate>
            <atom:updated>2018-05-08T21:48:21.700Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/712/1*9h6OAz32ITD5rXu0zakyZg.jpeg" /></figure><h4>Hack the stack.</h4><p><a href="https://medium.com/@aronbalog/spring-boot-kotlin-graphql-mongo-e73f25df6ab9">Spring Boot + Kotlin + GraphQL + MongoDB — Part 1</a></p><p>Most discussions of GraphQL focus on data fetching, but any complete data platform needs a way to modify server-side data as well.</p><p>In REST, any request might end up causing some side-effects on the server, but by convention it’s suggested that one doesn’t use GET requests to modify data. GraphQL is similar - technically any query could be implemented to cause a data write. However, it&#39;s useful to establish a convention that any operations that cause writes should be sent explicitly via a mutation.</p><ul><li>This post is a sequel to <a href="https://medium.com/@aronbalog/spring-boot-kotlin-graphql-mongo-e73f25df6ab9">Spring Boot + Kotlin + GraphQL + MongoDB — Part 1</a>.</li><li>Demo project repository is available at GitHub.</li></ul><h3>Creating your first GraphQL mutation</h3><p>In the previous post, I tried to explain how one can fetch Person object from the MongoDB using GraphQL queries. In this post we are going to insert the Person object into a database with the GraphQL mutations. Let’s go!</p><h4>Update PersonDao</h4><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/fb5771ed908f6a99df0d065cc35b8931/href">https://medium.com/media/fb5771ed908f6a99df0d065cc35b8931/href</a></iframe><p>createPerson(name:) method is appended to PersonDao class which passes name argument to the save(S) method from PersonRepository. As PersonRepository implements CrudRepository, so we got save(S) method for free.</p><h4>GraphQL input</h4><p><a href="http://graphql.org/learn/schema/#input-types">Read about</a> GraphQL input types.</p><p>Create person_input.graphqls file inside resources/graphql/input directory with following content:</p><pre><strong>input </strong>PersonInput {<br>    name: String!<br>}</pre><p>and the associated data class named PersonInput inside graphql/input package:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/14a1bf63ab5b2a03e0e73f3a108dc5d1/href">https://medium.com/media/14a1bf63ab5b2a03e0e73f3a108dc5d1/href</a></iframe><h4>GraphQL mutation</h4><p>Create mutation.graphqls inside resources/graphql directory with following content:</p><pre><strong>type </strong>Mutation {<br>    # Creates person<br>    personCreate(input: PersonInput!): Person!<br>}</pre><p>Same method must exist in GraphQLMutationResolver subclass, which is a Spring BootComponent. A good place to put it is in the graphql package:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/3a812f4adfb68ba2a24f0ae1c5dcdeea/href">https://medium.com/media/3a812f4adfb68ba2a24f0ae1c5dcdeea/href</a></iframe><p>PersonDao is our connection to a data layer. Passing a name should create a Person record in the database.</p><p>We’re done coding!</p><h4>Executing mutation</h4><p>Run mvn spring-boot:run and execute some mutations in the <em>GraphiQL</em> interface!</p><pre>mutation {<br>  personCreate(name: &quot;Joey Tribbiani&quot;) {<br>    id<br>    name<br>  }<br>}</pre><p>should return something like:</p><pre>{<br>  &quot;data&quot;: {<br>    &quot;personCreate&quot;: {<br>      &quot;name&quot;: &quot;Joey Tribbiani&quot;,<br>      &quot;id&quot;: &quot;b6ff8f21-923f-43a4-b84a-9e81705c8159&quot;<br>    }<br>  }<br>}</pre><p>Congratulations, you have successfully connected GraphQL mutations to the MongoDB!</p><p><a href="https://github.com/aronbalog/SpringGraphQLExample">aronbalog/SpringGraphQLExample</a></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=f825033bbfd3" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Spring Boot + Kotlin + GraphQL + MongoDB — Part 1]]></title>
            <link>https://medium.com/@aronbalog/spring-boot-kotlin-graphql-mongo-e73f25df6ab9?source=rss-589f1681fc5f------2</link>
            <guid isPermaLink="false">https://medium.com/p/e73f25df6ab9</guid>
            <category><![CDATA[query]]></category>
            <category><![CDATA[mongodb]]></category>
            <category><![CDATA[kotlin]]></category>
            <category><![CDATA[spring-boot]]></category>
            <category><![CDATA[graphql]]></category>
            <dc:creator><![CDATA[Aron Balog]]></dc:creator>
            <pubDate>Sun, 06 May 2018 03:50:25 GMT</pubDate>
            <atom:updated>2018-05-13T23:49:06.838Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/712/1*9h6OAz32ITD5rXu0zakyZg.jpeg" /></figure><h4>Hack the Stack</h4><p><a href="https://medium.com/@aronbalog/spring-boot-kotlin-graphql-mongodb-part-2-mutations-f825033bbfd3">Spring Boot + Kotlin + GraphQL + MongoDB — Part 2: Mutations</a></p><h3>Spring Boot</h3><p><strong>Spring Boot</strong> makes it easy to create stand-alone, production-grade Spring based Applications that you can “just run”. Most <strong>Spring Boot</strong> applications need very little Spring configuration.</p><h4>Features</h4><ul><li>Create stand-alone Spring applications</li><li>Embed <a href="http://tomcat.apache.org">Tomcat</a>, <a href="https://www.eclipse.org/jetty/">Jetty</a> or <a href="https://github.com/undertow-io/undertow">Undertow</a> directly (no need to deploy <a href="https://en.wikipedia.org/wiki/WAR_(file_format)">WAR</a> files)</li><li>Provide opinionated ‘starter’ <a href="https://www.google.com/url?sa=t&amp;rct=j&amp;q=&amp;esrc=s&amp;source=web&amp;cd=2&amp;cad=rja&amp;uact=8&amp;ved=0ahUKEwjU6Z20v-_aAhVC6KQKHWZQD_AQFgg0MAE&amp;url=https%3A%2F%2Fmaven.apache.org%2Fguides%2Fintroduction%2Fintroduction-to-the-pom.html&amp;usg=AOvVaw0UvDqSmsV_z7k_ESHC_Eik">POM</a>s to simplify your Maven configuration</li><li>Automatically configure Spring whenever possible</li><li>Provide production-ready features such as metrics, health checks and externalized configuration</li><li>Absolutely <strong>no code generation</strong> and <strong>no requirement for XML</strong> configuration</li></ul><h3>Kotlin</h3><p>Kotlin is statically typed programming language for modern multi-platform applications. It drastically reduce the amount of boilerplate code.</p><p>Example of <a href="https://en.wikipedia.org/wiki/Plain_old_Java_object">POJO</a> with getters, setters, equals(), hashCode(), toString() and copy() in a single line:</p><pre><strong>data</strong> <strong>class</strong> Customer(<strong>val</strong> name: String, <strong>val</strong> email: String, <strong>val</strong> company: String)</pre><p>Example of singleton:</p><pre><strong>object</strong> ThisIsASingleton {<br>    <strong>val</strong> companyName: String = &quot;JetBrains&quot;<br>}</pre><h3>GraphQL</h3><p>GraphQL is a query language for your API, and a server-side runtime for executing queries by using a type system you define for your data. GraphQL isn’t tied to any specific database or storage engine and is instead backed by your existing code and data.</p><p>A GraphQL service is created by defining types and fields on those types, then providing functions for each field on each type. For example, a GraphQL service that tells us who the logged in user is (me) as well as that user&#39;s name might look something like this:</p><pre><strong>type</strong> Query {<br>  me: <strong>Person</strong><br>}</pre><pre><strong>type</strong> Person {<br>  id: <strong>ID</strong><br>  name: <strong>String</strong><br>}</pre><p>Once a GraphQL service is running (typically at a URL on a web service), it can be sent GraphQL queries to validate and execute. A received query is first checked to ensure it only refers to the types and fields defined, then runs the provided functions to produce a result.</p><p>For example the query:</p><pre>{<br>  me {<br>    name<br>  }<br>}</pre><p>Could produce the JSON result:</p><pre>{<br>  &quot;me&quot;: {<br>    &quot;name&quot;: &quot;Sherlock Holmes&quot;<br>  }<br>}</pre><h3>MongoDB</h3><blockquote>MongoDB is a document database with the scalability and flexibility that you want with the querying and indexing that you need.</blockquote><ul><li><strong>MongoDB</strong> stores data in flexible, JSON-like documents, meaning fields can vary from document to document and data structure can be changed over time.</li><li>The document model maps to the objects in your application code, making data easy to work with.</li><li><strong>MongoDB</strong> is a distributed database at its core, so high availability, horizontal scaling, and geographic distribution are built in and easy to use.</li></ul><h3>Let’s get started!</h3><p>You can find this project at <a href="https://github.com/aronbalog/SpringGraphQLExample">GitHub</a>.</p><p>Go to <a href="http://start.spring.io">start.spring.io</a> and create starter package with following dependencies:</p><ul><li>Web</li><li>MongoDB</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*mE3d9q97Urvd1Nn4toH3cw.png" /></figure><h4>application.properties configuration:</h4><pre>spring.data.mongodb.database=example<br>spring.data.mongodb.port=27017</pre><p><strong>MongoDB</strong> <a href="https://docs.mongodb.com/manual/installation/">must be installed</a> prior running the mvn clean install command.</p><p>If everything is ok, it should build successfully:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*Ct_Pt9I_gRaGEO5iHsFrig.png" /></figure><p>Run mvn spring-boot:run and try to open http://localhost:8080 in web browser.</p><p>Response should look like this:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*gQZGoIQcvNDqseWMvgbUCw.png" /></figure><h3>Integrating GraphQL</h3><p>Add following dependencies to pom.xml file:</p><pre>&lt;dependency&gt;<br>   &lt;groupId&gt;com.graphql-java&lt;/groupId&gt;<br>   &lt;artifactId&gt;graphql-java&lt;/artifactId&gt;<br>   &lt;version&gt;8.0&lt;/version&gt;<br>&lt;/dependency&gt;<br>&lt;dependency&gt;<br>   &lt;groupId&gt;com.graphql-java&lt;/groupId&gt;<br>   &lt;artifactId&gt;graphiql-spring-boot-starter&lt;/artifactId&gt;<br>   &lt;version&gt;4.0.0&lt;/version&gt;<br>&lt;/dependency&gt;<br>&lt;dependency&gt;<br>   &lt;groupId&gt;com.graphql-java&lt;/groupId&gt;<br>   &lt;artifactId&gt;graphql-java-tools&lt;/artifactId&gt;<br>   &lt;version&gt;5.0.0&lt;/version&gt;<br>&lt;/dependency&gt;<br>&lt;dependency&gt;<br>   &lt;groupId&gt;com.graphql-java&lt;/groupId&gt;<br>   &lt;artifactId&gt;graphql-spring-boot-starter&lt;/artifactId&gt;<br>   &lt;version&gt;4.0.0&lt;/version&gt;<br>&lt;/dependency&gt;<br>&lt;dependency&gt;<br>   &lt;groupId&gt;com.graphql-java&lt;/groupId&gt;<br>   &lt;artifactId&gt;graphql-java-servlet&lt;/artifactId&gt;<br>   &lt;version&gt;5.0.0&lt;/version&gt;<br>&lt;/dependency&gt;<br>&lt;dependency&gt;<br>   &lt;groupId&gt;org.hibernate&lt;/groupId&gt;<br>   &lt;artifactId&gt;hibernate-core&lt;/artifactId&gt;<br>   &lt;version&gt;5.2.9.Final&lt;/version&gt;<br>&lt;/dependency&gt;</pre><p>and run mvn clean install. This should install all needed dependencies into the project.</p><p>Create new package with name graphql and a new package query under it.</p><p>Under resources folder, create a graphql directory. In this folder we are going to create schema files.</p><p>Package &amp; folder structure:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/630/1*wR1Q6IqxfMUc8Axykc6ong.png" /><figcaption>Package &amp; folder structure</figcaption></figure><h3>Our first GraphQL query</h3><p>Create new Kotlin class Query under graphql package:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/2d21b4478ed117e6d25f465531387b27/href">https://medium.com/media/2d21b4478ed117e6d25f465531387b27/href</a></iframe><p>and create new file named query.graphqls in resources/graphql directory:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/f4ddb7814b294a7e4061681589202631/href">https://medium.com/media/f4ddb7814b294a7e4061681589202631/href</a></iframe><p>Query type is now paired with Query class. Pay attention to @Component annotation. It indicates that an annotated class is a “component”. In Spring, such classes are considered as candidates for auto-detection when using annotation-based configuration and classpath scanning, so no additional configuration is required.</p><p>Now, run project by executing following command in terminal:</p><pre><strong>mvn</strong> spring-boot:run</pre><h3>Making requests</h3><h4>GraphiQL</h4><blockquote>/ˈɡrafək(ə)l/</blockquote><blockquote>A graphical interactive in-browser GraphQL IDE.</blockquote><p>Open GraphQL web interface — GraphiQL (<a href="http://localhost:8080/graphiql">http://localhost:8080/graphiql</a>) in your browser. It should look like this:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*lguPxEBsU07Do6PK3FBmyA.png" /><figcaption>GraphiQL interface</figcaption></figure><p>In the editor, type a query:</p><pre><strong>query</strong> {<br>  version<br>}</pre><p>and press play button to execute it. Server should respond with:</p><pre>{<br>  &quot;data&quot;: {<br>    &quot;version&quot;: &quot;1.0.0&quot;<br>  }<br>}</pre><p>Congratulations! You have GraphQL service up and running.</p><p>Now, we are going to create <strong>MongoDB</strong> database, and make some read &amp; write queries to it via <strong>GraphQL</strong>.</p><h3>Creating an Entity</h3><p><strong>Entity</strong> in this example is Person.</p><p>Create new package data and data class Person inside it:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/9a341986c11c42a86c73fbffc3f0fb3c/href">https://medium.com/media/9a341986c11c42a86c73fbffc3f0fb3c/href</a></iframe><p>@Document annotation ensures a MongoDB document from person collection is mapped to this class.</p><h3>Creating a Repository</h3><p>Create new package repository and PersonRepository interface inside it:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/a668f2cfb066d85021d4f7c0ecdaa108/href">https://medium.com/media/a668f2cfb066d85021d4f7c0ecdaa108/href</a></iframe><p>We want our repository to be able to:</p><ul><li>find person by its id</li><li>find all the persons containing characters from a given string (name)</li></ul><p>MongoRepository extends CrudRepository so we can simply build queries by naming the repository functions properly.</p><p>findById is already provided by CrudRepository so there is no need to declare this function.</p><h3>Creating a DAO</h3><p>Create new package dao and PersonDao class inside it:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/b05456af12782fdba3dceea3dc83a997/href">https://medium.com/media/b05456af12782fdba3dceea3dc83a997/href</a></iframe><p>PersonDao injects PersonRepository interface so it can perform database queries.</p><h3><strong>Connecting GraphQL with MongoDB</strong></h3><p>Create new directory type inside resources/graphql directory and create person.graphqls (GraphQL schema) file inside it:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/a5010b911f509b2cf5d967f3b6d90233/href">https://medium.com/media/a5010b911f509b2cf5d967f3b6d90233/href</a></iframe><p>Extend query.graphqls like this:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/e9e36a804697321aaa27e37c5fe76998/href">https://medium.com/media/e9e36a804697321aaa27e37c5fe76998/href</a></iframe><p>Create new package query inside graphql package and create PersonQueryResolver class inside it:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/916fde4ed63e6831f86f805b38e06f0a/href">https://medium.com/media/916fde4ed63e6831f86f805b38e06f0a/href</a></iframe><p>PersonQueryResolver injects PersonDao, which is our connection to a data layer.</p><p>Note that query names and arguments inside query.graphqls match the method names and arguments inside PersonQueryResolver class. When the application boots, it collects all the GraphQLQueryResolver subclasses and match them with appropriate queries.</p><p>At this point, <strong>GraphQL</strong> queries should be able to read data from <strong>MongoDB</strong> database.</p><p>We need to write some data to the database to be able to read it. Execute following commands in terminal:</p><pre>$ mongo<br>$ use example<br>$ db.person.insertOne( { _id: &quot;1&quot;, name: &quot;Sherlock Holmes&quot; } );</pre><p>Switch back web browser, go to GraphiQL interface, and run some queries!</p><pre>query {<br>  personsByName(name: &quot;Sherlock&quot;) {<br>    id<br>    name<br>  }<br>}</pre><p>should return:</p><pre>{<br>  &quot;data&quot;: {<br>    &quot;personsByName&quot;: [<br>      {<br>        &quot;id&quot;: &quot;1&quot;,<br>        &quot;name&quot;: &quot;Sherlock Holmes&quot;<br>      }<br>    ]<br>  }<br>}</pre><h3>Architecture graph</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/724/1*vB_Qq4i8v_3wJxd4BYHM9Q.png" /></figure><ul><li><a href="https://medium.com/@aronbalog/spring-boot-kotlin-graphql-mongodb-part-2-mutations-f825033bbfd3">Spring Boot + Kotlin + GraphQL + MongoDB — Part 2: Mutations</a></li><li><a href="https://github.com/aronbalog/SpringGraphQLExample">aronbalog/SpringGraphQLExample</a></li></ul><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=e73f25df6ab9" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[#3 iOS — Reinventing view controller navigation]]></title>
            <link>https://medium.com/@aronbalog/3-ios-reinventing-view-controller-navigation-c5bf972bf4b4?source=rss-589f1681fc5f------2</link>
            <guid isPermaLink="false">https://medium.com/p/c5bf972bf4b4</guid>
            <category><![CDATA[deep-linking]]></category>
            <category><![CDATA[ios]]></category>
            <category><![CDATA[universal-links]]></category>
            <category><![CDATA[swift]]></category>
            <category><![CDATA[routing]]></category>
            <dc:creator><![CDATA[Aron Balog]]></dc:creator>
            <pubDate>Sat, 05 May 2018 14:54:22 GMT</pubDate>
            <atom:updated>2018-05-05T14:57:27.852Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/712/1*-cIOn6UOc-LEaTVkybG00w.jpeg" /></figure><h4>Handle Universal Links Like a Boss.</h4><p>URLs are everywhere. On our screens, billboards, in the systems, in our minds. Literally everywhere. They contain valuable information needed to perform certain operations.</p><p>In iOS, Apple added the support for universal linking. This is a very cool feature but so far it required a lot of custom code being written. Some remarks to be shared:</p><ul><li>URLs are changeable which can raise issues with URL matching inside an app (requires an app update)</li><li>URLs can contain some pieces of information in their paths</li><li>URLs can be shortened and search engine friendly</li></ul><p>Your Swift code has a high probability to be bloated if the website that has to be linked with an app has complex URL formats that are weirdly generated.</p><p>We are gonna make an <a href="https://github.com/aronbalog/CoreNavigation/tree/master/Examples/DeepLinkingExample">DeepLinkingExample</a> app, which is an extended <a href="https://github.com/aronbalog/CoreNavigation/blob/master/Examples/PassingDataExample">PassingDataExample</a> app. It will demonstrate how to deal with these issues using <a href="https://github.com/aronbalog/CoreNavigation">CoreNavigation</a> framework. Let’s get started!</p><h4>1. Download and prepare <a href="https://github.com/aronbalog/CoreNavigation/tree/master/Examples/DeepLinkingExample">DeepLinkingExample</a> project</h4><h4>2. Create <a href="https://www.mockable.io">mockable</a> account</h4><p><a href="https://www.mockable.io/">mockable</a> is a simple configurable service to mock out RESTful API or SOAP web-services.</p><h4>3. Create <a href="https://developer.apple.com/library/content/documentation/General/Conceptual/AppSearch/UniversalLinks.html">apple-app-site-association</a> on <a href="https://www.mockable.io/">mockable</a></h4><pre>{<br>    &quot;applinks&quot;: {<br>        &quot;apps&quot;: [],<br>        &quot;details&quot;: [<br>            {<br>                &quot;appID&quot;: &quot;YOUR_TEAM_ID.org.corenavigation.DeepLinkingExample&quot;,<br>                &quot;paths&quot;: [&quot;*&quot;]<br>            }<br>        ]<br>    }<br>}</pre><p>Replace YOUR_TEAM_ID with your Apple Dev team id.</p><h4>4. Configure target capabilities</h4><p>Add <a href="https://www.mockable.io/">mockable</a> domain to target’s Associated Domains capabilities section in the following format:</p><p>applinks:MOCKABLE_DOMAIN</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*50766RAztuCKWDRUC4vaAQ.png" /></figure><p><em>Note: Domain defined in this screenshot won’t work because it does not return correct </em><em>apple-app-site-association file that matches your team id. You have to configure your own domain and ensure </em><em>apple-app-site-association file is available on the network.</em></p><h3>Use case</h3><ul><li>App has one view controller ColorViewController which can receive UIColor &amp; has color picker which triggers navigation to the same view controller type and passes chosen color as data to the new instance.</li><li>App can open a deep-link URL which contains hex string in its path.</li><li>App should map hex string to UIColor and pass it to ColorViewController.</li><li>App should open ColorViewController with appropriate color displayed in background using following URL formats:</li></ul><pre>https://DOMAIN/color/COLOR_HEX_STRING<br>http://DOMAIN/colour/COLOR_HEX_STRING<br>https://DOMAIN/color/COLOR_HEX_STRING<br>http://DOMAIN/colour/COLOR_HEX_STRING</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/320/1*VoORj5DvWhut257N5fxSvg.gif" /></figure><h3>Destination</h3><p>It’s nothing more than a simple view controller wrapper that provides some additional features and simplifies enrichment of truncated data (the one extracted from URL).</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/33778175a132fa257e9cdf170f6b3f79/href">https://medium.com/media/33778175a132fa257e9cdf170f6b3f79/href</a></iframe><p>Destination‘s resolve method is a place where parameters from URL are mapped to data destination view controller can receive. Such destinations need to be registered along with URL pattern strings. These are used in <a href="https://github.com/aronbalog/CoreNavigation">CoreNavigation</a>’s route matching mechanism.</p><h3>App delegate</h3><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/99dd99377f2de92c4be47a571336026b/href">https://medium.com/media/99dd99377f2de92c4be47a571336026b/href</a></iframe><p>Pay attention to registerRoutes() method in AppDelegate class. It says that any URL matching any of the strings in the passed array should resolve to Color destination type.</p><p>All the parameter placeholders starting with : (colon) character will be replaced with extracted data from the URL and passed to Color‘s resolove(context:) method.</p><p><strong>Formats to define param placeholder:</strong></p><pre>:PARAMETER_NAME</pre><p>or</p><pre>:PARAMETER_NAME(REGEX_MATCH_PATTERN)</pre><p><strong>Accessing extracted parameters:</strong></p><pre>let parameter = context.parameters?[&quot;PARAMETER_NAME&quot;] as? String</pre><p>In this example, route patterns are hardcoded. However, they can be generated on the server side and provided to an app so it will always stay in sync with the website and its URLs.</p><h3>NSUserActivity navigation extension</h3><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/566e145aa0652f6cf45063a798306d83/href">https://medium.com/media/566e145aa0652f6cf45063a798306d83/href</a></iframe><p><a href="https://github.com/aronbalog/CoreNavigation">CoreNavigation</a> supports navigation to URL type, so just navigate to it.</p><p>Happy coding!</p><p><a href="https://github.com/aronbalog/CoreNavigation">aronbalog/CoreNavigation</a></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=c5bf972bf4b4" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[#2 iOS — Reinventing view controller navigation]]></title>
            <link>https://medium.com/undabot/2-ios-reinventing-view-controller-navigation-6d3499d4df73?source=rss-589f1681fc5f------2</link>
            <guid isPermaLink="false">https://medium.com/p/6d3499d4df73</guid>
            <category><![CDATA[framework]]></category>
            <category><![CDATA[swift]]></category>
            <category><![CDATA[ios]]></category>
            <category><![CDATA[deep-linking]]></category>
            <category><![CDATA[navigation]]></category>
            <dc:creator><![CDATA[Aron Balog]]></dc:creator>
            <pubDate>Thu, 03 May 2018 23:45:33 GMT</pubDate>
            <atom:updated>2020-01-25T22:50:05.450Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/712/1*LFKyUcmEmWQjDBrSfEw9Yg.jpeg" /></figure><h4>Passing data between view controllers.</h4><p><em>Previous posts:</em></p><ul><li><a href="https://medium.com/@aronbalog/0-ios-reinventing-view-controller-navigation-c371175fbb7a"><em>#0 present &amp; push… For how long?</em></a></li><li><a href="https://medium.com/@aronbalog/1-ios-reinventing-view-controller-navigation-c2745b60bb6c"><em>#1 Forget about segues.</em></a></li></ul><blockquote><a href="https://github.com/aronbalog/CoreNavigation"><em>CoreNavigation</em></a><em> extends UIKit with additional features and tools helping you handle navigation use cases in few lines of code.</em></blockquote><p>In this post, I’ll walk you through <a href="https://github.com/aronbalog/CoreNavigation">CoreNavigation</a>’s Destination type and data passing capabilities. Source code can be found on <a href="https://github.com/aronbalog/CoreNavigation/tree/master/Examples/PassingDataExample">GitHub</a>.</p><p>We are gonna make a <a href="https://github.com/aronbalog/CoreNavigation/tree/master/Examples/PassingDataExample">simple app</a> with just one view controller containing a color picker.</p><p>ColorViewController can:</p><ul><li>navigate to the new view controller of same type and pass UIColor instance</li><li>receive UIColor which will be assigned to view’s backgroundColor</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/320/1*woeX5QsKXfyQ6EVS126GLg.gif" /></figure><h4>View controller</h4><p><a href="https://github.com/joncardasis/ChromaColorPicker">ChromaColorPicker</a> is used for the demo purpose.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/69bd9581ea0096963889dc624b2ddfb6/href">https://medium.com/media/69bd9581ea0096963889dc624b2ddfb6/href</a></iframe><p>Make view controller able to receive data by conforming DataReceivable protocol:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/1df8ac24364feef703eba339ae84a0bd/href">https://medium.com/media/1df8ac24364feef703eba339ae84a0bd/href</a></iframe><p>DataReceivable type has it’s associated type DataType. This means a Destination type can know about its view controller’s data type which opens a possibility to pass a concrete data from an outside world.</p><h4>Destination (view controller wrapper)</h4><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/e7b6f863240ac192e84fc5f6bab7087f/href">https://medium.com/media/e7b6f863240ac192e84fc5f6bab7087f/href</a></iframe><p>Destination protocol has it’s associated type ViewControllerType which is theUIViewController type. This means destination type can know about its view controller type. In this particular case, aColor destination is paired with ColorViewController.</p><h4>Navigation</h4><p>Detect color picker changes and navigate:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/3a7adb9a20684179de27a3f3f340154d/href">https://medium.com/media/3a7adb9a20684179de27a3f3f340154d/href</a></iframe><p>Using Destination type is optional and practically has no use in this use case but using it will give us an advantage in our next task where we’re going to extend current app with deep linking capabilities.</p><p>Happy coding!</p><p><em>Next post:</em></p><p><a href="https://medium.com/@aronbalog/3-ios-reinventing-view-controller-navigation-c5bf972bf4b4">#3 iOS — Reinventing view controller navigation</a></p><p><a href="https://github.com/aronbalog/CoreNavigation">aronbalog/CoreNavigation</a></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=6d3499d4df73" width="1" height="1" alt=""><hr><p><a href="https://medium.com/undabot/2-ios-reinventing-view-controller-navigation-6d3499d4df73">#2 iOS — Reinventing view controller navigation</a> was originally published in <a href="https://medium.com/undabot">Undabot</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[#1 iOS — Reinventing view controller navigation]]></title>
            <link>https://medium.com/undabot/1-ios-reinventing-view-controller-navigation-c2745b60bb6c?source=rss-589f1681fc5f------2</link>
            <guid isPermaLink="false">https://medium.com/p/c2745b60bb6c</guid>
            <category><![CDATA[ios]]></category>
            <category><![CDATA[navigation]]></category>
            <category><![CDATA[uikit]]></category>
            <category><![CDATA[storyboard]]></category>
            <category><![CDATA[swift]]></category>
            <dc:creator><![CDATA[Aron Balog]]></dc:creator>
            <pubDate>Thu, 03 May 2018 00:13:08 GMT</pubDate>
            <atom:updated>2018-05-04T23:30:16.832Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/712/1*jc2M0dNBUZH3Y8pqU_ouZg.jpeg" /></figure><h4>Forget about segues.</h4><p><em>Previous posts:</em></p><ul><li><a href="https://medium.com/@aronbalog/0-ios-reinventing-view-controller-navigation-c371175fbb7a"><em>#0 present &amp; push… For how long?</em></a></li></ul><p>Few things about segues:</p><ul><li>Apple’s out of the box navigation solution defined in storyboard file</li><li>hard to inspect if you have many view controllers on one storyboard</li><li>not good enough in more complex cases</li></ul><p>I just don’t like them. Naming is weird. API-s are weird. I also don’t like storyboards. When reviewing other developers’ code it is just impossible to see what is going on in the xml, not to mention the pain in resolving git conflicts. <a href="https://github.com/aronbalog/CoreNavigation">CoreNavigation</a> is 100% code based and does not yet support segues. However, you can still use view controller instances initiated from storyboards.</p><blockquote>It’s time to boost some coding skills.</blockquote><h3>View controller navigation</h3><p>Many modern app architectures wrap navigation logic but developers for some reason like to couple app’s business logic with UIKit navigation APIs. Things get messy when a client makes the request for a new feature, e.g. deep linking or state restoration. More edge cases arise when users can have multiple access levels in the app and client wants some <a href="https://en.wikipedia.org/wiki/Access_control_list">ACL</a> mechanism implemented to warn the user, or to intercept, redirect or even disable navigation. I know this sounds like custom business logic but it can be abstracted. Abstracting common use cases requires some deeper knowledge of UIKit navigation behavior and <a href="https://github.com/aronbalog/CoreNavigation">CoreNavigation</a> wraps these things for you.</p><h4>Passing data</h4><p>The most common thing we do while navigating between screens is passing data to destination view controller. Developers tend to create custom initialisers with destination data as method arguments. This is OK for small apps (2–3 screens). Bigger apps — big no-no.</p><p>Perceive this problem as building your own town.</p><p>Small app — small town. Each of its districts is your view controller. They are connected with roads — these could be your segues. People, bikes, and cars traveling between districts are the data passed to view controllers. If the town is small enough there will be no need for road signs, people will know the path so custom initialisers on view controllers are fine. This could all be defined in a single storyboard file.</p><blockquote>More view controllers — more need for greater control</blockquote><p>As your town gets bigger, you’ll need to provide some traffic lights to people. Roads become highways — no more segues. Traffic lights are your custom navigation logic, e.g. green light can be letting authenticated user navigating to wanted destination view controller (district).</p><p>Letting other apps open certain view controller via deep linking is just letting tourists visit your town. Your town would need an airport or road connection with an outside world. <a href="https://developer.apple.com/library/content/documentation/General/Conceptual/AppSearch/UniversalLinks.html">Read more</a> about universal linking.</p><p>Sometimes you may find yourself working in multiple-teams environment (huge apps like facebook, uber, etc.) where each team is building their own towns and you are not allowed to make any roads on your own. There is another team connecting the towns with each other and outside world.</p><p>For years I have to deal with the case where view controllers have several ways of navigating:</p><blockquote><strong>Truncated data</strong><br><em>Truncated data (e.g. userId string) is passed to destination view controller which is opened immediately. Destination view controller animates a spinner while fetching full data. Fetching completion triggers layout on view controller’s view.</em></blockquote><blockquote><strong>Full data</strong><em><br>Full data (e.g. </em><em>User object) is passed to destination view controller which is opened immediately. There is no loading animation as data is already present.</em></blockquote><blockquote><strong>Truncated data with preloading (least used)</strong><em><br>Truncated data (e.g. </em><em>userId string) is used to preload full data (e.g.</em><em>User object) which is passed to destination view controller. During the data fetching loading animation is displayed on origin view controller.</em></blockquote><p>Things get interesting when one view controller needs to be able to consume both data types, truncated and full. In the first case, origin view controller would have full data and in the other case would have just a reference to a full data. Questions arise:</p><ul><li>Should data be fetched before navigation or after?</li><li>How to design a data model for destination view controller?</li><li>Where to put the code for navigation?</li><li>Where to put the code for fetching data?</li><li>When using state restoration, should data be reloaded or restored from cache?</li><li>How to extract and map deep link data parameters?</li></ul><p>Whatever the answers are, the conclusion is we need some wrapper around view controllers. They cannot stand for themselves in a world of deep links, conditional navigation, state restoration, caching etc. They need support.</p><p>In the following post I am going to talk about new term — Destination.</p><p><em>Next posts:</em></p><ul><li><a href="https://medium.com/@aronbalog/2-ios-reinventing-view-controller-navigation-6d3499d4df73">#2 Passing data between view controllers</a></li></ul><p><a href="https://github.com/aronbalog/CoreNavigation">aronbalog/CoreNavigation</a></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=c2745b60bb6c" width="1" height="1" alt=""><hr><p><a href="https://medium.com/undabot/1-ios-reinventing-view-controller-navigation-c2745b60bb6c">#1 iOS — Reinventing view controller navigation</a> was originally published in <a href="https://medium.com/undabot">Undabot</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[#0 iOS — Reinventing view controller navigation]]></title>
            <link>https://medium.com/undabot/0-ios-reinventing-view-controller-navigation-c371175fbb7a?source=rss-589f1681fc5f------2</link>
            <guid isPermaLink="false">https://medium.com/p/c371175fbb7a</guid>
            <category><![CDATA[deep-linking]]></category>
            <category><![CDATA[navigation]]></category>
            <category><![CDATA[framework]]></category>
            <category><![CDATA[swift]]></category>
            <category><![CDATA[ios]]></category>
            <dc:creator><![CDATA[Aron Balog]]></dc:creator>
            <pubDate>Sun, 29 Apr 2018 23:10:53 GMT</pubDate>
            <atom:updated>2023-08-04T18:40:17.784Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/471/1*QNJHm9XNjBb8zDEMcP0ipA.png" /></figure><h4>present &amp; push… For how long?</h4><p>Through my career, I dealt with dozen different ways of navigating through screens (a.k.a. view controllers). Honestly, I never felt “safe” while using Apple’s navigation APIs.</p><pre>presentViewController:animated:completion:</pre><pre>pushViewController:animated:</pre><p>Wrapping these into some reusable components helped on some occasions but only temporarily. In environments where screen navigation is frequently used functionality, reusing such components can be very unthankful and frustrating as making a breaking change may result in an exhausting refactor across the whole stack.</p><p>I expected to see some moves from Apple on this topic since “the big refactor” (release of iOS 7 and iOS 8). I couldn’t be more wrong — so obviously, nothing happened. These minimalistic APIs for navigation are good enough for the simple use cases. But we live in a world where developers are spoiled and expect at least:</p><ul><li>APIs for data passing between screens (view controllers)</li><li>APIs for conditional navigation (e.g. user is not allowed to open certain parts of the app)</li><li>easier handling of state restoration</li><li>URL navigation (deep linking)</li><li>caching</li><li>navigation history handling (like browsers do)</li></ul><p>I stepped into the maze of potential solutions and created a new one. Many of these mentioned things are wrapped and powered by simple APIs.</p><blockquote><a href="https://github.com/aronbalog/CoreNavigation">CoreNavigation</a> extends UIKit with additional features and tools helping you handle navigation use cases in few lines of code.</blockquote><p>If you have any questions, remarks or advice it would be my pleasure to discuss it with you.</p><p>In the following posts, I will try to explain how to useCoreNavigation.</p><p><em>Next posts:</em></p><ul><li><a href="https://medium.com/@aronbalog/1-ios-reinventing-view-controller-navigation-c2745b60bb6c"><em>#1 Forget about segues.</em></a></li><li><a href="https://medium.com/@aronbalog/2-ios-reinventing-view-controller-navigation-6d3499d4df73"><em>#2 Passing data between view controllers</em></a><em>.</em></li><li><a href="https://medium.com/@aronbalog/3-ios-reinventing-view-controller-navigation-c5bf972bf4b4"><em>#3 iOS — Reinventing view controller navigation</em></a></li></ul><p><a href="https://github.com/aronbalog/CoreNavigation">aronbalog/CoreNavigation</a></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=c371175fbb7a" width="1" height="1" alt=""><hr><p><a href="https://medium.com/undabot/0-ios-reinventing-view-controller-navigation-c371175fbb7a">#0 iOS — Reinventing view controller navigation</a> was originally published in <a href="https://medium.com/undabot">Undabot</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Series 7— Custom operators for better code readability.]]></title>
            <link>https://medium.com/undabot/series-6-custom-operators-for-better-readability-2155775fc91f?source=rss-589f1681fc5f------2</link>
            <guid isPermaLink="false">https://medium.com/p/2155775fc91f</guid>
            <category><![CDATA[ios]]></category>
            <category><![CDATA[swift]]></category>
            <category><![CDATA[code-readability]]></category>
            <category><![CDATA[code-syntax]]></category>
            <category><![CDATA[custom-operator]]></category>
            <dc:creator><![CDATA[Aron Balog]]></dc:creator>
            <pubDate>Fri, 30 Mar 2018 00:03:08 GMT</pubDate>
            <atom:updated>2018-03-30T00:06:25.630Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*NyoHqDC4JiOTwA0m2Lmitw.png" /></figure><p>Basic usage of custom operators is demonstrated in <a href="https://medium.com/@aronbalog/series-5-custom-operators-combined-with-localization-5378c282ea16">Series 6</a>. But can we use them for something else? In this post we are gonna do little experiment.</p><p>This is the pure example how to use custom operators to improve code readability.</p><p><strong>Our goal</strong></p><pre>let label = UILabel()<br>    &lt;- &quot;Gimme some sugar.&quot; // text<br>    &lt;- 2 // number of lines<br>    &lt;- UIColor.black // text color<br>    &lt;- NSTextAlignment.right // text alignment<br>    &lt;- UIFont.preferredFont(forTextStyle: .largeTitle) // font<br>    &lt;- CGRect(x: 0, y: 200, width: 200, height: 100) // frame</pre><p><strong>Expected result</strong></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/744/1*gZQUwDEOLIEJrkqoA-kh6g.png" /></figure><h3>How to achieve this?</h3><p><strong>1.</strong> Declare custom operator &lt;-</p><pre>infix operator &lt;-: AdditionPrecedence</pre><p><strong>2.</strong> Declare Configurable protocol:</p><pre>protocol Configurable: class {}</pre><p><strong>3.</strong> Configurable default implementation for UIView:</p><pre>extension Configurable where Self: UIView {<br>    static func &lt;-(left: Self, right: UIViewContentMode) -&gt; Self {<br>        left.contentMode = right<br>        <br>        return left<br>    }<br>    <br>    static func &lt;-(left: Self, right: CGRect) -&gt; Self {<br>        left.frame = right<br>        <br>        return left<br>    }<br>}</pre><p><strong>4.</strong> Configurable default implementation for UILabel:</p><pre>extension Configurable where Self: UILabel {<br>    static func &lt;-(left: Self, right: String) -&gt; Self {<br>        left.text = right<br>        <br>        return left<br>    }<br>    <br>    static func &lt;-(left: Self, right: UIColor) -&gt; Self {<br>        left.textColor = right<br>        <br>        return left<br>    }<br>    <br>    static func &lt;-(left: Self, right: NSTextAlignment) -&gt; Self {<br>        left.textAlignment = right<br>        <br>        return left<br>    }<br>    <br>    static func &lt;-(left: Self, right: UIFont) -&gt; Self {<br>        left.font = right<br>        <br>        return left<br>    }<br>    <br>    static func &lt;-(left: Self, right: Int) -&gt; Self {<br>        left.numberOfLines = right<br>        <br>        return left<br>    }<br>}</pre><p><strong>5.</strong> Conform UIView to Configurable:</p><pre>extension UIView: Configurable {}</pre><p><strong>That’s it!</strong></p><p><em>It kinda look like a new syntax, doesn’t it? :)</em></p><pre>let label = UILabel()<br>    &lt;- &quot;Gimme some sugar.&quot; // text<br>    &lt;- 2 // number of lines<br>    &lt;- UIColor.black // text color<br>    &lt;- NSTextAlignment.right // text alignment<br>    &lt;- UIFont.preferredFont(forTextStyle: .largeTitle) // font<br>    &lt;- CGRect(x: 0, y: 200, width: 200, height: 100) // frame</pre><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=2155775fc91f" width="1" height="1" alt=""><hr><p><a href="https://medium.com/undabot/series-6-custom-operators-for-better-readability-2155775fc91f">Series 7— Custom operators for better code readability.</a> was originally published in <a href="https://medium.com/undabot">Undabot</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Series 6— Custom operators combined with localization]]></title>
            <link>https://medium.com/undabot/series-5-custom-operators-combined-with-localization-5378c282ea16?source=rss-589f1681fc5f------2</link>
            <guid isPermaLink="false">https://medium.com/p/5378c282ea16</guid>
            <category><![CDATA[ios-app-development]]></category>
            <category><![CDATA[custom-operator]]></category>
            <category><![CDATA[swift]]></category>
            <category><![CDATA[localization]]></category>
            <category><![CDATA[swift-extensions]]></category>
            <dc:creator><![CDATA[Aron Balog]]></dc:creator>
            <pubDate>Thu, 29 Mar 2018 22:01:13 GMT</pubDate>
            <atom:updated>2018-03-29T23:44:37.839Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*MvHfSa2Y3nbxJDVPZeeRmw.jpeg" /></figure><p>In this episode we are gonna use custom operator for setting localizable strings on UI components.</p><p><em>Note: This is just a simple example, not a real world solution.</em></p><p><strong>This episode’s goal:</strong></p><pre>let label = UILabel() &lt;- Localization.welcomeMessage<br>print(label.text?) // prints &quot;Gimme some sugar.&quot;</pre><p>Let’s declare Localizable protocol responsible for providing localized string:</p><pre>protocol Localizable {<br>    var localizedString: String? { get }<br>}</pre><p>Our localization is enumtype. Each of its case represents a key which will be used in NSLocalizedString macro.</p><pre>enum Localization: String, Localizable {<br>    case welcomeMessage = &quot;Gimme some sugar.&quot;<br>    case warningMessage = &quot;Too much sugar!&quot;<br>}</pre><p>Localization enum is RawRepresentable with String as its associated type so this knowledge can be used in our default implementation of Localizable protocol.</p><pre>extension Localizable<br>    where Self: RawRepresentable, Self.RawValue == String<br>{<br>    var localizedString: String? {<br>        return NSLocalizedString(rawValue, comment: &quot;&quot;)<br>    }<br>}</pre><h3>Custom operator</h3><p>We’re gonna use infix operator. Custom operators are not covered in this post. <a href="https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/AdvancedOperators.html#//apple_ref/doc/uid/TP40014097-CH27-ID46">Read more about custom operators.</a></p><pre>infix operator &lt;-: AdditionPrecedence</pre><p>Protocol which will provide abstraction for any object which has text: String? property. We’ll call it TextAware:</p><pre>protocol TextAware: class {<br>    var text: String? { get set }<br>}</pre><p>Apply &lt;- operator to TextAware protocol:</p><pre>extension TextAware {<br>    static func &lt;-(left: Self, right: Localization) -&gt; Self {<br>        left.text = right.localizedString<br> <br>        return left<br>    }<br>}</pre><p>Now we can extend UI components with TextAware:</p><pre>extension UILabel: TextAware {}<br>extension UITextField: TextAware {}</pre><p>And finally we can use:</p><pre>let label = UILabel() &lt;- Localization.welcomeMessage<br>print(label.text?) // prints &quot;Gimme some sugar.&quot;</pre><pre>let textField = UITextField() &lt;- Localization.warningMessage<br>print(textField.text?) // prints &quot;Too much sugar!&quot;</pre><p>Pretty easy, isn’t it?</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=5378c282ea16" width="1" height="1" alt=""><hr><p><a href="https://medium.com/undabot/series-5-custom-operators-combined-with-localization-5378c282ea16">Series 6— Custom operators combined with localization</a> was originally published in <a href="https://medium.com/undabot">Undabot</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Gimme some sugar.]]></title>
            <link>https://medium.com/undabot/gimme-some-sugar-7dcd7983fef?source=rss-589f1681fc5f------2</link>
            <guid isPermaLink="false">https://medium.com/p/7dcd7983fef</guid>
            <category><![CDATA[uibutton]]></category>
            <category><![CDATA[stored-property]]></category>
            <category><![CDATA[uicontrol]]></category>
            <category><![CDATA[ios]]></category>
            <category><![CDATA[swift]]></category>
            <dc:creator><![CDATA[Aron Balog]]></dc:creator>
            <pubDate>Wed, 28 Mar 2018 21:24:43 GMT</pubDate>
            <atom:updated>2018-03-31T02:10:33.527Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*MvHfSa2Y3nbxJDVPZeeRmw.jpeg" /></figure><h3>Gimme some sugar. Series 5 — Stored properties in swift extensions + sweet UIControl action handling</h3><p>In <a href="https://medium.com/@aronbalog/gimme-some-sugar-series-3-selector-ef3fcd2771f">one of the previous posts</a> I demonstrated how to use Selector extension to prettify your code. In this post we are gonna make it even sweeter.</p><p>Wishful thinking (our goal):</p><pre>let button = UIButton()</pre><pre>button.on(.touchUpInside) {<br>    // we want to handle button tap here<br>}</pre><p>UIButton inherits from UIControl which owns addTarget(_:action:for:). <a href="https://developer.apple.com/documentation/uikit/uicontrol/1618259-addtarget">Read more about it.</a></p><p>Somehow closure has to be invoked inside the selector passed in addTarget(_:action:for:) function.</p><h3>Gimme some sugar and make it sweeter.</h3><p>First we need our proxy target:</p><pre>// MARK: Proxy target</pre><pre>class Target: NSObject {<br>    let completion: (UIControl) -&gt; Void<br>    <br>    init(completion: @escaping (UIControl) -&gt; Void) {<br>        self.completion = completion<br>    }<br>    <br>    @objc func action(_ sender: UIControl) {<br>        completion(sender)<br>    }<br>}</pre><p>At the moment there is no place to store Target instances because Swift doesn’t support stored properties inside extensions. Well, this is not entirely true.</p><p>We’re gonna call Objective-C for help here. This simple class acts as low level memory storage:</p><pre>// MARK: Storage</pre><pre>final class ObjectAssociation&lt;T: AnyObject&gt; {<br>    private let policy: objc_AssociationPolicy<br>    <br>    public init(policy: objc_AssociationPolicy = .OBJC_ASSOCIATION_RETAIN) {<br>        self.policy = policy<br>    }<br>    <br>    public subscript(index: AnyObject) -&gt; T? {<br>        get {<br>            return objc_getAssociatedObject(index, Unmanaged.passUnretained(self).toOpaque()) as! T?<br>        }<br>        set {<br>            objc_setAssociatedObject(index, Unmanaged.passUnretained(self).toOpaque(), newValue, policy)<br>        }<br>    }<br>}</pre><p>Let’s make target storage on UIControl using ObjectAssociationclass:</p><pre>// MARK: Storage extension</pre><pre>extension UIControl {<br>    private static let association = ObjectAssociation&lt;NSMutableArray&gt;()</pre><pre>    var targets: [Target] {<br>        get {<br>            if UIControl.association[self] == nil {<br>                UIControl.association[self] = NSMutableArray()<br>            }<br>            return UIControl.association[self] as? [Target] ?? []<br>        }<br>        set {<br>            UIControl.association[self] = NSMutableArray(array: newValue)<br>        }<br>    }<br>}</pre><p>Now Target objects can be stored in UIControl instance. Cool hack, isn’t it?</p><p>And finally UIControl extension:</p><pre>// MARK: Syntax sugar extension</pre><pre>extension UIControl { <br>    @discardableResult func on&lt;T: UIControl&gt;(_ events: UIControlEvents, _ completion: @escaping (T) -&gt; Void) -&gt; Self {<br>        let target = Target {<br>            if let control = $0 as? T {<br>                completion(control)<br>            }<br>        }</pre><pre>        targets.append(target)<br>        <br>        addTarget(target, action: #selector(Target.action(_:)), for: events)<br>        <br>        return self<br>    }<br>}</pre><p>We are done.</p><p>Enjoy the sweetness!</p><pre>let button: UIButton = ...</pre><pre>button<br>    .on(.touchUpInside) { $0<br>        print(&quot;Touch up inside!&quot;)<br>    }<br>    .on(.touchUpOutside) { $0<br>        print(&quot;Touch up outside!&quot;)<br>    }</pre><p>P.S. Apple should have done it in the first place, right?</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=7dcd7983fef" width="1" height="1" alt=""><hr><p><a href="https://medium.com/undabot/gimme-some-sugar-7dcd7983fef">Gimme some sugar.</a> was originally published in <a href="https://medium.com/undabot">Undabot</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Gimme some sugar. Series 4 — Mutating in block]]></title>
            <link>https://medium.com/undabot/gimme-some-sugar-series-4-mutating-in-block-88a56e4bf800?source=rss-589f1681fc5f------2</link>
            <guid isPermaLink="false">https://medium.com/p/88a56e4bf800</guid>
            <category><![CDATA[sugar]]></category>
            <category><![CDATA[ios-app-development]]></category>
            <category><![CDATA[swift]]></category>
            <category><![CDATA[closure]]></category>
            <category><![CDATA[extension]]></category>
            <dc:creator><![CDATA[Aron Balog]]></dc:creator>
            <pubDate>Tue, 27 Mar 2018 22:40:14 GMT</pubDate>
            <atom:updated>2018-03-28T00:36:25.840Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*MvHfSa2Y3nbxJDVPZeeRmw.jpeg" /></figure><p>Take a look at this code example:</p><pre>let viewController = UIViewController()<br> <br>viewController.navigationItem.leftBarButtonItem = UIBarButtonItem(...)<br> <br>viewController.navigationItem.rightBarButtonItem = UIBarButtonItem(...)</pre><pre>viewController.title = &quot;Title&quot;</pre><pre>viewController.view.backgroundColor = UIColor.white</pre><pre>viewController.presentData(...)<br>...</pre><p>This have tendencies to get messy and hard to read.</p><p>Sure, some logic can be moved/wrapped to new functions, you can delegate object configuration to another objects, you can even indent some of the stuff in code, but if you use some lint tool, you’re in problems.</p><h3>Gimme some sugar and make it sweeter.</h3><pre>protocol Configurable {}</pre><pre>extension Configurable {<br>    func configure(_ block: (inout Self) -&gt; Void) -&gt; Self {<br>        var instance = self<br>        block(&amp;instance)<br> <br>        return instance<br>    }<br>}</pre><p>In this very moment, this code does nothing.</p><p>But if NSObject is extended (which is the base class in Foundation) all its subclasses become configurable:</p><pre>extension NSObject: Configurable {}</pre><p>Sweetness is here.</p><pre>let viewController = UIViewController().configure {<br>    $0.navigationItem.leftBarButtonItem = ...<br>    <br>    ...<br>}</pre><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=88a56e4bf800" width="1" height="1" alt=""><hr><p><a href="https://medium.com/undabot/gimme-some-sugar-series-4-mutating-in-block-88a56e4bf800">Gimme some sugar. Series 4 — Mutating in block</a> was originally published in <a href="https://medium.com/undabot">Undabot</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
    </channel>
</rss>