<?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 Pablo Villar on Medium]]></title>
        <description><![CDATA[Stories by Pablo Villar on Medium]]></description>
        <link>https://medium.com/@volbap?source=rss-2261535f21e------2</link>
        <image>
            <url>https://cdn-images-1.medium.com/fit/c/150/150/1*hq4QF8iTyGv7-OkeOuWzAQ.jpeg</url>
            <title>Stories by Pablo Villar on Medium</title>
            <link>https://medium.com/@volbap?source=rss-2261535f21e------2</link>
        </image>
        <generator>Medium</generator>
        <lastBuildDate>Mon, 13 Jul 2026 17:42:10 GMT</lastBuildDate>
        <atom:link href="https://medium.com/@volbap/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[Neat Data Sources in Swift]]></title>
            <link>https://medium.com/@volbap/neat-data-sources-in-swift-a788c439a227?source=rss-2261535f21e------2</link>
            <guid isPermaLink="false">https://medium.com/p/a788c439a227</guid>
            <category><![CDATA[iphone]]></category>
            <category><![CDATA[ios]]></category>
            <category><![CDATA[swift]]></category>
            <category><![CDATA[programming]]></category>
            <category><![CDATA[clean-code]]></category>
            <dc:creator><![CDATA[Pablo Villar]]></dc:creator>
            <pubDate>Tue, 18 Dec 2018 13:19:40 GMT</pubDate>
            <atom:updated>2018-12-18T17:07:25.248Z</atom:updated>
            <content:encoded><![CDATA[<p>How to write clean code when it comes to data sources and delegates.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*zwhaSwAvcnxOb1pMdpjHPA.png" /></figure><p>In this article, we will improve the code that goes within our data source methods to make it <strong>more meaningful, understandable, and maintainable</strong>, either for table views, collection views, or any other kind that we need.</p><blockquote>Disclaimer: This content is not about any different way of working with data sources, but rather about enhancing the internal implementations of the existent good-old and well-known data source methods.</blockquote><h3>Three Simple Rules</h3><p>All it takes to have cleaner data source implementations is to stick to these statements:</p><ul><li><strong>Avoid formulas for calculating indexes</strong></li><li><strong>Avoid magic numbers</strong></li><li><strong>Always consider all the possible scenarios</strong></li></ul><p>Applying these small concepts is really simple, and has enormous benefits in terms of code maintainability.</p><h3>Sections</h3><p>The first step, and the most important one, is to think carefully<strong> how the information can be split into sections</strong>.</p><p>In a data source, sections allows us to define logical chunks of data. Then, it makes sense to group items that are alike and visually together into sections.</p><p>As a practical example, we can take a look at the following table view:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/332/1*dm0pol2nyXGoAUdvu56w8g.gif" /></figure><p>Here, we can think of 3 groups of items:</p><ul><li>Album Info</li><li>Tracks</li><li>Actions</li></ul><h4>⛔️ A Bad Implementation</h4><p>First, I want to show you what the code looks like when we try to handle everything into just one section:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/b54a9f75f5db7bea745127c1ab890127/href">https://medium.com/media/b54a9f75f5db7bea745127c1ab890127/href</a></iframe><p>Obtaining the number of rows is complex. Getting the indexes for creating cells is complex. Delegating actions is complex. Everything is complex. And that&#39;s because <strong>calculating the indexes is complex</strong>.</p><p>The problem with this kind of approach is that while in our head it might make sense — <em>because we designed it</em> — one day other devs will have to modify this code, and that day, they are going to have a terrible time.</p><h4>✅ A Good Implementation</h4><p>The good news is that it&#39;s not that hard to refactor it. All we have to do is divide the data into <strong>meaningful groups</strong> that make sense, and use <strong>one section per group</strong>.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/71049648b76ab69a526761ff38301c03/href">https://medium.com/media/71049648b76ab69a526761ff38301c03/href</a></iframe><p>If we group our data like this, <strong>we will always obtain indexes easily</strong>:</p><ul><li>For sections that contain a <strong>single element<em> </em></strong><em>— like Album Info—</em><strong><em> </em></strong>the number of rows is always <strong>1</strong>, and the row index number is always <strong>0</strong>, for that first and only element</li><li>For sections that contain a <strong>collection of elements </strong><em>— like Tracks —</em><strong> </strong>, the number of rows is the <strong>count</strong> of elements of that collection, and each element is obtained by subscripting with the given <strong>indexPath.row</strong></li></ul><p>This way, we realize that calculating the indexes is simple, as it will never require any intricate or shady logic. This is the most important part of dealing with data sources. If you&#39;ve achieved a good distribution of your information into meaningful groups, your data source code is already robust enough. Congratulations!</p><h3>Enumerations</h3><p>A little issue in this code is that we are still using hardcoded numbers for identifying each section. Because of that, if we wanted to alter the sections, either by changing the order, or adding or removing some, we would have to modify all these numbers manually. That would be a cumbersome and error-prone task. Let&#39;s fix it.</p><p>If we make the following association:</p><blockquote>Section <strong>0</strong> → Album Info</blockquote><blockquote>Section 1 → Tracks</blockquote><blockquote>Section 2 → Actions</blockquote><p>Then, <strong>we can use an enum</strong> with integer raw values to represent and identify these sections unequivocally.</p><pre>private enum Section: Int, CaseIterable {<br>    case albumInfo, tracks, actions <br>}</pre><blockquote>It is a good practice to define this Section enum as a <strong>private</strong> type inside the class that we are working with.</blockquote><p>Now, each time we are given an <strong>indexPath.section</strong>, we can tell what Section it corresponds to, using the enum initializer:</p><pre>let section = Section(rawValue: indexPath.section)!</pre><p>This way, we no longer need to use magic numbers:</p><pre>if section == .albumInfo {<br> <br>   // do stuff</pre><pre>}</pre><h3>Switches</h3><p>Last, but not least, it&#39;s a good idea to have a discrete way to switch over that enum we&#39;ve just defined. This is, we will look for a way to <strong>consider all the possible scenarios</strong> regarding sections, never missing out any of them.</p><p>This is done very simply. We just have to use a <strong>switch statement </strong>— <em>and avoid if-else chains</em> — each time we have to identify a section in the code.</p><h4>✅ Good</h4><pre>switch section {<br>    case .albumInfo:<br>    case .tracks:<br>    case .actions:<br>}</pre><h4>⛔️ Bad</h4><pre>if section == .albumInfo {<br>    <br>} else if section == .tracks {<br>    <br>} // other cases can be missed out easily</pre><h4>⚠️ Avoid Default</h4><p>Since the number of elements that we have in the Section enum is <em>finite</em>, it is recommendable <strong>not to write the </strong><strong>default clause</strong>. That way, we force ourselves and our teammates to always update the switch statements to still consider all possible scenarios whenever the sections get altered. Although having the default clause may look innocuous, it could be harmful, as it is an easy way to forget extra cases that might be added later.</p><h4>️️⚠️ Define Limits</h4><p>One little issue is that the Section(rawValue:) initializer returns an <em>optional</em> value. And it makes sense, as we could think of <em>any</em> number from the integers&#39; domain, and it doesn&#39;t necessarily mean that there should be a valid section for that number.</p><p>Usually, our section numbers will go from<strong> </strong><strong>0</strong> to <strong>sections.count — 1</strong>. This is, if we try to initialize a Section with a rawValue that is ≥ the amount of sections, we won&#39;t get a valid case for that number, then nil will be returned. Nevertheless, <strong>this scenario is not expected to happen</strong>, as we should always constrain the number of sections of the table view to equal the total number of sections we have defined:</p><pre>func numberOfSections(in tableView: UITableView) -&gt; Int {<br>    return Section.allCases.count<br>}</pre><h3>Outcome</h3><p>Finally, this is the result of a clean data source implementation:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/3b8266667ba4885c61d3aa90b55ffdc4/href">https://medium.com/media/3b8266667ba4885c61d3aa90b55ffdc4/href</a></iframe><p>For further reference, you can check out this <a href="https://github.com/volbap/NeatDataSources">sample project</a>.</p><h3>Conclusions</h3><p>As always, <strong>we must strive for clean code</strong>. It makes ourselves better developers, and our code more pleasant to work with for everybody.</p><h4>Lessons Learned</h4><ul><li><strong>Sections</strong>: Divide your data into meaningful groups, one section per each</li><li><strong>Enumerations:</strong> Avoid magic numbers, use a<strong> </strong>Section enumeration</li><li><strong>Switches:</strong> Always prefer switch over if-else, and prefer<strong> </strong>not to use the default clause for finite enumerations</li></ul><p>I hope it helps, and I look forward to see your comments and experiences below.</p><p>Happy data sourcing!</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=a788c439a227" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Function Naming in Swift]]></title>
            <link>https://medium.com/appcoda-tutorials/function-naming-in-swift-dbf5d918c8e3?source=rss-2261535f21e------2</link>
            <guid isPermaLink="false">https://medium.com/p/dbf5d918c8e3</guid>
            <category><![CDATA[naming]]></category>
            <category><![CDATA[function]]></category>
            <category><![CDATA[api]]></category>
            <category><![CDATA[good-practices]]></category>
            <category><![CDATA[swift]]></category>
            <dc:creator><![CDATA[Pablo Villar]]></dc:creator>
            <pubDate>Fri, 30 Nov 2018 14:22:39 GMT</pubDate>
            <atom:updated>2018-12-07T02:42:56.021Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1000/1*tk24aGJAmmBMaOUanbvAgg.jpeg" /></figure><p>In this article, we will face a question that we should always ask ourselves when writing a function:</p><blockquote>How should I name this function?</blockquote><p>Although this question looks simple, getting it answered properly determines a crucial aspect in our professional lives as software developers. It makes our codebases cleaner and easier to use, as we will see.</p><h3>The Importance of Clear APIs</h3><p>If you were to use a function from a third party library, let&#39;s say for creating fancy labels, and you find these two options:</p><pre>// A<br>static func makeLabel(withTitle title: String) -&gt; FancyLabel</pre><pre>// B<br>static func configure(_ text: String) -&gt; FancyLabel</pre><p>Which one would you feel more comfortable with? A or B?</p><p>In case you are still hesitating, I&#39;ll give you a clue: common sense makes me think of option A, too.</p><p>Why option A, then…?</p><p>First, let&#39;s analyze why B isn&#39;t so good: Option B does not tell us what we are <em>configuring</em> exactly. Is it an existent instance? Does it create a new one? Does it return a new thing? It doesn’t tell us what&#39;s the meaning of the String it expects either. All we can tell beforehand is that it receives a String and returns a FancyLabel, but we don’t know exactly what it does. There is ambiguity and lack of information, and that&#39;s something we should avoid.</p><p>Option A, on the other hand, <strong>is totally explicit about these three things</strong>:</p><ul><li><strong>What it needs in order to work</strong><em> — a title</em></li><li><strong>What it does</strong>* — <em>it makes a label</em></li><li><strong>What&#39;s the outcome</strong> — <em>the created label</em></li></ul><blockquote>* We care about <strong>what</strong> it does (or is supposed to do), not about <strong>how</strong> it does that thing. We don’t care about the inner workings of the function. That’s how encapsulation works.</blockquote><p>The usage of this function becomes very natural by just having these three things clear, because in this way <strong>we can know what the function goes about, without misunderstandings.</strong> As simple as it.</p><p>We will see it clearer when we take a look at how these functions are called:</p><pre>let labelA = FancyLabel.makeLabel(withTitle: &quot;Hello world&quot;) // clear</pre><pre>let labelB = FancyLabel.configure(&quot;Hello world&quot;) // not so clear</pre><p>Now, what if we translated that example to a real life project with multiple developers working on it? What would you prefer to name your functions like? A or B? What would you prefer your teammates to name their functions like? A or B?</p><p>You can think of it like this: <strong>Each time you define a function, you are defining an interface that someone else will use in the future</strong>. Even if it’s private, and even if you think that nobody else will ever use it, it&#39;s always important that it is clear. Because any developer at any moment could need to deal with the internal code of any class in the project, even yourself. You never know!</p><p>In conclusion, if you put effort on naming your functions such that there is no ambiguity about what their inputs and outputs are, and what they do, a lot of effort can be saved when others have to call your function. They won’t have to go through its implementation to figure it all out. In this way, we save time and avoid misapprehensions that can lead to bugs. Defining clear interfaces in our code comes with the huge benefit of a <strong>codebase that is easier to deal with, to use, to shape, and to maintain</strong>.</p><p>Those extra seconds — <em>or minutes —</em> you need to think of the name of a function <strong>is time well invested</strong>.</p><h3>Function Signatures in Swift</h3><p>One of the most radical changes in Swift, if we compare it to Objective-C, and particularly since Swift 3.0, is the way <strong>function signatures</strong> work. Since that version, Swift is not only less verbose than its predecessor, but it&#39;s also clearer.</p><p>Let&#39;s take a look at an example:</p><pre>dateLabel.text = [formatter stringWith<strong>Date</strong>: [[Date alloc] init]]];</pre><pre>dateLabel.text = formatter.string(with: Date())</pre><p>We see two main differences here. First, the creation of the date instance is way more verbose in the first case, although that&#39;s only related to Objective-C&#39;s verbosity. Then, we can observe that the Objective-C version, besides lots of extra brackets, includes an extra word (Date) that the Swift one doesn&#39;t have.</p><p>This subtle — <em>yet effective</em> — change is actually possible thanks to the static nature of types in Swift. In the Swift version of the function, you are not able to pass in another object that is not a Date, because the compiler won&#39;t let you do that.</p><p>This change is simple, but it opened doors to a new world of function signatures. The code in general has become much more pleasant to read, as it&#39;s more concise and more similar to spoken language.</p><p>As mentioned, our next step is aiming to <strong><em>prune</em></strong> functions signatures, in such a way they become short enough to be concise, but still clear enough to avoid ambiguities.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/500/1*thF2JmyvC7subZC2E7z8Pg.gif" /><figcaption>Let&#39;s the prune begin…!</figcaption></figure><h3>Pruning</h3><p>Finally, let&#39;s analyze some examples of different functions signatures and see how we can make them look better by <strong><em>pruning</em></strong>, i.e. by removing some words.</p><pre>// Signature</pre><pre>func moveView(view: UIView, toPoint point: CGPoint) { ... }</pre><pre>// Usage</pre><pre>moveView(view: headerView, toPoint: .zero) // ⚠️ long and redundant</pre><p>It can become:</p><pre>// Signature</pre><pre>func move(_ view: UIView, to point: CGPoint) { ... }</pre><pre>// Usage</pre><pre>move(headerView, to: CGPoint.zero) // 👏 clear and concise</pre><p>Thanks to static typing, we don&#39;t need to specify that we are moving a <em>view</em> object in the function signature. Since the function requests for a UIView object, the only thing you can pass in is a that kind of object. Same with the <em>point</em>.</p><p>There are exceptions, though. You still need to specify what the parameter is about because its type might not be enough to describe it.</p><pre>// Signature</pre><pre>func makeButton(withTitle title: String) -&gt; UIButton { ... }</pre><pre>// Usage</pre><pre>let button = makeButton(withTitle: &quot;Function Naming&quot;) // 👍 good</pre><p>Let&#39;s see what happens when we try to prune here…</p><pre>// Signature</pre><pre>func makeButton(with title: String) -&gt; UIButton { ... }</pre><pre>// Usage</pre><pre>let button = makeButton(with: &quot;Function Naming&quot;) // 👎 not clear</pre><p>This happens because the type (String) does not exactly match the semantics of the content (a title). A String can represent lots of other things besides titles.</p><p>When in such a situation, there are two possible approaches that we can take. We either specify the semantics of the content by making the parameter name more explicit, as in the first part of the example above, or, we create a <em>new type </em>that describes the semantics more specifically, and use that new type as a parameter. In the example, we could have created a Title type for managing titles. The ideal scenario is going with the latter, as you will take even more advantages from the static typing system and your code will end up being more secure. I recommend you learn about techniques like <a href="http://kean.github.io/post/phantom-types">phantom types</a> and <a href="https://github.com/pointfreeco/swift-tagged">tagged types</a> for this purpose.</p><h3>Final Thoughts</h3><ul><li>Naming is hard. However, the time you spend on doing so is well invested. It reduces the possibilities of misunderstandings and prevents other developers — <em>or yourself </em>— from having to look at how all the code works trying to understand what it does. So, <strong>invest time in naming</strong>.</li><li><strong>Take advantage of static typing</strong>. Make your APIs clear and concise.</li><li>Share this knowledge with your teammates and encourage good practices.</li><li>Practise! Practise! Practise!</li></ul><p>And remember, <strong>a function should always be clear about 3 things</strong>:</p><ul><li><strong>What it needs</strong> — <em>input</em></li><li><strong>What it does</strong> —<em> describe the process without exposing the inner workings</em></li><li><strong>What it returns </strong>—<strong> </strong><em>output</em></li></ul><h3>See you next time!</h3><p>I hope this guide is useful for you, and I look forward to learning about your experiences and opinions in the comments below. Please, comment, suggest, and if you find it useful, share :)</p><p>Thank you for reading.</p><p><strong>Follow us on social media platforms:</strong><br>Facebook: <a href="http://facebook.com/AppCodamobile/">facebook.com/AppCodamobile/</a><br>Twitter: <a href="https://twitter.com/AppCodaMobile">twitter.com/AppCodaMobile</a><br>Instagram: <a href="http://instagram.com/AppCodadotcom">instagram.com/AppCodadotcom</a></p><h4>If you enjoyed this article, please click the 👏 button and share to help others find it! Feel free to leave a comment below.</h4><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=dbf5d918c8e3" width="1" height="1" alt=""><hr><p><a href="https://medium.com/appcoda-tutorials/function-naming-in-swift-dbf5d918c8e3">Function Naming in Swift</a> was originally published in <a href="https://medium.com/appcoda-tutorials">AppCoda Tutorials</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[The Power of Meeting People]]></title>
            <link>https://medium.com/tech-lead-talks/the-power-of-meeting-people-90aa5e8cbfd2?source=rss-2261535f21e------2</link>
            <guid isPermaLink="false">https://medium.com/p/90aa5e8cbfd2</guid>
            <category><![CDATA[people]]></category>
            <category><![CDATA[social]]></category>
            <category><![CDATA[conference]]></category>
            <category><![CDATA[meetup]]></category>
            <category><![CDATA[life]]></category>
            <dc:creator><![CDATA[Pablo Villar]]></dc:creator>
            <pubDate>Fri, 10 Aug 2018 21:01:37 GMT</pubDate>
            <atom:updated>2018-08-10T21:01:37.946Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*jOr7HkILRy27lVdGa4AQBA.jpeg" /><figcaption>Going to conferences is not just about the technical stuff…</figcaption></figure><p>I wrote this article almost two years ago. Unfortunately, the website where I published it shut down. By luck, though, I&#39;ve been recently told I was allowed to republish this content, which is what I&#39;m gladly doing right now.</p><p>Special thanks to <a href="https://medium.com/u/788b9596f013">Brujo Benavides</a> who pushed so hard on getting these contents back to the Internet. Soon, I will revive some other articles I wrote, which are worth the respawn too. Stay tuned.</p><p>This blogpost in particular contains lots of time references, so, when it says &quot;<em>2 months ago</em>&quot; it now means &quot;<em>21 months ago</em>&quot;, &quot;<em>recently</em>&quot; now means &quot;<em>a while ago</em>&quot;, and so on… You get the point. Anyway, it is kind of irrelevant <em>when</em> it happened. The important part, which is what I&#39;d like to revive, are the <strong><em>lessons that I learned</em></strong> during this experience. So, here we go…</p><h3>Back then in November 2016 …</h3><p>About two months ago, I attended the <a href="https://www.tryswift.co/"><strong>Try! Swift NYC</strong></a><strong> conference</strong> and the <a href="http://www.meetup.com/Brooklyn-Swift-Developers/"><strong>Brooklyn Swift Developers</strong></a><strong> meetup</strong>, and since then, my life as a software developer changed radically.</p><p>It’s almost impossible that I can pass on all the things I learned back then, so that won’t be the goal of this post. However, I’d like to channel, at least, a bit of all the excitement and good vibes that I’ve been feeling.</p><h3>Going To Conferences ✈️</h3><p>Recently, I’ve been asked the following question several times:</p><blockquote>&quot;Why going to conferences if you can watch the talks online?”</blockquote><p>This comes up mostly because of what it takes for us in Argentina to afford all the expenses.</p><p>Well, that’s mostly what I’ve learned: <strong>Going to conferences and meetups is not just about learning technical stuff</strong>. You also meet new people, you make new connections, you get to know different mindsets, and learn different ways of thinking. You also have fun. You also end up with new ideas. You also change. And by changing you grow, in your personality and in becoming a technical expert. And a big list of etceteras, which can all fit in this fact: <strong>YOU LEARN ABOUT LIFE</strong>.</p><p>Of course, all of this depends on you: you have to be open to these kind of experiences; otherwise, they won’t happen. Anyway, if you just start by being open and keeping a good attitude overall, the rest will just happen and everything will flow at some point: it’s nature.</p><h3>What Meetups Can Do 🗣</h3><p>About five months ago, I started to organize <a href="http://www.meetup.com/SwiftBA/">Swift meetups in Buenos Aires</a>. At that moment, I had no idea what a meetup represented, and I didn’t know what meetups could do for us. The only thing I knew was that “you meet other fellows and share knowledge”. Of course that happens, everyone ends up learning new stuff. But, besides that, I can guarantee that <strong>meetups have power</strong>. If you put energy into it, it will be spread, as simple as that.</p><p>During <a href="http://www.meetup.com/SwiftBA/events/231048182/">our first event</a> in June, two talks were given, and we began meeting each other in this local community. The feedback was great, and I was quite excited about it.</p><p>Later, in September, we held <a href="http://www.meetup.com/SwiftBA/events/232728330/">our second event</a>, and the outcome was awesome. Even more excited people than the first time and three speakers, with whom I kept in contact after the event: I gave them my good feedback about how everything went, and their feedback to me was gratifying too. All of this made me want to go on with it.</p><p>Besides the stuff overall, I also learned that little things can make the huge diference. For instance, in his talk, <a href="https://twitter.com/FranDepascuali">Francisco Depascuali</a> mentioned an app for a charity project he was working on: <a href="http://www.proyectoalimentar.org/">Proyecto Alimentar</a>. For non-spanish speakers: it’s about a community whose commitment lies in reducing the contradiction between people wasting food and the need of other people for it, i.e. turning that <em>wasting</em> into <em>helping</em>.</p><p>Getting to know these kind of things really motivates you; everyone learns from each other, yet it’s not only about the technical knowledge.</p><p>With results like these, you feel thankful, happy; but most important, you feel <strong>empowered</strong> to do more and more things that can help the community and, why not, the world. At the same time, you feel <strong>successful</strong> in your career path. Give and take. It’s about life.</p><h3>We Are Sowing 🌱</h3><p>Everything we sow today is tomorrow’s harvest. Somehow, we are leaving a mark. If we want to live in a better world, we have to strive for it.</p><p>One thing I’ve realized is that <strong>spreading good messages pushes people towards success</strong>. And, of course, everything depends on what kind of <em>success</em> we are talking about. Individually, I’m talking about growth and personal fulfillment. As for communities, I’m referring to collective development and general well-being. I hope that’s the <em>success</em> most of us look for.</p><p>In relation to what I mentioned above, <strong>meetups and conferences are a great place for these things to happen</strong>, and it’s really good to know that. This is mainly why I’m writing today. If you have participated in these kind of events, you will probably know what I’m talking about. If you haven’t, it’s never too late: I encourage you to do so, you’ll experience the benefits by yourself. If you want it, go for it.</p><h3>Balance ⚖️</h3><p>I’ve just talked about meeting people and getting involved in communities. Enhancing your social skills does contribute to your Career Path. But, what about your technical skills?</p><p>It’s worth mentioning the importance of maintaining a <a href="http://domain.me/technical-skills-vs-soft-skills-finding-the-balance/"><strong>balance</strong></a> between your <strong>technical</strong> and <strong>social</strong> skills. When you look at the big picture of yourself as a professional, these two complement each other. To be one day an architect or lead developer, you wouldn’t be complete if you’re pure technical, in the same manner you wouldn’t be complete if you’re just social either.</p><h3>Mentors, Not Idols 👨‍🏫</h3><p>Finally, I want to stand out the importance of having <a href="https://en.wikipedia.org/wiki/Mentorship">mentors</a>. Not only in your professional career, but also in every aspect of your life.</p><p>Mentors are people from whom you learn, people who inspire you, people who motivate you to grow. Nevertheless, they do not escape from the fact that they are just that: people. They are humans; ergo, not perfect. They make mistakes, as you do. They learn, as you do. They can be really good at certain things, and really terrible at others, as you are. Be aware of that: Always remark the good aspects of every mentor in your life, and take the best of them. You would not want to be like someone _at all_. You might want to acquire someone’s knowledge and/or ways of thinking <em>in certain aspects</em> of your life. This is the best way of being yourself: choosing, prioritizing, and being selective, always being guided by your principles.</p><p>Again, mentoring is a give and take. Without realizing it, you might be mentoring some people in some aspects of their lives, too.</p><h3>Further Reading 📚</h3><p>A lot can be discussed on these topics, but this article ends here. If you enjoyed it and are eager to read more, below you’ll find a list with some related resources that might be of your interest. Thank you for reading.</p><ul><li><a href="https://opbeat.com/community/posts/healthy-minds-in-a-healthy-community-by-erik-romijn-and-mikey-ariel/">Healthy Minds in a Healthy Community </a>— <em>How communities can be a good place for helping and being helped.</em></li><li><a href="https://medium.com/tech-lead-talks/come-together-3a308f671f30#.q8e37jk94">Come Together</a> —<em> The outcomes of meeting people face-to-face instead of virtually.</em></li><li><a href="https://realm.io/news/altconf-natasha-murashev-digital-nomad/">The Secret Life of a Digital Nomad</a> — <em>Great talk on escaping from your comfort zone and some advices you have to keep on mind while doing so.</em></li><li><a href="http://nsakaimbo.me/blog/2016/10/25/a-retrospective-on-try-swift-nyc-2016">A Retrospective on Try! Swift NYC 2016</a>— <em>A summary of how it felt attending this conference.</em></li></ul><p>Thank you for reading.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=90aa5e8cbfd2" width="1" height="1" alt=""><hr><p><a href="https://medium.com/tech-lead-talks/the-power-of-meeting-people-90aa5e8cbfd2">The Power of Meeting People</a> was originally published in <a href="https://medium.com/tech-lead-talks">Tech Lead Talks</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[The Strategy Pattern  in iOS Apps]]></title>
            <link>https://medium.com/@volbap/the-strategy-pattern-in-ios-apps-346abc9e86a6?source=rss-2261535f21e------2</link>
            <guid isPermaLink="false">https://medium.com/p/346abc9e86a6</guid>
            <category><![CDATA[quality-software]]></category>
            <category><![CDATA[patterns]]></category>
            <category><![CDATA[ios]]></category>
            <category><![CDATA[swift]]></category>
            <category><![CDATA[programming]]></category>
            <dc:creator><![CDATA[Pablo Villar]]></dc:creator>
            <pubDate>Tue, 16 Jan 2018 13:21:27 GMT</pubDate>
            <atom:updated>2018-07-31T20:42:58.465Z</atom:updated>
            <content:encoded><![CDATA[<h3>The Strategy Pattern in iOS Apps</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*UyMu5XACjjVhcs9Z2ZZStw.png" /></figure><p>The <a href="http://www.blackwasp.co.uk/Strategy.aspx">Strategy Pattern</a> is one of the first <a href="https://en.wikipedia.org/wiki/Design_Patterns">design patterns</a> I’ve learned in the theory. Sadly, however, it was very difficult for me to find <em>real</em> use cases where it could be applied in actual iOS codebases. Most books and tutorials showcase examples that are good for understanding what the pattern goes about (by using everyday objects such as animals, vehicles, or pizzas), but are usually far away from the actual code that you encounter in your projects.</p><p>In this article, I will expose concrete scenarios that I&#39;ve recently stumbled upon while developing some iOS apps, and in which<strong> I could find the pattern to be an elegant solution that successfully led the code towards improvement</strong>.</p><h3>A Real Use Case: Followers List</h3><h4>The Scenario</h4><p>A <em>social network</em> app. I needed to add a screen that would show a list of all the current user’s followers. This screen also needed some complex functionality such as pagination and filtering followers by certain search criteria. The point was that <strong>a very similar screen already existed</strong>, but this one would show <em>trending</em> users instead of followers.</p><h4>The Regular Solution</h4><p>The first solution that would usually come to my mind was trying to reuse that existing view controller&#39;s code by making some differentiation <em>within</em> it, like:</p><pre>enum UserType { case trending, followers }<br>var userType: UserType! // set from the outside</pre><pre>var users: [User] = []</pre><pre>// and at some point in the view controller...</pre><pre>switch userType {<br>case .trending:    <br>    users = retrieveTrendingUsers()<br>case .followers:  <br>    users = retrieveFollowers()<br>}</pre><p><em>I&#39;m over-simplifying the code from the actual code for readiness purposes. Of course, there were more complex stuff like users being fetched asynchronously (I had to use completion closures instead of direct assignation), etc... But these things don&#39;t matter for the purpose of the example.</em></p><p>The problem with this approach is the <strong>switch</strong> statement inside the view controller: <strong>It&#39;s a code smell</strong>, and I will explain you why. Let&#39;s suppose that in a near future, we are requested to add a <em>Users that I&#39;m following </em>screen to the app, and it has the exact same functionalities that these two we are handling above. In that case, we&#39;d need to add an extra case to both the enum and the switch statement. Now imagine a further future where we were requested to add more similar screens that <strong>only</strong> vary on how the users are fetched: We&#39;d end up with a huge switch statement with lots of cases and we&#39;d have to modify the view controller each time we need to add a new one. That doesn&#39;t sound right. Wouldn&#39;t it be better if we could make the view controller independent of this retrieval process? Couldn&#39;t we find a place in the code where the view controller can say <em>&quot;OK, I know I need to fetch users here, someone else will give me these, I don&#39;t care where they come from. I just know how to display and filter them.&quot;?</em></p><h4>A Better Approach</h4><p>Let&#39;s define an interface for fetching users, which is the process that we want the view controller to be independent of:</p><pre>protocol UsersStore {<br>    func retrieveUsers() -&gt; [User]<br>}</pre><pre>class TrendingUsersStore: UsersStore {</pre><pre>    func retrieveUsers -&gt; [User] {<br>        // returns trending users from server<br>    }</pre><pre>}</pre><pre>class FollowersStore: UsersStore {</pre><pre>    func retrieveUsers -&gt; [User] {<br>        // returns current user&#39;s followers from server<br>    }</pre><pre>}</pre><p>Finally, let&#39;s have the view controller compatible with this interface:</p><pre>var usersStore: UsersStore!</pre><pre>// somewhere in the view controller...</pre><pre>users = usersStore.retrieveUsers()</pre><p>In the same way a certain userType was injected from the outside depending on the navigation (probably in a prepareForSegue function or similar), now the corresponding usersStore has to be injected instead.</p><pre>// from somewhere else outside the view controller</pre><pre>controller.usersStore = FollowersStore()</pre><h4>What are the Benefits?</h4><p>We have just gained a lot with this little change. Notice that we’ve eliminated the enumeration, and that <strong>we no longer need to break inside something</strong> (the enum and the switch statement) to add more code to handle variants. Now, if we were to add more ways to retrieve users, we could just add new classes that conform to the UserStore protocol, without having to modify anything. <strong>This is pretty much the </strong><a href="https://en.wikipedia.org/wiki/Open/closed_principle"><strong>open/closed</strong></a><strong> principle</strong>, that you’ve probably heard of. Our view controller is now <strong>closed for modification</strong> (we don’t need to modify it whenever we need to add more similar screens), and our UserStore protocol is <strong>open for extension</strong> (we can add as many classes as we want conforming to it in order to have more and more ways for retrieving users).</p><p>Also, <strong>we are </strong><a href="http://www.artima.com/lejava/articles/designprinciples.html"><strong>programming to an interface, not to an implementation</strong></a> anymore (that&#39;s something we&#39;ve been told we should accomplish over, and over, and over). Notice that the view controller relies on an interface: it knows <em>what</em> should be done (users retrieval), it doesn&#39;t care about <em>how</em> it&#39;s done (whether it&#39;s by requesting followers to the server, or by requesting trending users to the server, or by fetching users from a local database, or by fetching hardcoded users from a test case, etc).</p><p>Speaking of which, <strong>this is a huge win for testability too</strong>. Given that how the users are fetched is not a responsibility of the view controller anymore, now we can inject it with <em>fake</em> users that we create in our test cases, and check whether or not these are displayed and filtered properly.</p><p>What’s more, <strong>our view controller is now smaller</strong>, as it has been taken away some responsibilities. By achieving this, we are following the <a href="https://en.wikipedia.org/wiki/Single_responsibility_principle">single responsibility principle</a> a bit more than before.</p><h3>Other Use Cases</h3><p>I&#39;ve also come across other scenarios that I will briefly share below, so you can see how easy it is to find good opportunities to apply the Strategy Pattern in iOS apps:</p><ul><li>A feed that would show posts in different fashions depending on the user’s settings (e.g. dark mode). The <a href="https://softwareengineering.stackexchange.com/a/311122">seam</a> here was the point in the code where the cells were formatted. Dark format, light format, among others, were turned into <em>strategies</em> (classes in this case) that conformed to a unique CellFormatter protocol.</li><li>A screen that had to show messages (as in a <em>chat</em> fashion), but depending on the current user&#39;s type, the messages could be fetched in very different ways (hitting different APIs and parsing items differently). Even though the root problem here was clearly<em> </em>the API&#39;s design, changing it was not an option at that point, so, applying strategy for the messages retrieval client-side was a clever and practical solution to enhance the iOS app code.</li></ul><p>Finally, I want to give you a <em>magic formula</em> to detect the usual suspects:</p><ul><li>Suspect from any view controller that is being reused in screens that are alike, but differ in some aspects, and whose code in charge of handling those differences is inside the view controller, and is not trivial. Watch out for switch statements (or worse, long if-else chains) that need to add more and more cases to handle variants.</li></ul><p>Of course, there are other situations where the pattern applies as well. I just found this one involving ViewControllers&#39; internal logic to be very repetitive among apps, and I have rarely seen the pattern already applied in these cases.</p><h3>Conclusions</h3><p>We should not force any design pattern to be applied at all costs. However, we&#39;ve learned that finding scenarios where the Strategy Pattern does fit in iOS codebases appears more often than we think.</p><p>Applying the pattern is actually <strong>really simple</strong>, and it has <strong>huge benefits</strong>, as I mentioned above:</p><ul><li><strong>Get rid of code smells</strong> like enums / switch statements that need to be modified frequently</li><li><strong>Program to interfaces and not to implementations</strong></li><li><strong>Follow the Open/Closed Principle</strong></li><li><strong>Facilitate unit tests </strong>through dependency injection</li><li><strong>End up with shorter classes </strong>by following the Single Responsibility Principle</li></ul><p><strong>This story is published in </strong><a href="http://blog.usejournal.com"><strong>Noteworthy</strong></a><strong>, where 10,000+ readers come every day to learn about the people &amp; ideas shaping the products we love.</strong></p><p><a href="http://blog.usejournal.com"><strong>Follow our publication</strong></a><strong> to see more product &amp; design stories featured by the </strong><a href="https://usejournal.com/?/utm_source=usejournal.com&amp;utm_medium=blog&amp;utm_campaign=guest_post&amp;utm_content=pablo_villar"><strong>Journal</strong></a><strong> team.</strong></p><ul><li><a href="http://blog.usejournal.com"><strong>Follow our publication</strong></a><strong> to see more product &amp; design stories featured by the </strong><a href="https://usejournal.com/?/utm_source=usejournal.com&amp;utm_medium=blog&amp;utm_campaign=guest_post&amp;utm_content=dr_brady_salcido"><strong>Journal</strong></a><strong> team.</strong></li></ul><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=346abc9e86a6" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Debuggable Alerts in iOS]]></title>
            <link>https://medium.com/@volbap/debuggable-alerts-in-ios-df7e0a2fc779?source=rss-2261535f21e------2</link>
            <guid isPermaLink="false">https://medium.com/p/df7e0a2fc779</guid>
            <category><![CDATA[ios]]></category>
            <category><![CDATA[ui]]></category>
            <category><![CDATA[qa]]></category>
            <category><![CDATA[swift]]></category>
            <category><![CDATA[productivity]]></category>
            <dc:creator><![CDATA[Pablo Villar]]></dc:creator>
            <pubDate>Mon, 08 Jan 2018 13:01:01 GMT</pubDate>
            <atom:updated>2018-01-08T13:01:01.487Z</atom:updated>
            <content:encoded><![CDATA[<p>Quite often in iOS projects, it happens that QA people find issues like this one:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/487/1*tbwKsdvBipKztRlgRci2Iw.png" /><figcaption>That doesn&#39;t give us any clue, does it?</figcaption></figure><p>Usually, they report the bug, and, when it’s your turn to fix it, the first thing you think is <em>“Okay, I’ll put a breakpoint where the alert is created and see what’s going on”</em>. Next step, you’re doing something like this:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/869/1*EhwfkvVjdyjKn_Sq_dNfvA.png" /></figure><p>To find out that the reason could just be:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/308/1*LyotMjEFDs16_gXbGeYOXQ.png" /><figcaption>(Backend people, don&#39;t feel offended, this isn&#39;t always the case…)</figcaption></figure><p>A <strong>server error</strong>! Your code might look different, though. Maybe you are not even parsing server errors as Error objects in your code (you should), but follow me on this one… When this is the case, couldn’t we <strong>all</strong> save a lot of time if we knew <em>beforehand</em> that the issue was caused by the server, and not by the client app?</p><p>What if the alert view itself could describe what&#39;s going on?</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/487/1*hXQpSGrY4ZX8MFZD8veyuw.png" /><figcaption>Here, at least we&#39;ve got a clue of what happened.</figcaption></figure><p>This way, testers would be able to see that information <strong>without needing any developer debug it</strong>.</p><p>Of course, this debug information shouldn&#39;t reach final users. But that is not difficult to achieve, as we&#39;ll see next… Introducing: debuggable alerts.</p><h3>UIAlertController+Debug</h3><p>We can introduce a simple mechanism to append debug information to our alerts in an extension of UIAlertController :</p><pre>extension UIAlertController {</pre><pre>convenience init(title: String?, message: String?, error: Error? = nil, enableDebug: Bool = Settings.shared.enableAlertLogs) {<br>        var finalMessage = message ?? &quot;&quot;<br>        if enableDebug, let theError = error {<br>            finalMessage += &quot;\n\n⬇ DEBUG INFO ⬇\n\n\(theError)&quot;<br>        }<br>        self.init(title: title, message: finalMessage, preferredStyle: .alert)<br>        let ok = UIAlertAction(title: &quot;OK&quot;, style: .default) { _ in<br>            self.dismiss(animated: true, completion: nil)<br>        }<br>        addAction(ok)<br>    }</pre><pre>}</pre><p>Notice that I distinguished between the scenario where we want debug messages vs. the one where we don&#39;t. We should not display any debug information in AppStore builds: these messages are meant to be internal and should never reach final users.</p><p>In this example, the default value for the enableDebug boolean is loaded from our application&#39;s shared settings, and from there, it can be automatically set depending on the build configuration, as I explain in <a href="https://medium.com/@volbap/effective-environment-switching-in-ios-6df0b08e9556">this article about how to switch our app&#39;s settings in an efficient way</a>.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/657/1*Rd2tKAFvEUeHEfkHTpze-g.png" /><figcaption>What our team will see vs. What final users will see</figcaption></figure><p>Also, an Error instance should always be passed to the alert&#39;s initializer, so that the debug information can be obtained from there when needed.</p><p>Said that, this is how you would initialize the alert:</p><pre>case .failure(let error):<br>    let alert = UIAlertController(title: &quot;Oops&quot;, message: &quot;Feed could not be loaded.\nTry again later.&quot;, <strong>error: error</strong>)<br>    present(alert, animated: true, completion: nil)</pre><p>As you can see, since the enableDebug parameter takes a default value, you don&#39;t even need to bother passing it through the initializer&#39;s call, that&#39;s done behind the scenes for you.</p><p>Of course, any iOS dev involved in the project should always leverage this custom initializer instead of the default one when creating an alert. But that’s about a practice that is not difficult to get used to.</p><h3>The Outcome</h3><p>Now, let&#39;s compare what the process was like <strong><em>without</em></strong> debuggable alerts…</p><ol><li>QA can’t load feed, error says “Could not load feed. Try again later”</li><li>QA reports bug to PM</li><li>PM creates associated ticket and assigns to an iOS dev</li><li>iOS dev takes the ticket and starts debugging</li><li>iOS dev finds out the cause was actually the server</li><li>iOS dev notifies PM about it</li><li>PM reassigns ticket to backend dev</li><li>Backend dev grabs ticket and fixes issue</li></ol><p>… to what it is <strong><em>with</em></strong> debuggable alerts:</p><ol><li>QA can’t load feed, error says “Could not load feed. Try again later. <strong>500 server error</strong>”</li><li>QA reports bug to PM</li><li>PM creates associated ticket and assigns it<strong> directly to a</strong> <strong>backend dev</strong></li><li>Backend dev fixes the issue</li></ol><p>See the difference? The debug message is something really small, but it has a <strong>huge impact</strong> on the process. No iOS devs were required to take a look at the issue in the latter scenario. No time and effort wasted. Lots of context switches avoided. This kind of situation happens more often than what you think. So, why not using something that simple to our projects that could benefit us like this?</p><h3>In Conclusion</h3><p>By introducing this subtle practice, <strong>we can make a big difference by saving time and effort in our everyday work</strong>. Also, the whole team becomes more efficient and in consequence is able to deliver results faster.</p><p>In this article, I just exposed the example of the “<em>500 server error</em>” because I consider it being maybe one of the most annoying to mobile devs. However, the benefits of using debuggable alerts also apply to several other scenarios where having some little debug information about the error can help a lot by pointing out where the problems could be, without having to manually debug.</p><p>Happy coding!</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=df7e0a2fc779" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Effective Environment Switching in iOS]]></title>
            <link>https://medium.com/@volbap/effective-environment-switching-in-ios-6df0b08e9556?source=rss-2261535f21e------2</link>
            <guid isPermaLink="false">https://medium.com/p/6df0b08e9556</guid>
            <category><![CDATA[xcode]]></category>
            <category><![CDATA[settings]]></category>
            <category><![CDATA[swift]]></category>
            <category><![CDATA[productivity]]></category>
            <category><![CDATA[ios]]></category>
            <dc:creator><![CDATA[Pablo Villar]]></dc:creator>
            <pubDate>Tue, 19 Dec 2017 12:59:41 GMT</pubDate>
            <atom:updated>2019-01-28T21:07:33.209Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*phOfJPH1G1VTDfpyqVlkow.jpeg" /></figure><h3>Introduction</h3><p>Engaging gears in a project involves powering up our everyday processes. In the iOS world, a very important one is how we deal with <strong>environments </strong>and other <strong>settings</strong> that need to be customized depending on the audience. Xcode does have a set of tools to help us along the way. Unfortunately, though, I&#39;ve seen that most of the times teams are not even close to take the best of these tools. It&#39;s not their fault: I think Apple doesn&#39;t do very well at encouraging good practices, as they just provide <em>not-so-useful</em> configurations by default.</p><p>In this article, we&#39;ll explore how we can take advantage of Xcode configurations, and how we can define our app&#39;s settings in an organized way.</p><h3>Xcode Configurations</h3><p>The way Xcode can package different settings into your builds is through configurations. Roughly speaking, a configuration is just a bunch of settings that define how the compiler must create the build. The IDE lets you customize some settings depending on the different configurations. You&#39;ve very likely seen these:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/533/1*3M9G9pHYcupklR3xdFX7PA.png" /><figcaption>… and so on.</figcaption></figure><h4>Debug vs. Release</h4><p>These are the two configurations that Xcode gives us by default. Of course, you can create your own, but this isn&#39;t a common practice since there aren&#39;t <em>universal</em> conventions adopted by the iOS community about which configurations could be useful to have depending on the project.</p><p>These two default configurations have several differences, which I&#39;m not going into detail here, but can be summarized in:</p><blockquote>In a <strong>debug</strong> build, the complete symbolic debug information is emitted to help while debugging applications and also the code optimization is not taken into account (faster build times). Whereas, in <strong>release</strong> build, the debug info is not emitted and the code execution is optimized (slower build times).</blockquote><p>As for their usage, <strong>debug</strong> is the configuration we normally use in our everyday life, whereas <strong>release</strong> is what we use to distribute our apps to other people: testers, project managers, customers, the world.</p><p>The point is that, these two are usually not enough. What&#39;s more, devs often mislead ≪<em>debug vs. release</em>≫ with ≪<em>staging vs. production</em>≫, concepts that should not be mixed up.</p><h4>We can do better</h4><p>Some projects work with different environments: development, staging, production, pre-production, etc. Take whatever you want. This classification doesn&#39;t have a natural connection with the two default configurations we&#39;ve discussed above. Even if we tried to force this correspondency, it wouldn&#39;t always work out very well. For instance, if you want to prepare a <strong><em>release</em></strong> build, it doesn&#39;t mean it should point to a <strong><em>production</em></strong> server: Take the situation where you have to prepare a release build for QA which needs to be tested against a staging server. Default configurations just won&#39;t work.</p><p>In consequence, I propose replacing the basic debug &amp; release configurations by others that could help us a bit more. To keep it simple, I&#39;ll only include staging and production environments in this approach, but you&#39;ll observe that it&#39;s very easy to add more environments as you need them.</p><h4>Let&#39;s redefine configurations</h4><p>We can define these 4 configurations instead:</p><ul><li>Debug Staging</li><li>Debug Production</li><li>TestFlight Staging</li><li>TestFlight Production</li></ul><p>By just reading their name, you might have guessed what they are about. Here are the details:</p><ul><li>The first two of them (Debug Staging &amp; Debug Production) behave as the original Debug configuration, but <strong>each one points to a different environment</strong>.</li><li>Something similar happens with the last two (TestFlight ones). They behave as the original Release one, including compiler optimizations and excluding debug information, but <strong>each one works on its corresponding environment</strong>.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/516/1*E24WkTnP6IXFceTvE3MtxQ.png" /><figcaption>It&#39;s very simple to achieve this. Just go to your Project Settings &gt; Info &gt; Configurations, and hit the + button. Duplicate the Debug configuration and rename the original one to “Debug Staging” and the new one to “Debug Production”. Do the proper with Release too.</figcaption></figure><p>You should end up with something like this:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*TalswynK3oCREkrhNBJGlg.png" /><figcaption>A project that has 4 different configurations</figcaption></figure><h4>The Fifth Element</h4><p>There is a reason why I chose to call the release configurations “<em>TestFlight</em>” instead of “<em>Release</em>”. There might be certain events in your code that need to happen only when the app is used by final users, not by testers or customers. A clear example is the usage of analytics to track events. It could be a requirement that event tracking should only be applied to final users, not to testers under production environments. In this case, we are talking about a <em>TestFlight Production</em> configuration with some subtle differences, hence the need for a distinction. Introduce our fifth configuration:</p><ul><li>AppStore</li></ul><p>This configuration can be quickly duplicated from TestFlight Production. Notice that you won&#39;t always need it, as you could not have to perform anything different than when on TestFlight Production.</p><p>Now, you might wonder <strong>how you can manage different things to happen in your app depending on the selected configuration</strong>. That&#39;s explained in the next section.</p><h3>Custom Settings</h3><p>There are many ways to achieve what we need: Perform different actions based on which configuration is selected. There are precompiler directives, environment variables, different plist files, and more. Each one has its pros and cons. I&#39;ll just focus on the way I use to do it, which I consider a very clean one.</p><p>Those different actions that need to be done depending on the configuration can usually be encapsulated into variables, which will define our app&#39;s behavior. These variables are usually called <strong>settings</strong>. Example of settings are: the server&#39;s API&#39;s base URL, the Facebook App ID, the logs&#39; detail level, whether or not offline access is enabled, <a href="https://medium.com/@volbap/debuggable-alerts-in-ios-df7e0a2fc779">whether or not to show debug information in alerts</a>, etc.</p><p>Next up, I&#39;ll show you the way I currently manage custom settings to vary depending on the selected configuration, which I consider a very convenient approach so far, based on my experience.</p><h4>Settings.swift</h4><p>The app&#39;s custom settings can be easily accessible through a singleton.</p><pre>struct Settings {</pre><pre>    static var shared = Settings()</pre><pre>    let apiURL: URL<br>    let isOfflineAccessEnabled: Bool<br>    let feedItemsPerPage: Int</pre><pre>    private init() {<br>        let path = Bundle.main.path(forResource: &quot;Info&quot;, ofType: &quot;plist&quot;)!<br>        let plist = NSDictionary(contentsOfFile: path) as! [AnyHashable: Any]<br>        let settings = plist[&quot;AppSetings&quot;] as! [AnyHashable: Any]<br>        <br>        apiURL = URL(string: (settings[&quot;ServerBaseURL&quot;] as! String))!<br>        isOfflineAccessEnabled = settings[&quot;EnableOfflineAccess&quot;] as! Bool<br>        feedItemsPerPage = settings[&quot;FeedItemsPerPage&quot;] as! Int<br>        <br>        print(&quot;Settings loaded: \(self)&quot;)<br>    }</pre><pre>}</pre><p>This struct is in charge of reading and storing the settings (that we&#39;ll later define in the app&#39;s Info.plist file) so that they are available from anywhere in the codebase. I prefer to perform force unwraps here since if a setting is missing, I don&#39;t want my app to run.</p><h4>Info.plist</h4><p>We will define our settings in the Info.plist file. I recommend using a separate dictionary entry to group them all:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*NlmqO1X2mvioMWhj9swBXg.png" /></figure><p>So far, we have set up a clean way to retrieve our app&#39;s settings. However, they don&#39;t vary among configurations yet. We&#39;re almost there.</p><h4>User-Defined Settings</h4><p>Let&#39;s think. What things normally change depending on the configuration in any project? Well, there is the compiler optimization level, there are the header search paths, the provisioning profiles, and much more. Wouldn&#39;t it be nice if we could define our own custom <em>things-that-vary-upon-selected-configuration</em>? Well, it turns out that we can, by creating User-Defined Settings.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/830/1*ilzKZsI_BCcgal5tzhkUWw.png" /><figcaption>Creating User-Defined settings is very easy, just go to your Target &gt; Build Settings, hit the + button, and select “Create User-Defined Setting”. They can be created at the project level too; I just consider the target level to be a better fit for them.</figcaption></figure><p>Since your User-Defined Settings may have to live together with others that you haven&#39;t created, it&#39;s recommended that you use a prefix convention to name yours.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/594/1*25yr4QF6vBFNK2F1DOh6nw.png" /><figcaption>I used my initials here to prefix my User-Defined Settings. I suggest using the project&#39;s name initials.</figcaption></figure><p>Now, to refer to one of these from the Info.plist file, you just do it like this:</p><pre>$(YOUR_USER_DEFINED_SETTING_NAME)</pre><h4>Integrating them all</h4><p>This is where the magic occurs: You can replace all the fixed strings from the Info.plist entries that correspond to your settings with their corresponding references to each User-Defined Setting. You will need one User-Defined Setting for each custom setting that you have.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*UMNV9ZDKIjr3J3UpWKOIbA.png" /></figure><p>When the Info.plist file is compiled, it&#39;ll take all the settings values that correspond to the selected configuration, and these will be fixed on each entry at compile time.</p><p>Now, you can <em>nicely</em> refer to any setting from anywhere in your code like this:</p><pre>if Settings.shared.isOfflineAccessEnabled {<br>    // do stuff<br>}</pre><p>Finally, selecting which configuration to compile with is a piece of cake, either from Xcode:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/899/1*D5Z2ipWESxi1MW5s0xvmMw.png" /></figure><p>Or from CLI:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/808/1*MHK2NWnxjk0rPY4mFuzAZQ.png" /></figure><h3>Wrapping Up</h3><p>By using this approach, we have gained these benefits:</p><ul><li>Organized builds workflow.</li><li>Organized way to manage app&#39;s custom settings.</li><li>Flexibility to change settings depending on the configuration.</li><li>Easiness with continous integration (given that selecting which configuration to compile with is easily doable in command line tools).</li></ul><p>However, there are some caveats that are worth the mention:</p><ul><li>There is no flexibility to change settings at run time, as they are packaged with the build at compile time.</li><li>Switching often between configurations is not that nice: Xcode creates a build from scratch each time you change the build configuration, which means having to wait for the entire project to recompile in that case.</li><li>Settings can only be modified through the .xcodeproj; there is no flexibility to change their values <a href="https://hackernoon.com/system-settings-9ed72d5ef629"><em>nicely</em></a> from the outside.</li><li>User-Defined Settings are <a href="https://medium.freecodecamp.org/how-to-securely-store-api-keys-4ff3ea19ebda"><strong>exposed to anyone that has access to the code</strong></a><strong>, </strong>so it&#39;s not a recommended place to put any key.</li></ul><p>These pitfalls can be solved, though. The aim so far was just to improve our usage of these tools when coming from an almost zero-knowledge base. Mitigating these issues implies applying some modifications that complicates things a bit further, and they are out of the scope of this article, as I didn&#39;t want it to become too overwhelming. But believe me, we’ve done a lot. <strong>In an upcoming second part, we will explore how to face these issues and take our projects to the next level…</strong></p><p>To be continued.</p><figure><a href="https://usejournal.com/?utm_source=medium.com&amp;utm_medium=noteworthy_blog&amp;utm_campaign=guest_post_image"><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*f2IVAl0TbsfES9cFGYr40g.png" /></a></figure><p>📝 Read this story later in <a href="https://usejournal.com/?utm_source=medium.com&amp;utm_medium=noteworthy_blog&amp;utm_campaign=guest_post_read_later_text">Journal</a>.</p><p>🗞 Wake up every Sunday morning to the week’s most noteworthy Tech stories, opinions, and news waiting in your inbox: <a href="https://usejournal.com/newsletter/?utm_source=medium.com&amp;utm_medium=noteworthy_blog&amp;utm_campaign=guest_post_text">Get the noteworthy newsletter &gt;</a></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=6df0b08e9556" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Working efficiently with colors in Xcode]]></title>
            <link>https://medium.com/@volbap/working-efficiently-with-colors-in-xcode-bc4c58b16f9a?source=rss-2261535f21e------2</link>
            <guid isPermaLink="false">https://medium.com/p/bc4c58b16f9a</guid>
            <category><![CDATA[ios]]></category>
            <category><![CDATA[design]]></category>
            <category><![CDATA[colors]]></category>
            <category><![CDATA[swift]]></category>
            <category><![CDATA[xcode]]></category>
            <dc:creator><![CDATA[Pablo Villar]]></dc:creator>
            <pubDate>Wed, 06 Dec 2017 11:58:34 GMT</pubDate>
            <atom:updated>2018-12-02T02:23:15.254Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*2ru5YK_9HRJ62VgmzRqiCQ.jpeg" /></figure><h3>Hello there!</h3><p>It’s been a while since I shared <a href="http://inaka.net/blog/2014/09/05/getting-the-right-colors-in-your-ios-app/">Getting the right colors in your iOS app</a>, a blogpost I wrote for helping iOS devs prevent the color nightmare that happens every now and then. That blogpost was cool and got more visits than I expected, but, the information I exposed at that moment was neither complete nor certainly accurate, and it got outdated very quickly too. My appologies for taking too long to write about it again.</p><p>Today, I bring this update in order to help the iOS community once more, because, I found that there aren’t much articles out there that involve all the required information that one needs in order not to fail miserably when working with colors in Xcode.</p><p>After lots of research, information gathering, experiments, insights, and conclusions, I feel prepared to dive in to the colors world again. So, here we go…</p><h3>How do I set the right color?</h3><p>First things first. There are two ways of setting a color for a UI component in Xcode:</p><ul><li>Interface Builder</li><li>Programmatically</li></ul><p>No matter which one you use, the point is that, <strong>you need to make sure you obtain the same exact color in <em>either</em> case</strong>, even more if you consider that it’s very likely you’ll need to use both methods at some point in your project. Consistency is key.</p><p>It turns out that when you create a color programmatically, by calling UIColor(red:green:blue:alpha:), Xcode will create a color using the <a href="https://en.wikipedia.org/wiki/SRGB">sRGB IEC 61966-2-1</a> color space (more on color spaces later). Given that case, whenever you are setting a color through Interface Builder, you must ensure that it&#39;s being created with that same color space too, so that, the color is exactly the same.</p><p>This is, given this code…</p><pre>let myCustomColor = UIColor(red: 38/255.0, green: 49/255.0, blue: 197/255.0, alpha: 1.0) // sRGB</pre><p>…you should make sure that you set the same RGBA values <strong>and you use the same color space</strong> when in Interface Builder…</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/512/1*YwXwvG-tFnWN2BQ1syfYWA.png" /></figure><p>You can quickly verify that the colors are the same by doing this simple experiment:</p><ol><li>Put a view inside a view</li><li>Set the outer view’s color programmatically</li><li>Set the inner view’s color via Interface Builder, using the same RGBA values, and selecting the sRGB color space</li><li>Build &amp; Run, and check out the outcome</li></ol><figure><img alt="" src="https://cdn-images-1.medium.com/max/838/1*VGpcNvsVcgghxUWR2QIp5w.png" /><figcaption>If you use UIColor(red:green:blue:alpha:) in your code, and you select sRGB when in Interface Builder, using the same RGBA values, the colors will match.</figcaption></figure><p>Well done! This is half of the process of being consistent, and it might have already solved your issues. However, in order to guarantee that the colors in your app match the UI designs you are supposed to follow, you must also make sure that the color you’ve picked is the one you’re supposed to use, and this is the hardest part, which I’ll cover in the next section.</p><h3>How do I pick the right color?</h3><p>Extracting the RGBA components of a color can be a cumbersome task, and this could be mostly because of a lack of understanding of how <a href="https://www.youtube.com/watch?v=N2T62ZHIu6s">color spaces</a> work. Long story short, I will try to summarize this complex world as best as possible.</p><p>In order to represent a color, two components are required:</p><ol><li><strong>Values</strong></li><li><strong>A color space</strong>, in which the color is represented ← <em>This is what most people don’t know</em></li></ol><p>On to the values, there are several models to depict them:</p><ul><li>RGBA (Red, Green, Blue, Alpha) ← the one we mostly use in Xcode</li><li>HSV (Hue, Saturation, Value)</li><li>HSL (Hue, Saturation, Lightness)</li><li>And more…</li></ul><p>These different models are just bells and whistles to work more comfortably when creating colors through UI sliders or fancy wheels, and I won’t get into detail here, since you’ll encounter yourself copying RGBA values about 99,99% of the time. It doesn’t matter whether you use 0–255 integer notation, 0–1 floating point notation, or Hex notation; it’s all the same as long as you do the maths well.</p><p>Now let’s talk about color spaces, which is where it does get complex…</p><h3>Color Spaces</h3><p>What’s a <a href="https://www.youtube.com/watch?v=N2T62ZHIu6s">color space</a>, anyway? Do I even need to care? The answer is <em>yes, at least a bit</em>.</p><p><strong>A color space is a component that defines which range of colors can be represented</strong> through the notations we mentioned above.</p><p>The human eye can see plenty of colors. In fact, it can see way more colors than what most screens can actually expose. This is because the hardware that screens use is somehow limited, and in consequence they work with restricted color spaces (at least more limited than what the human eye can see).</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*rd1IeecZwT-ASm2uZFypHw.png" /></figure><p><strong>Different screens represent colors through different color spaces, depending on the device’s hardware.</strong></p><ul><li><a href="https://developer.apple.com/library/content/documentation/DeviceInformation/Reference/iOSDeviceCompatibility/Displays/Displays.html#//apple_ref/doc/uid/TP40013599-CH108-SW3">All iPhones prior to iPhone 7</a> only represent colors within the <a href="https://en.wikipedia.org/wiki/SRGB">sRGB IEC 61966–2–1</a> color space (sRGB for short)</li><li>Whereas, newer Apple devices, such as the iPhone X, use a bigger color space that covers a wider gamut of colors, the <a href="https://en.wikipedia.org/wiki/DCI-P3">Display-P3</a> standard (or, just P3 for short)</li></ul><p>If you <a href="https://webkit.org/blog-files/color-gamut/Webkit-logo-P3.png">click here</a> you’ll see an image that contains a logo, which you’ll only distinguish if your display works with a P3 color space (otherwise, you’ll see a boring rectangle filled with just one reddish color).</p><p>Now that you understand what color spaces are, let’s explore the issues that they carry…</p><h3>How color spaces fit into RGBA values</h3><p>Let’s suppose we are using the RGBA notation to write down a color. With this notation, and a depth of 8 bits per channel, you can represent up to 255 x 255 x 255 colors = 16,581,375 (the famous <em>16 million colors</em>) and even more, when you combine them with the alpha component (x 255 again) you’ll get up to more than 4 billion (also known as <em>true color</em>). That is the amount of colors you can represent using this notation, and notice that this value is <strong>fixed</strong>. It doesn’t matter whether you choose a bigger or smaller color space to work with: You cannot represent more than that number of colors in RGBA. Imagine this as having a fixed number of 4,228,250,625 slots: Any color you want to represent must fall into one of these slots. Notice this: You won’t necessarily get a bigger number of colors by using a bigger color space, because there is a limit on how many colors you can write down. What changes, however, is that <strong>when working on a bigger color space, the variation between two consecutive values</strong> (for instance: #A0A0A0 and #A0A0A1) <strong>is more noticeable to the eye</strong>. This happens because when using a bigger color space, more actual colors have to fit within the same amount of fixed slots. Besides, when in a bigger color space, the values on the extremes will represent <a href="https://petapixel.com/2009/09/17/why-you-should-probably-use-srgb/">more vivid colors</a> (e.g. #FF0000 in P3 is a much more vivid red than #FF00000 in sRGB). It&#39;s because of these observable changes that you probably get headaches when not getting the exact color you want: Maybe you are just obtaining their RGBA values from one color space, and generating them in Xcode using a different color space. <strong>If the color spaces mismatch, you will get incorrect colors in your app, in spite of having replicated the same RGBA values.</strong></p><p>Now that you know that color space matters, you must make sure that you pick colors from the proper color space. This is, <strong>if you are using </strong><strong>sRGB to represent a color in your app, you must pick colors from a </strong><strong>sRGB color space</strong>, and just replicate the same RGBA values in Xcode. This sounds a lot simpler than it really is. The million dollar question is, how do you pick a color from a sRGB space?</p><h3>Getting the right RGBA values</h3><h4>Photoshop</h4><p>If you are cropping your assets right away from a PSD file, then it’s a piece of cake: You just open it in Photoshop and use the eyedropper tool to get the RGB values. This way, you will get RGB values with a full alpha component (A = 1). If you want to be more thorough, you can check out the individual layer components (for instance, a color overlay) and take the exact RGB and Alpha values (transparencies might play an important role in your app’s design). But, be aware: The PSD file must be opened using the sRGB color space as its working space. You can check that out by going to Edit &gt; Color Settings. If it’s not using sRGB, you will need to convert the file to that profile, and it’s highly suggested that you warn the designers to use sRGB profiles when creating assets for mobile apps.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/619/1*nyfkvZZVaLgNruoKoyP3mA.png" /><figcaption>I have to admit that I used to ignore these alerts…</figcaption></figure><p>There is another option, though. You can get the color from a different profile, say Adobe RGB for instance (which is bigger than sRGB), and generate the colors in Xcode by always using the Adobe RGB color space, both via Interface Builder (by selecting it from the dropdown menu) and via code (by using a different function to generate the color, other than the conventional UIColor(red:green:blue:alpha:) that I mentioned above - you can check out <a href="https://developer.apple.com/documentation/uikit/uicolor">the official documentation</a> on how to do that). However, <strong>sRGB is the standard that most applications use</strong> (e.g. web navigators, Sketch, Zeplin, etc, not to mention Xcode itself too), that&#39;s why I highly recommend sticking to this one.</p><h4>Other Design Apps</h4><p>If you are getting your assets from tools like Sketch or Zeplin, you can get the RGBA values straight from there, without even needing an eyedropper tool. These values are represented in the sRGB color space.</p><h4>Digital Color Meter</h4><p>Another simpler approach to extract RGB values is to use an eyedropper tool from your Mac. There is the native Digital Color Meter app that can do that. The problem with this one is that, if your iOS app needs to use a bigger color space than the one that your display works with (for instance: you are using P3 for your app, but your Mac’s display is limited to sRGB), then the eyedropper won’t catch those P3 colors that your sRGB display cannot represent. To prove that, you can <a href="https://webkit.org/blog-files/color-gamut/Webkit-logo-P3.png">check out this image</a>, and use Digital Color Meter to extract its RGB values while working in a sRGB display. You’ll always get the same RGB values across the whole image. On the other hand, if you open it in Photoshop (using P3 as working color space), and use the eyedropper tool, you’ll realize that there are two different colors in the image, even though you won’t be able to distinguish them through your sRGB display. I have discovered this through lots of try-and-error-like experiments. Another issue with Digital Color Meter is that you have to make sure that the image is opened with an app that takes into account its embedded color profile. Preview app works well for this purpose. Another experiment led me to realize that picking a color from an image opened in Preview vs. picking the same color straight from Finder’s carousel preview (which does not embed the profile) lead to different RGB values.</p><h3>What about image assets?</h3><p>Besides picking individual colors properly, you must make sure to pick files properly too when working with entire images. As stated by <a href="https://developer.apple.com/ios/human-interface-guidelines/visual-design/color/">the official documentation</a>,</p><blockquote><em>Apply color profiles to your images. The default color space on iOS is Standard RGB (sRGB). To ensure that colors are correctly matched to this color space, make sure your images include embedded color profiles.</em></blockquote><p>To know which color profile is embedded into an specific image, right-click the file and check it out under Get Info. To embed the image into a different color profile, you can use tools like Photoshop.</p><h3>Shouldn&#39;t I work with P3?</h3><p>Now you might wonder, if the newest devices can display P3, why should I stick to sRGB? Well, the truth is that if you work in a computer that has an sRGB display but you need to cover P3 colors, you’re going to have a hard time. Currently, almost at the end of 2017, most designers still work with sRGB displays. This is, they won’t be able to get the best out of their assets if they work with a bigger color space than what they can actually see on their screens.</p><p>Apple recommends to use the P3 color space only in specific situations, such as for UI components that can enhance the user experience by standing out through more intense colors, or for entire pictures that need to be <a href="https://webkit.org/blog-files/color-gamut/">more vivid</a>. This <a href="https://developer.apple.com/videos/play/wwdc2017/821/">WWDC session</a> has a great insight on when to use P3.</p><p>The transition hasn’t been done yet, and again, sRGB is still the standard today, so, that’s the choice you should go for in most of cases.</p><h3>TL;DR</h3><p>As you might have noticed, working with colors may look like a very straightforward thing, but it isn’t, at all.</p><p>Nevertheless, it’s just a matter of <strong>consistency</strong>. My suggestions to keep this process as simple as possible are:</p><ol><li>Let the UI designers know that you are going to work with the sRGB color space. Suggest them to use the sRGB color profile for mobile apps. Make sure the PSD files you use to crop images have sRGB as working space, and the PNG images you use in your assets catalog have the sRGB color profile embedded.</li><li>Use UIColor(red:green:blue:alpha:) for creating colors programmatically.</li><li>Make sure the sRGB option is selected in the Interface Builder’s color picker dropdown menu each time you set a color this way.</li><li>Work efficiently: Stick to one source of truth.</li></ol><h3>Bonus Track: The One Source of Truth</h3><p>I’ve been wondering for years how it was possible that there hadn’t been a way to refer to the same <em>thing</em> when getting a color from the code vs. from Interface Builder. How come I have to write these RGBA values <em>twice</em> for the same color? I mean, one time in my code, and another time in Interface Builder’s color picker. Not only this is an obvious pain in the neck, but it also leads to problems because of breaking the <a href="https://en.wikipedia.org/wiki/Don%27t_repeat_yourself">DRY principle</a>.</p><p><strong>Good news</strong>, as of Xcode 9, you can create a color specifying it only once, by using <a href="http://martiancraft.com/blog/2017/06/xcode9-assets/#color-assets">Color Assets</a>.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*8lNp0SqN2dqrX_RHy0R8tg.png" /><figcaption>You can get your custom color either from Interface Builder or from the code, referring in both cases to the same thing.</figcaption></figure><p>I got mind blown when I saw this tool for the first time, as not only it prevents you from writing things twice, but also organizes your app’s colors in such a way that is very convenient for everyone to use. Honestly, I shouldn’t have been that surprised, as this kind of utility should have existed from long, long time ago.</p><p><strong>Bad news</strong>, this tool is only compatible as of iOS 11. So, if your app has to support older iOS versions, you will need to write this kind of code:</p><pre>let lime: UIColor</pre><pre>if #available(iOS 11.0, *) {<br>    lime = UIColor(named: &quot;Lime&quot;)!<br>} else {<br>    lime = UIColor(red: 222/255.0, green: 254/255.0, blue: 50/255.0, alpha: 1.0)<br>}</pre><p>…</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/499/1*yZtxkohTIlLS73HgFMbs8g.png" /><figcaption>…That’s bad.</figcaption></figure><h3>Resources</h3><p>I hope I’ve just covered this topic well and I made it understandable using the right words. There is a lot more detail to dive in. I will be happy to see your comments and experiences!</p><p>Here is a list with some of the resources I’ve used during my research. They could be useful for you too:</p><ul><li><a href="https://www.youtube.com/watch?v=N2T62ZHIu6s">https://www.youtube.com/watch?v=N2T62ZHIu6s</a></li><li><a href="https://developer.apple.com/videos/play/wwdc2016/712/">https://developer.apple.com/videos/play/wwdc2016/712/</a></li><li><a href="https://developer.apple.com/videos/play/wwdc2017/821/">https://developer.apple.com/videos/play/wwdc2017/821/</a></li><li><a href="https://developer.apple.com/documentation/uikit/uicolor">https://developer.apple.com/documentation/uikit/uicolor</a></li><li><a href="https://developer.apple.com/ios/human-interface-guidelines/visual-design/color/">https://developer.apple.com/ios/human-interface-guidelines/visual-design/color/</a></li><li><a href="https://petapixel.com/2009/09/17/why-you-should-probably-use-srgb/">https://petapixel.com/2009/09/17/why-you-should-probably-use-srgb/</a></li><li><a href="http://appleinsider.com/articles/16/09/09/apples-wide-color-screen-on-the-iphone-7-will-lead-to-more-faithful-color-reproduction">http://appleinsider.com/articles/16/09/09/apples-wide-color-screen-on-the-iphone-7-will-lead-to-more-faithful-color-reproduction</a></li><li><a href="https://apple.stackexchange.com/questions/252159/what-color-space-is-iphones-7-wide-color-display-p3">https://apple.stackexchange.com/questions/252159/what-color-space-is-iphones-7-wide-color-display-p3</a></li><li><a href="http://martiancraft.com/blog/2017/06/xcode9-assets/#color-assets">http://martiancraft.com/blog/2017/06/xcode9-assets/#color-assets</a></li><li><a href="https://blog.zeplin.io/asset-catalog-colors-on-xcode-9-c4fdccc0381a">https://blog.zeplin.io/asset-catalog-colors-on-xcode-9-c4fdccc0381a</a></li><li><a href="https://webkit.org/blog-files/color-gamut/">https://webkit.org/blog-files/color-gamut/</a></li><li><a href="http://www.astramael.com/">http://www.astramael.com/</a></li><li><a href="https://en.wikipedia.org/wiki/SRGB">https://en.wikipedia.org/wiki/SRGB</a></li><li><a href="https://en.wikipedia.org/wiki/DCI-P3">https://en.wikipedia.org/wiki/DCI-P3</a></li><li><a href="https://en.wikipedia.org/wiki/HSL_and_HSV">https://en.wikipedia.org/wiki/HSL_and_HSV</a></li></ul><p>Happy coloring!</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=bc4c58b16f9a" width="1" height="1" alt="">]]></content:encoded>
        </item>
    </channel>
</rss>