<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
xmlns:content="http://purl.org/rss/1.0/modules/content/"
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:atom="http://www.w3.org/2005/Atom"
xmlns:sy="http://purl.org/rss/1.0/modules/syndication/">
	<channel>
		<title>Author at Infinum</title>
		<atom:link href="https://infinum.com/blog/author/goran-brlas/feed/" rel="self" type="application/rss+xml" />
		<link></link>
		<description>Building digital products</description>
		<lastBuildDate>Thu, 16 Apr 2026 15:26:52 +0000</lastBuildDate>
		<sy:updatePeriod>hourly</sy:updatePeriod>
		<sy:updateFrequency>1</sy:updateFrequency>

					<item>
				<image>
					<url>52435https://infinum.com/uploads/2024/04/img-DMA-hero-min-1.webp</url>
				</image>
				<title>Apple Meets EU’s Digital Markets Act – What You Need to Know</title>
				<link>https://infinum.com/blog/apple-digital-markets-act/</link>
				<pubDate>Tue, 02 Apr 2024 15:00:11 +0000</pubDate>
				<dc:creator>Goran Brlas</dc:creator>
				<guid isPermaLink="false">https://infinum.com/?p=52435</guid>
				<description>
					<![CDATA[<p>We present the most relevant changes Apple introduced to comply with EU's Digital Markets Act in a friendly FAQ.</p>
<p>The post <a href="https://infinum.com/blog/apple-digital-markets-act/">Apple Meets EU’s Digital Markets Act – What You Need to Know</a> appeared first on <a href="https://infinum.com">Infinum</a>.</p>
]]>
				</description>
				<content:encoded>
					<![CDATA[<div
	class="wrapper"
	data-id="es-265"
	 data-animation-target='inner-items'>
		
			<div class="wrapper__inner">
			<div class="block-blog-content js-block-blog-content">
	
<div class="block-blog-content-sidebar" data-id="es-92">
	</div>

<div class="block-blog-content-main">
	
<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-95"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-93">
	<p	class='typography typography--size-36-text js-typography block-typography__typography'
	data-id='es-94'
	>
	<strong>To comply with the Digital Markets Act, Apple introduced new rules that bring substantial changes for everyone who distributes apps in the EU market. We present the most relevant ones in a fully digestible FAQ. </strong></p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-98"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-96">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-97'
	>
	The release of iOS 17.4 was not just another system update for Apple. As you might have heard, it brought with it a whole assortment of <strong>changes for app developers and users</strong> in the European Union. </p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-101"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-99">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-100'
	>
	From the introduction of alternative app marketplaces to new payment models, the Cupertino tech giant was forced to reconstruct its rules and procedures to comply with the EU’s key piece of regulation for the digital economy – the <strong>Digital Markets Act</strong>. </p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-104"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-102">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-103'
	>
	Just like some of our software development projects, the changes are extensive both in scope and complexity. To save you the effort of going through the fine print, we’ve pulled out the ones we find to be most relevant and put together an FAQ that should solve some of your dilemmas.&nbsp;</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-107"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-105">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-106'
	>
	The <strong>obligatory disclaimer</strong> here is that this article is <strong>by no means comprehensive</strong>, that you should keep an eye out for any <strong>updates</strong>, and if in doubt, consult with your <strong>legal team</strong>.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-110"
	 data-animation='slideFade' data-animation-target='inner-items'>
				<div class="wrapper__anchor" id="dma"></div>
	
			<div class="block-typography" data-id="es-108">
	<h2	class='typography typography--size-52-default js-typography block-typography__typography'
	data-id='es-109'
	>
	What’s the deal with that Digital Markets Act?</h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-113"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-111">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-112'
	>
	In the past few years, Big Tech companies and EU regulators have been arguing over app stores, fair access, and the digital market in general. In 2022, the EU passed the <strong>Digital Markets Act</strong>, a regulation that aims to make the <strong>digital economy fairer and more open</strong>. </p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-116"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-114">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-115'
	>
	The DMA introduced obligations for so-called <strong>gatekeeper services</strong> that link businesses and consumers, and the iPhone operating system and its App Store have both been classified as such.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-119"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-117">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-118'
	>
	With the release of iOS 17.4 on 5 March, Apple implemented the required changes regarding <strong>alternative app marketplaces</strong>, <strong><a href="https://infinum.com/pci-dss-compliance-guide/" id="https://infinum.com/pci-dss-compliance-guide/">payment processing</a></strong>, and <strong>new payment models and services.</strong> Apple announced they will bring the changes to iPadOS later this fall, with no specific date provided yet. </p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-122"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-120">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-121'
	>
	However, accepting the changes is <strong>optional</strong>. Apple had to provide a choice, but app developers can decide whether to continue adhering to the old rules, or accept the new ones.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-125"
	 data-animation='slideFade' data-animation-target='inner-items'>
				<div class="wrapper__anchor" id="alternative-marketplaces"></div>
	
			<div class="block-typography" data-id="es-123">
	<h2	class='typography typography--size-52-default js-typography block-typography__typography'
	data-id='es-124'
	>
	What is the meaning of alternative marketplaces?</h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-128"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-126">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-127'
	>
	Until now, the only way a user could obtain an iOS or iPadOS app was through the App Store. The new rules introduce the possibility of <strong>alternative app marketplaces</strong> or <strong>direct app downloads</strong> through the developer’s website. </p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-131"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-129">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-130'
	>
	This means that developers have the option to <strong>create independent marketplaces</strong> for app distribution and that businesses can, but no longer have to offer their apps through the App Store. </p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-134"
	 data-animation='slideFade' data-animation-target='inner-items'>
				<div class="wrapper__anchor" id="in-app-payment-changes"></div>
	
			<div class="block-typography" data-id="es-132">
	<h2	class='typography typography--size-52-default js-typography block-typography__typography'
	data-id='es-133'
	>
	What about the changes to in-app payment processing? </h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-137"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-135">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-136'
	>
	Before these changes, the only way to perform in-app payments was to use Apple’s proprietary systems. Now, an app can <strong>integrate a third-party payment processor</strong> like Stripe or provide a link for completing a transaction outside the app. </p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-140"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-138">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-139'
	>
	It was the same with contactless payments. The only way to perform them on any piece of Apple hardware was Apple Pay. You could add your credit or debit card to Apple Wallet, provided that your bank or other card issuer had an agreement with Apple about this.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-143"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-141">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-142'
	>
	Now, contactless payments can be<strong> integrated into banking and fintech apps</strong>, and users have the option to use an <strong>alternative wallet app</strong> on their iPhones. </p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-146"
	 data-animation='slideFade' data-animation-target='inner-items'>
				<div class="wrapper__anchor" id="commission-and-fee-changes"></div>
	
			<div class="block-typography" data-id="es-144">
	<h2	class='typography typography--size-52-default js-typography block-typography__typography'
	data-id='es-145'
	>
	What is changing about Apple’s commissions and fees?</h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-149"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-147">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-148'
	>
	In the pre-DMA world, Apple would take a 30% cut (15% for the Small Business Program) for any financial transaction within an iOS app that involved the <strong>purchase of digital goods</strong>. This includes subscriptions, games and additional game content, courses, memberships, one-time media purchases, etc. </p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-152"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-150">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-151'
	>
	Game developers, and Epic Games in particular, have been very unhappy and very vocal about this, as evidenced by the famous <a href="https://en.wikipedia.org/wiki/Epic_Games_v._Apple" target="_blank" rel="noreferrer noopener">Epic vs. Apple battle</a>. </p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-155"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-153">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-154'
	>
	Apple now provides <strong>an additional payment model for its fees and commissions</strong>, so app developers can choose. The model is structured in a way that it practically discourages most developers from making that choice, but more detail on that is provided in the questions <a href="https://infinum.com/blog/apple-digital-markets-act/#commission-and-fee">What are the changes to Apple’s commission and fee model?</a>, <a href="https://infinum.com/blog/apple-digital-markets-act/#payment-models">How do I know which model to choose?</a>, and <a href="https://infinum.com/blog/apple-digital-markets-act/#malicious-compliance">What does malicious compliance mean?</a></p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-158"
	 data-animation='slideFade' data-animation-target='inner-items'>
				<div class="wrapper__anchor" id="applies-to-me"></div>
	
			<div class="block-typography" data-id="es-156">
	<h2	class='typography typography--size-52-default js-typography block-typography__typography'
	data-id='es-157'
	>
	How do I know if this applies to me?</h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-161"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-159">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-160'
	>
	The rules apply to all iOS apps <strong>available on the App Store and distributed in the EU</strong> and will likewise apply to iPadOS apps when Apple ships the announced update in the fall. It doesn’t matter where the company that owns the app is based. </p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-164"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-162">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-163'
	>
	If your company has more than one entity, you can choose to <strong>accept the rules or not</strong> at the account level – opt in for some developer accounts and opt out for others.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-167"
	 data-animation='slideFade' data-animation-target='inner-items'>
				<div class="wrapper__anchor" id="benefit-alternative-marketplaces"></div>
	
			<div class="block-typography" data-id="es-165">
	<h2	class='typography typography--size-52-default js-typography block-typography__typography'
	data-id='es-166'
	>
	How can I benefit from alternative marketplaces?</h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-170"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-168">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-169'
	>
	Developers can choose to provide their app for download via <strong>a marketplace other than the App Store</strong> or as a <strong>direct download</strong> from their website. </p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-173"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-171">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-172'
	>
	If an app is not distributed on the App Store, it means that it <strong>doesn’t have to comply with its rules and guidelines</strong>. This opens up possibilities for certain niches that aren’t allowed on the App Store, like gambling or adult content. However, each new marketplace will come with its own set of rules to consider.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-176"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-174">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-175'
	>
	For those who decide to <a href="https://developer.apple.com/help/app-store-connect/distributing-apps-in-the-european-union/manage-distribution-on-an-alternative-app-marketplace" target="_blank" rel="noreferrer noopener">distribute via an alternative marketplace</a>, Apple will still perform a <strong>notarization</strong> of their apps. It means that they will check whether the app meets some <strong>basic requirements</strong> regarding accuracy, functionality, safety, security, and privacy. </p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-179"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-177">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-178'
	>
	An important note here is that alternative app marketplaces will stop working 30 days after a user physically leaves the EU, and any apps installed through them will not be able to receive updates.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-182"
	 data-animation='slideFade' data-animation-target='inner-items'>
				<div class="wrapper__anchor" id="own-marketplace"></div>
	
			<div class="block-typography" data-id="es-180">
	<h2	class='typography typography--size-52-default js-typography block-typography__typography'
	data-id='es-181'
	>
	Can I build my own marketplace?</h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-185"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-183">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-184'
	>
	Yes, Apple provides the SDK for building a marketplace, but there is also quite <a href="https://developer.apple.com/support/alternative-app-marketplace-in-the-eu/" target="_blank" rel="noreferrer noopener">a rigorous list of requirements to meet</a>. </p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-188"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-186">
	<p	class='typography typography--size-20-text-roman js-typography block-typography__typography'
	data-id='es-187'
	>
	Marketplace developers need to pay Apple 0.50 euro for each marketplace app download, while developers who distribute apps via an alternative marketplace pay 0.50 euro for each download after the 1M mark. There are certain exceptions to the latter rule (explained in the question <a href="https://infinum.com/blog/apple-digital-markets-act/#exemption-core-technology-fee">Who is exempt from paying the Core Technology Fee?</a>), while more details about Apple’s payment systems can be found in the question <a href="https://infinum.com/blog/apple-digital-markets-act/#commission-and-fee">What are the changes to Apple’s commission and fee model</a>?</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-191"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-189">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-190'
	>
	While there are already some announcements for alternative marketplaces such as <a href="https://macpaw.com/news/setapp-ios-beta-announcement" target="_blank" rel="noreferrer noopener">this one from MacPaw</a>, we don’t expect to see them flooding the market. <strong>The business requirements for building a marketplace are very high</strong>, and will probably only be attainable by big players.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-194"
	 data-animation='slideFade' data-animation-target='inner-items'>
				<div class="wrapper__anchor" id="developer-website"></div>
	
			<div class="block-typography" data-id="es-192">
	<h2	class='typography typography--size-52-default js-typography block-typography__typography'
	data-id='es-193'
	>
	How does app distribution through a developer’s website work?</h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-197"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-195">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-196'
	>
	Developers will be able to distribute their iOS and iPadOS apps <strong>directly from a website</strong>, and according to current announcements, this feature will be available “later this spring.”</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-200"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-198">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-199'
	>
	Using a website for app distribution also requires adhering to <strong>Apple’s strict rules</strong> and meeting <strong>specific criteria</strong>. For example, the developer will have to be “a member of good standing” in the Apple Developer Program for at least two years and have an app that had <strong>more than a million</strong> first annual installs on iOS in the EU in the prior calendar year. </p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-203"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-201">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-202'
	>
	The <strong>Core Technology Fee</strong> (explained in the question What are the changes to Apple’s commission and fee model?) and <strong>notarization requirements</strong> still apply, and apps can only be installed from a website domain registered with Apple. </p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-206"
	 data-animation='slideFade' data-animation-target='inner-items'>
				<div class="wrapper__anchor" id="alternative-payment-providers"></div>
	
			<div class="block-typography" data-id="es-204">
	<h2	class='typography typography--size-52-default js-typography block-typography__typography'
	data-id='es-205'
	>
	What does using alternative payment providers and linking out for payment mean?</h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-209"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-207">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-208'
	>
	In addition to Apple’s In-App Purchase system, you can now use <a href="https://developer.apple.com/support/apps-using-alternative-payment-providers-in-the-eu/" target="_blank" rel="noreferrer noopener">new methods for managing in-app payments</a> involving digital goods and services. These are: </p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-212"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="lists" data-id="es-210">
	<ul	class='typography typography--size-16-text-roman js-typography lists__typography'
	data-id='es-211'
	>
	<li><strong>Payment Service Provider (PSP)</strong> – an alternative payment processor that lets users complete transactions within the app</li><li><strong>Linking out for payment</strong> – you can direct your users to complete a transaction on a webpage. The link presentation can include information about promotions, discounts, and other deals.</li></ul></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-215"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-213">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-214'
	>
	To benefit from these options, you need to <strong>accept the new rules</strong>. What exactly this entails is explained in more detail in questions <a href="https://infinum.com/blog/apple-digital-markets-act/#payment-models">How do I know which payment model to choose?</a> and <a href="https://infinum.com/blog/apple-digital-markets-act/#opt-out">Can I opt out?</a></p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-218"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-216">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-217'
	>
	You can still choose to keep using <a href="https://developer.apple.com/in-app-purchase/" target="_blank" rel="noreferrer noopener">Apple’s In-App purchase system</a>. However, there’s <strong>no mix &amp; match here</strong>. If you go with Apple, you can’t offer alternative PSPs and/or link out for payment <strong>on the same storefront</strong>, which is basically one country’s App Store.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-221"
	 data-animation='slideFade' data-animation-target='inner-items'>
				<div class="wrapper__anchor" id="commission-and-fee"></div>
	
			<div class="block-typography" data-id="es-219">
	<h2	class='typography typography--size-52-default js-typography block-typography__typography'
	data-id='es-220'
	>
	What are the changes to Apple’s commission and fee model?</h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-224"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-222">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-223'
	>
	The new rules introduce <strong>a new model for paying Apple’s fees and commissions</strong> for financial transactions connected to the purchase of digital goods. Digital goods include subscriptions to digital content, games and additional game content, courses, memberships, one-time media purchases and the like. </p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-227"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-225">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-226'
	>
	To be perfectly clear, <strong>this applies to those who sell such goods through apps</strong>. You still don’t have to pay a commission if you don’t charge your users for downloading or using the app. It also doesn’t apply to physical goods. If you have an e-commerce app, you don’t pay a commission to Apple for each transaction. </p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-230"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-228">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-229'
	>
	The existing rules impose a 30% (15% in the Small Businesses Program) fee per transaction. Under the new rules, that commission is <strong>reduced to 17% (10% for small businesses)</strong>, with an <strong>additional 3%</strong> if using <a href="https://developer.apple.com/in-app-purchase/" target="_blank" rel="noreferrer noopener">Apple’s In-App Purchase system</a>. However, there’s a caveat. If you accept the new rules, you also pay the newly introduced <a href="https://developer.apple.com/support/core-technology-fee/" target="_blank" rel="noreferrer noopener">Core Technology Fee</a>, which is <strong>0.50 euro</strong> for each first install after one million in a year.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-233"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-231">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-232'
	>
	When iPadOS starts to support these changes, the Core Technology Fee will also apply to iPad apps downloaded through the App Store, web distribution, and/or alternative marketplaces. However, if a user installs <strong>the same app on their iPhone and iPad</strong> within a 12-month period, it will count as one <strong>first annual installation</strong> of that app. </p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-236"
	 data-animation='slideFade' data-animation-target='inner-items'>
				<div class="wrapper__anchor" id="exemption-core-technology-fee"></div>
	
			<div class="block-typography" data-id="es-234">
	<h2	class='typography typography--size-52-default js-typography block-typography__typography'
	data-id='es-235'
	>
	Who is exempt from paying the Core Technology Fee?</h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-239"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-237">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-238'
	>
	Developers whose apps have less than one million annual installs per year, nonprofits, educational institutions, and government entities with an Apple Developer Program fee waiver do not pay the Core Technology Fee.&nbsp;</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-242"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-240">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-241'
	>
	The exemption also applies to developers who run <strong>no-revenue businesses</strong> and offer <strong>free apps without monetization</strong>. These apps can not be related to revenue of any kind: physical, digital, advertising, or otherwise. It’s important to emphasize that in order to be eligible for the exemption, the business itself must earn no revenue whatsoever, not just in relation to the app. </p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-245"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-243">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-244'
	>
	Further, developers with a global annual business revenue <strong>lesser than €10M</strong> who adopt the new rules receive <strong>a three-year free on-ramp</strong> to the Core Technology Fee. If they cross the one million install threshold during that period, they are not required to pay the fee. </p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-248"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-246">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-247'
	>
	However, if a developer grows to earn global revenue between €10M and €50M within the three-year on-ramp period, they will start paying the Core Technology Fee after one million first annual installs with a cap of one million euro per year.&nbsp;</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-251"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-249">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-250'
	>
	Developers whose revenue crosses €50M will pay the full fee.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-254"
	 data-animation='slideFade' data-animation-target='inner-items'>
				<div class="wrapper__anchor" id="payment-models"></div>
	
			<div class="block-typography" data-id="es-252">
	<h2	class='typography typography--size-52-default js-typography block-typography__typography'
	data-id='es-253'
	>
	How do I know which payment model to choose?</h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-257"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-255">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-256'
	>
	It’s simple. You do the math. Thankfully, <a href="https://developer.apple.com/support/fee-calculator-for-apps-in-the-eu/" target="_blank" rel="noreferrer noopener">Apple provided a convenient calculator</a> to help you in this process. </p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-260"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-258">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-259'
	>
	Generally speaking, if the sale of digital goods <strong>doesn’t</strong> account for much of your revenue like it does for Spotify or Netflix for example, you won’t save much by choosing this model. On the contrary, you’d probably end up paying <strong>far more than you do now</strong>. </p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-263"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-261">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-262'
	>
	To illustrate, here are some projections for the amounts paid to Apple on account of in-app transactions and and app downloads.</p></div>	</div>
</div>
</div>		</div>
	</div>

<div
	class="wrapper"
	data-id="es-268"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="wrapper__inner">
			<div class="block-media">
	<div	class="media block-media__media media__border--none media__align--center-center"
	data-id="es-266"
	 data-media-type='image'>

	<figure class="image block-media__image-figure image--size-stretch" data-id="es-267">
	<picture class="image__picture block-media__image-picture">
								
			<source
				srcset=https://infinum.com/uploads/2024/04/graf_1-1400x535.webp				media='(max-width: 699px)'
				type=image/webp								height="535"
												width="1400"
				 />
												<img
					src="https://infinum.com/uploads/2024/04/graf_1.webp"
					class="image__img block-media__image-img"
					alt=""
										height="696"
															width="1823"
										loading="lazy"
					 />
					</picture>

			<figcaption class="image__figcaption block-media__image-figcaption">
			APPS SELLING DIGITAL GOODS AND SERVICES		</figcaption>
	</figure></div></div>		</div>
	</div>

<div
	class="wrapper"
	data-id="es-271"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="wrapper__inner">
			<div class="block-media">
	<div	class="media block-media__media media__border--none media__align--center-center"
	data-id="es-269"
	 data-media-type='image'>

	<figure class="image block-media__image-figure image--size-stretch" data-id="es-270">
	<picture class="image__picture block-media__image-picture">
								
			<source
				srcset=https://infinum.com/uploads/2024/04/graf_2-1400x471.webp				media='(max-width: 699px)'
				type=image/webp								height="471"
												width="1400"
				 />
												<img
					src="https://infinum.com/uploads/2024/04/graf_2.webp"
					class="image__img block-media__image-img"
					alt=""
										height="650"
															width="1934"
										loading="lazy"
					 />
					</picture>

			<figcaption class="image__figcaption block-media__image-figcaption">
			APPS NOT SELLING DIGITAL GOODS AND SERVICES		</figcaption>
	</figure></div></div>		</div>
	</div>

<div
	class="wrapper"
	data-id="es-318"
	 data-animation-target='inner-items'>
		
			<div class="wrapper__inner">
			<div class="block-blog-content js-block-blog-content">
	
<div class="block-blog-content-sidebar" data-id="es-272">
	

</div>

<div class="block-blog-content-main">
	
<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-275"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-273">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-274'
	>
	As we can see, if you don’t serve a very large user base and/or offer many in-app purchases, it’s safe to assume you’ll be <strong>better off with the existing rules</strong>. If you go with the new rules and lower fees, remember that you also likely need to pay the <a href="https://developer.apple.com/support/core-technology-fee/" target="_blank" rel="noreferrer noopener">Core Technology Fee</a>. To see how all of this impacts your individual case, it’s best to <strong>use the calculator</strong> and find out exactly how much each option would cost you. </p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-277"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-highlighted-text">
	<p	class='typography typography--size-36-text js-typography block-highlighted-text__typography'
	data-id='es-276'
	>
	<strong>It’s important to bear in mind that the rules are a package deal. If you want to benefit from alternative marketplaces or linking out to payment, you also accept the new fees.</strong></p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-280"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-278">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-279'
	>
	However, <em>some</em> of the changes Apple introduced to comply with the DMA are applied universally and have nothing to do with whether you accept the new rules or not. This includes <strong>contactless payments</strong> and <strong>wallet apps</strong>. App distributors in the EU are simply <strong>free to use these options</strong> from now on.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-283"
	 data-animation-target='inner-items'>
		
			<div class="block-group" data-id=es-282>
	
<div
	class="wrapper"
	data-id="es-281"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="wrapper__inner">
			
<figure class="wp-block-table"><table><tbody><tr><td></td><td><strong>Existing rules</strong></td><td><strong>New rules</strong></td></tr><tr><td>Digital sales commission</td><td>30% (15% in the Small Business Program)</td><td>17% (10% in the Small Business Program)<br><br>+&nbsp;<br><br>3% if IAP used<br></td></tr><tr><td><a href="https://developer.apple.com/support/core-technology-fee/" target="_blank" rel="noreferrer noopener">Core Technology Fee</a></td><td>€0</td><td>€0.50 for each app installation after a million in a year (updates count as well)*</td></tr><tr><td><a href="https://developer.apple.com/in-app-purchase/" target="_blank" rel="noreferrer noopener">In-App purchase</a> required</td><td>yes</td><td>no</td></tr><tr><td><a href="https://developer.apple.com/support/apps-using-alternative-payment-providers-in-the-eu/" target="_blank" rel="noreferrer noopener">Alternative payment processors and/or linking out for payment</a> allowed</td><td>no</td><td>yes</td></tr><tr><td><a href="https://developer.apple.com/help/app-store-connect/distributing-apps-in-the-european-union/manage-distribution-on-an-alternative-app-marketplace" target="_blank" rel="noreferrer noopener">Distribution on alternative markets</a></td><td>no</td><td>yes</td></tr><tr><td><a href="https://developer.apple.com/support/hce-payment-transactions-in-payment-apps/" target="_blank" rel="noreferrer noopener">Contactless payment transactions and wallet apps in EEA</a></td><td>yes</td><td>yes</td></tr></tbody></table><figcaption class="wp-element-caption">* <em>For exemptions, see question <a href="https://infinum.com/blog/apple-digital-markets-act/#exemption-core-technology-fee">Who is exempt from paying the Core Technology Fee?</a></em></figcaption></figure>
		</div>
	</div>
</div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-286"
	 data-animation='slideFade' data-animation-target='inner-items'>
				<div class="wrapper__anchor" id="contactless-payments"></div>
	
			<div class="block-typography" data-id="es-284">
	<h2	class='typography typography--size-52-default js-typography block-typography__typography'
	data-id='es-285'
	>
	What about those contactless payments?</h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-289"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-287">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-288'
	>
	iOS 17.4 introduced new APIs that support <a href="https://developer.apple.com/support/hce-payment-transactions-in-payment-apps/" target="_blank" rel="noreferrer noopener">contactless payment transactions</a> within banking and wallet apps using host card emulation (HCE). </p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-292"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-290">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-291'
	>
	In practice, this means that you can <strong>add contactless payment options</strong> from a provider other than Apple to your (usually <strong>banking and fintech</strong>) apps. Users in the European Economic Area (EEA) will be able to access the payment option the same way they access Apple Pay, by <strong>pressing the side button</strong> on their iPhone twice. </p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-295"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-293">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-294'
	>
	Developers of banking or wallet apps who want to make use of this feature will also have to comply with <a href="https://developer.apple.com/support/hce-payment-transactions-in-payment-apps/" target="_blank" rel="noreferrer noopener">Apple’s requirements</a>.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-298"
	 data-animation='slideFade' data-animation-target='inner-items'>
				<div class="wrapper__anchor" id="other-changes"></div>
	
			<div class="block-typography" data-id="es-296">
	<h2	class='typography typography--size-52-default js-typography block-typography__typography'
	data-id='es-297'
	>
	What are some other interesting changes?</h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-301"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-299">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-300'
	>
	An interesting user-facing change is the possibility of using alternative browser engines. While browsers like Google Chrome were available on iOS, they still had to use Safari’s underlying engine <a href="https://webkit.org/" target="_blank" rel="noreferrer noopener">WebKit</a>. Basically, the Chrome you used on your iPhone was 95% Safari, only Google-branded. </p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-304"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-302">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-303'
	>
	iPhone and iPad users will be able to use the real Chrome, Firefox, Edge, Opera, or whatever browser they choose, and Safari will <strong>no longer be the default browser</strong> <em>by default</em>, but will have to ask for that permission.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-307"
	 data-animation='slideFade' data-animation-target='inner-items'>
				<div class="wrapper__anchor" id="malicious-compliance"></div>
	
			<div class="block-typography" data-id="es-305">
	<h2	class='typography typography--size-52-default js-typography block-typography__typography'
	data-id='es-306'
	>
	What does malicious compliance mean?</h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-310"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-308">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-309'
	>
	You might have heard this term mentioned in connection with Apple and the DMA, or you might have gone through some of the questions in this FAQ and thought to yourself, “Wait, <strong>how is this better than before</strong>?”</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-313"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-311">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-312'
	>
	This is what <strong>malicious compliance</strong> means. The DMA forced Apple to provide <em><strong>options</strong></em>. Apple complied, but they also made sure to make these options <strong>so unappealing</strong> that few businesses would decide to take advantage of them. The <a href="https://developer.apple.com/support/core-technology-fee/" target="_blank" rel="noreferrer noopener">Core Technology Fee</a> is a perfect example of this. </p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-316"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-314">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-315'
	>
	And here is another one. When an app integrates an alternative payment processing service, this is the screen the user is met with before proceeding to payment:&nbsp;</p></div>	</div>
</div>
</div>		</div>
	</div>

<div
	class="wrapper"
	data-id="es-321"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="wrapper__inner">
			<div class="block-media">
	<div	class="media block-media__media media__border--none media__align--center-center"
	data-id="es-319"
	 data-media-type='image'>

	<figure class="image block-media__image-figure image--size-stretch" data-id="es-320">
	<picture class="image__picture block-media__image-picture">
												<img
					src="https://infinum.com/uploads/2024/04/screen-private-large_2x.webp"
					class="image__img block-media__image-img"
					alt=""
										height="1075"
															width="496"
										loading="lazy"
					 />
					</picture>

			<figcaption class="image__figcaption block-media__image-figcaption">
			NOT INTIMIDATING AT ALL, RIGHT?		</figcaption>
	</figure></div></div>		</div>
	</div>

<div
	class="wrapper"
	data-id="es-374"
	 data-animation-target='inner-items'>
		
			<div class="wrapper__inner">
			<div class="block-blog-content js-block-blog-content">
	
<div class="block-blog-content-sidebar" data-id="es-322">
	

</div>

<div class="block-blog-content-main">
	
<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-325"
	 data-animation='slideFade' data-animation-target='inner-items'>
				<div class="wrapper__anchor" id="opt-out"></div>
	
			<div class="block-typography" data-id="es-323">
	<h2	class='typography typography--size-52-default js-typography block-typography__typography'
	data-id='es-324'
	>
	Can I opt out?</h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-328"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-326">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-327'
	>
	Yes, you can. Accepting the new rules is entirely <strong>optional</strong>. In fact, if you do nothing, the old rules still apply to you by default. </p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-331"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-329">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-330'
	>
	Some of the changes Apple introduced <strong>apply universally</strong>, and app developers in the EU can benefit from them whether they <strong>accept the new rules or not</strong>. This includes <strong>contactless payments</strong> via alternative providers and using <strong>different browser engines</strong>, for example. </p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-334"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-332">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-333'
	>
	However, when considering whether to accept Apple’s new rules, you need to be aware that some of them are a <strong>package deal</strong>. If you want to benefit from linking out to payment, you’ll also have to accept the new fee system. To see what goes with what, check out the table in the question How do I know which payment model to choose?</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-337"
	 data-animation='slideFade' data-animation-target='inner-items'>
				<div class="wrapper__anchor" id="change-my-mind"></div>
	
			<div class="block-typography" data-id="es-335">
	<h2	class='typography typography--size-52-default js-typography block-typography__typography'
	data-id='es-336'
	>
	Can I change my mind about accepting the new rules?</h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-340"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-338">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-339'
	>
	There is a very complicated answer to this seemingly simple question, and this is it: <strong>you can, once, and it depends.</strong>&nbsp;</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-343"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-341">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-342'
	>
	You have a <strong>one-time option</strong> to <strong>change your mind</strong>. If you’ve accepted the new rules but would like to return to the old ones, you can do so provided<strong> </strong>you never created an alternative marketplace, distributed an app through an alternative marketplace, used alternative payment processing, or linking out for payment with that account. </p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-346"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-344">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-345'
	>
	In short, this is an “<strong>emergency exit</strong>” option for those who have adopted the new rules to <strong>pay a lower fee</strong> but have decided to keep going through Apple for everything else. </p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-349"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-347">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-348'
	>
	Oh, and don’t worry:&nbsp;</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-351"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-highlighted-text">
	<p	class='typography typography--size-20-text js-typography block-highlighted-text__typography'
	data-id='es-350'
	>
	<em>Any remaining payments due to the Core Technology Fee are still applicable even after termination.</em></p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-354"
	 data-animation='slideFade' data-animation-target='inner-items'>
				<div class="wrapper__anchor" id="what-now"></div>
	
			<div class="block-typography" data-id="es-352">
	<h2	class='typography typography--size-52-default js-typography block-typography__typography'
	data-id='es-353'
	>
	OK, so what do I do now?</h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-357"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-355">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-356'
	>
	We suggest you take it all in, consider your options, consider the limitations, and decide. If you have done <strong>nothing</strong> so far, the <strong>old rules</strong> still apply to you.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-360"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-358">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-359'
	>
	If this is a lot to digest, you can always consult with those who’ve worked with apps and app markets literally <strong>since they’ve existed</strong>. If you’re considering <strong>building a new app for the EU market </strong>or <strong>updating an existing one</strong>, we’ll consider your specific case and advise you on the best course of action, as we’ve done for all our clients. </p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-363"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-361">
	<h2	class='typography typography--size-52-default js-typography block-typography__typography'
	data-id='es-362'
	>
	No more questions, unless you have questions</h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-366"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-364">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-365'
	>
	As Apple was forced to at least slightly <strong>lower the fence to its walled garden</strong> in the EU, we hope we managed to shed some light on this extremely complex, not at all appealing, and still highly important matter.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-369"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-367">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-368'
	>
	This FAQ covers a selection of topics we found to be most relevant for app providers in the EU, but it is by no means comprehensive. If you want to explore any of the topics in detail, we encourage you to check <a href="https://developer.apple.com/support/dma-and-apps-in-the-eu/">Apple&#8217;s guidelines </a>directly and use them as your <strong>primary reference</strong>.  </p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-372"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-370">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-371'
	>
	We’ll make sure to <strong>update</strong> this article if there are any <strong>significant changes</strong>, and if you feel that there’s an area we didn’t cover, feel free to let us know on our social media channels.</p></div>	</div>
</div>
</div>		</div>
	</div><p>The post <a href="https://infinum.com/blog/apple-digital-markets-act/">Apple Meets EU’s Digital Markets Act – What You Need to Know</a> appeared first on <a href="https://infinum.com">Infinum</a>.</p>
]]>
				</content:encoded>
			</item>
					<item>
				<image>
					<url>34067https://infinum.com/uploads/2023/02/MasterConnect_IoT_blogpost.webp</url>
				</image>
				<title>Building Philips MasterConnect on BLE and Zigbee Protocols</title>
				<link>https://infinum.com/blog/philips-masterconnect-innovation-iot/</link>
				<pubDate>Tue, 14 Feb 2023 14:02:43 +0000</pubDate>
				<dc:creator>Goran Brlas</dc:creator>
				<guid isPermaLink="false">https://infinum.com/?p=34067</guid>
				<description>
					<![CDATA[<p>How we managed complex hardware-software interactions in an enterprise-level IoT lighting system Philips MasterConnect using BLE and Zigbee.</p>
<p>The post <a href="https://infinum.com/blog/philips-masterconnect-innovation-iot/">Building Philips MasterConnect on BLE and Zigbee Protocols</a> appeared first on <a href="https://infinum.com">Infinum</a>.</p>
]]>
				</description>
				<content:encoded>
					<![CDATA[<div
	class="wrapper"
	data-id="es-457"
	 data-animation-target='inner-items'>
		
			<div class="wrapper__inner">
			<div class="block-blog-content js-block-blog-content">
	
<div class="block-blog-content-sidebar" data-id="es-375">
	</div>

<div class="block-blog-content-main">
	
<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-378"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-376">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-377'
	>
	During our years-long cooperation with <a href="https://www.signify.com/global" target="_blank" rel="noreferrer noopener">Signify</a> on the <a href="https://www.lighting.philips.co.uk/oem-emea/products/connected-lighting/masterconnect" target="_blank" rel="noreferrer noopener">Philips MasterConnect system</a>, we’ve built multiple mobile applications that bring this industry-leading <a href="https://infinum.com/custom-iot-solutions/">smart lighting system</a> to life.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-380"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-highlighted-text">
	<p	class='typography typography--size-24-text js-typography block-highlighted-text__typography'
	data-id='es-379'
	>
	<a href="https://infinum.com/work/philips-masterconnect-iot-lighting/" target="_blank" rel="noreferrer noopener"><strong>The Philips MasterConnect app</strong></a><strong> is the core tool for setting up and configuring smart lighting networks in commercial buildings. The app is straightforward and easy to use, but at the same time, it manages very complex hardware-software interactions.</strong></p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-383"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-381">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-382'
	>
	The whole system, consisting of smart wireless switches, sensors, and luminaires from Signify’s MasterConnect line, is built on Bluetooth Low Energy (BLE) and Zigbee protocols. Since it utilizes technologies that come with phones we use every day, there’s no need to use any additional devices during installation, as was the case with older connected lighting systems.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-386"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-384">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-385'
	>
	While <a href="https://infinum.com/work/philips-masterconnect-iot-lighting/" target="_blank" rel="noreferrer noopener">our case study</a> of this project provides an overview of the system features, this blog post will give you a view of how things work under the hood. We will focus on how BLE and Zigbee enabled us to build this product and cover some of the app’s high-end features in more detail.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-393"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<a	class="card-simple js-card-simple card-simple--is-ad block-card__card-simple card-simple--has-link js-card-simple-link card-simple__content-align--left"
	data-id="es-387"
	 target='_blank' rel='noopener noreferrer' href='https://infinum.com/iot-implementation/'>

	
	
	<div class="card-simple__content">
		<div class="card-simple__heading-wrap">
			<h2	class='typography typography--size-24-text js-typography card-simple__heading'
	data-id='es-388'
	>
	From strategy to deployment, we cover all aspects of IoT development lifecycle. <strong>Download our Guide to Successful IoT Implementation</strong>.</h2>		</div>

		<button	class="btn btn--color-infinum btn--size-small btn--width-default btn__icon-position--right card-simple__btn js-block-card-btn js-card-simple-link"
	data-id="es-390"
	 tabindex='-1'>
		<div class="btn__inner">
					<div	class='typography typography--size-none js-typography btn__label'
	data-id='es-391'
	>
	Learn more</div>		
		<i
	class="icon btn__icon icon--size-16 icon--scale-100"
	 aria-hidden='true' data-name='arrow-right-16' data-id='es-392'>
	<svg fill='none' height='16' viewBox='0 0 17 16' width='17' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink'><g stroke='currentColor' stroke-width='2'><path d='m.5 7.99999 14 .00001'/><path d='m9.23352 2.7251 5.97848 5.97852'/><path d='m9.23352 13.2744 5.97848-5.9785'/></g></svg></i>	</div>
	</button>	</div>
</a>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-396"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-394">
	<h2	class='typography typography--size-52-default js-typography block-heading__heading'
	data-id='es-395'
	>
	Bluetooth Low Energy &amp; Zigbee making magic</h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-399"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-397">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-398'
	>
	The two wireless communication protocols that make the magic in the MasterConnect system happen are <a href="https://www.bluetooth.com/learn-about-bluetooth/tech-overview/" target="_blank" rel="noreferrer noopener">Bluetooth Low Energy (BLE)</a> and <a href="https://en.wikipedia.org/wiki/Zigbee" target="_blank" rel="noreferrer noopener">Zigbee</a>. The backbone of Internet of Things, they have been revolutionizing the way we interact with our devices for the past few years.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-402"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-400">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-401'
	>
	As its name suggests, BLE is a wireless communication technology created to be low-power and efficient. It is a version of the popular Bluetooth technology specifically designed for IoT devices. While Bluetooth Classic only supports point-to-point communication, BLE provides additional communication options such as broadcasting and meshing, enabling connectivity between devices in a network that supports this type of communication.&nbsp;</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-405"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-403">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-404'
	>
	Similar to BLE, Zigbee is a wireless communication protocol specifically designed for low-power, low-data-rate applications. Zigbee efficiently transmits messages that are small in size, while its design allows devices to run on batteries for years, making this technology a great choice for systems that need to be installed in hard-to-reach locations or need to operate without frequent maintenance.&nbsp;</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-408"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-406">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-407'
	>
	Both protocols have something in common – the ability to efficiently configure devices into large-scale networks that require zero maintenance. Since our system is fully scalable and adapts to buildings of various sizes, this was exactly what we needed to ensure network reliability in any scenario.&nbsp;</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-411"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-409">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-410'
	>
	It might seem surprising that we’ve chosen two protocols so similar in nature. However, to support different types of communication taking place in the system, we needed both. Our smartphones have been supporting BLE pretty much since its release as part of the Bluetooth 4.0 standard, but they don’t support Zigbee, whose mesh networking is perfect for light connectivity.&nbsp;</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-413"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-highlighted-text">
	<p	class='typography typography--size-24-text js-typography block-highlighted-text__typography'
	data-id='es-412'
	>
	<strong>The lighting industry paved the way to Zigbee standardization, with Signify as one of the key advocates. The MasterConnect system was one of the first ones to launch with the newly standardized protocol. </strong></p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-416"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-414">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-415'
	>
	To work around this limitation for mobile, we modeled the system so that our apps communicate with devices using BLE, and then the devices communicate between themselves using Zigbee. That’s the high-level overview, but let’s roll up our sleeves and get a bit lower.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-419"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-417">
	<h2	class='typography typography--size-52-default js-typography block-heading__heading'
	data-id='es-418'
	>
	Achieving seamless hardware-software interaction</h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-422"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-420">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-421'
	>
	When setting up a lighting system, installers first need to physically install all of the devices in their respective places in a building. Once that’s done, they use the Philips MasterConnect app to configure the system.<br />
<br />
The app guides the installers through each phase of the setup – from creating projects and groups to discovering and commissioning lights, sensors, or switches into those projects. </p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-425"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-423">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-424'
	>
	Let’s go over some of those steps in a bit more detail.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-428"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-426">
	<h2	class='typography typography--size-36-text js-typography block-heading__heading'
	data-id='es-427'
	>
	Device discovery</h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-431"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-429">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-430'
	>
	All BLE devices need to follow something called the <a href="https://www.bluetooth.com/bluetooth-resources/intro-to-bluetooth-generic-access-profile-gap/" target="_blank" rel="noreferrer noopener">Generic Access Profile (GAP) guidelines</a>, which dictate how they need to advertise data to other devices. This could be a blog post on its own (like our article on <a href="https://infinum.com/blog/bluetooth-beacons/" target="_blank" rel="noreferrer noopener">Bluetooth Beacons</a>), but in short, the devices advertise information about them with a certain frequency. We could say that they yell something along the lines of “Hey, I’m here, my name is X. I am a light and I support Y features”. This allows us to filter out the devices that are a part of our system and present only them to the installers.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-434"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-432">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-433'
	>
	To make things even easier for the installers, we implemented an innovative solution to solve the problem of identifying specific devices in a room where there are hundreds of them. We decided to use torches (not the fire kind, the ones that produce light). Installers just need to point an everyday pocket torch at a light, and the onboard sensor will pick up the spike in the detected brightness. This will cause the device advertisement to change in a way that enables us to identify it and automatically start communicating with it.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-437"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-435">
	<h2	class='typography typography--size-36-text js-typography block-heading__heading'
	data-id='es-436'
	>
	Communicating with devices</h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-440"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-438">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-439'
	>
	Once we have discovered all the lights we need, we have to connect to each of them before we can make them a part of our network. We do this by following the <a href="https://learn.adafruit.com/introduction-to-bluetooth-low-energy/gatt" target="_blank" rel="noreferrer noopener">Generic ATTribute Profile (GATT) guidelines</a>, which specify how a device can support various features using services and characteristics.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-443"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="bullet bullet--left bullet__type--dot bullet__color--infinum block-bullet__bullet" data-id="es-441">
			<div class="bullet__dot"></div>
		<div class="bullet__content">
		<p	class='typography typography--size-20-text-roman js-typography bullet__paragraph'
	data-id='es-442'
	>
	<strong>Services</strong> are used to break up data into logical entities and contain specific chunks of data called characteristics. A service can have one or more characteristics, and each service distinguishes itself from other services with a unique numeric ID called a UUID.</p>	</div>
</div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-446"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="bullet bullet--left bullet__type--dot bullet__color--infinum block-bullet__bullet" data-id="es-444">
			<div class="bullet__dot"></div>
		<div class="bullet__content">
		<p	class='typography typography--size-20-text-roman js-typography bullet__paragraph'
	data-id='es-445'
	>
	<strong>Characteristics</strong> are the lowest-level concept in GATT transactions, and they encapsulate a single data point that can be either read from or written to.</p>	</div>
</div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-449"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-447">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-448'
	>
	In short, if you want to get some specific information from a device, you need to read the data from a characteristic that holds it. Alternatively, if you want to write some data to a device in order to tell it to do something, you need to write to a characteristic that is connected to that behavior.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-452"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-450">
	<h2	class='typography typography--size-36-text js-typography block-heading__heading'
	data-id='es-451'
	>
	Creating and configuring a network</h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-455"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-453">
	<p	class='typography typography--size-20-text-roman js-typography block-paragraph__paragraph'
	data-id='es-454'
	>
	Now that we know how to discover a device and how to communicate with it, we need to bring Zigbee into the picture. Zigbee enables us to arrange devices into groups, which allows us to use group addressing to communicate with multiple devices at the same time.&nbsp;</p></div>	</div>
</div>
</div>		</div>
	</div>

<div
	class="wrapper"
	data-id="es-460"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="wrapper__inner">
			<div class="block-media">
	<div	class="media block-media__media media__border--none media__align--center-center"
	data-id="es-458"
	 data-media-type='image'>

	<figure class="image block-media__image-figure image--size-stretch" data-id="es-459">
	<picture class="image__picture block-media__image-picture">
								
			<source
				srcset=https://infinum.com/uploads/2023/02/MasterConnect_IoT_inarticle_image_1-1400x818.webp				media='(max-width: 699px)'
				type=image/webp								height="818"
												width="1400"
				 />
								
			<source
				srcset=https://infinum.com/uploads/2023/02/MasterConnect_IoT_inarticle_image_1-2400x1401.webp				media='(max-width: 1199px)'
				type=image/webp								height="1401"
												width="2400"
				 />
												<img
					src="https://infinum.com/uploads/2023/02/MasterConnect_IoT_inarticle_image_1.webp"
					class="image__img block-media__image-img"
					alt=""
										height="1600"
															width="2740"
										loading="lazy"
					 />
					</picture>

			<figcaption class="image__figcaption block-media__image-figcaption">
			by organizing devices into groups, it&#8217;s easy to apply settings to a whole area		</figcaption>
	</figure></div></div>		</div>
	</div>

<div
	class="wrapper"
	data-id="es-546"
	 data-animation-target='inner-items'>
		
			<div class="wrapper__inner">
			<div class="block-blog-content js-block-blog-content">
	
<div class="block-blog-content-sidebar" data-id="es-461">
	</div>

<div class="block-blog-content-main">
	
<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-464"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-462">
	<p	class='typography typography--size-20-text-roman js-typography block-paragraph__paragraph'
	data-id='es-463'
	>
	Since our phones don’t support Zigbee, we can’t send Zigbee messages directly to devices. That would be too easy. We’ve found a workaround by creating a Zigbee message on the app side that tells the device which group it will be a part of, and then send that message to the device over BLE. After receiving the message, the device firmware processes it and executes the appropriate actions.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-467"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-465">
	<p	class='typography typography--size-20-text-roman js-typography block-paragraph__paragraph'
	data-id='es-466'
	>
	After that, configuring devices is rather straightforward. First, the installer uses the intuitive app UI to configure how the devices should behave in the desired setup. The array of options is quite extensive here – from changing the brightness and color temperature to configuring occupancy sensing and matching the lighting with the human circadian rhythm. All the various properties are then converted into appropriate Zigbee messages that we send to a device using BLE.&nbsp;</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-470"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-468">
	<p	class='typography typography--size-20-text-roman js-typography block-paragraph__paragraph'
	data-id='es-469'
	>
	Once a device receives those messages, it configures itself and relays the messages throughout the device network using Zigbee. This eliminates the need to be close to all the devices and provides significant time savings in large-scale setups.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-473"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-471">
	<h2	class='typography typography--size-36-text js-typography block-heading__heading'
	data-id='es-472'
	>
	The setup is complete, now off to the cloud</h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-476"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-474">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-475'
	>
	Once a system is configured, installers can back up all the necessary project data in the cloud, making it easy to share access between multiple installers. System maintenance can then also be transferred to the building manager or a person in a similar role, thus removing the need to hire installers for small maintenance work or system monitoring, e.g., reading the energy consumption report. </p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-479"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-477">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-478'
	>
	An additional benefit of backing up data in the cloud is that it can always serve as a safety net. In case something happens to the phone that configured the system, or there’s a need to revert to earlier settings, it’s easy to restore the original configuration.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-482"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-480">
	<h2	class='typography typography--size-52-default js-typography block-heading__heading'
	data-id='es-481'
	>
	Secure communication via Bluetooth</h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-485"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-483">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-484'
	>
	Philips MasterConnect systems are installed in public buildings, which means that security was a top priority for us.&nbsp;</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-488"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-486">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-487'
	>
	Whenever two devices communicate over BLE, they usually exchange bytes of data that both of them know how to process. Let’s use a simple example of turning a light on. </p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-491"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-489">
	<p	class='typography typography--size-20-text-roman js-typography block-paragraph__paragraph'
	data-id='es-490'
	>
	To achieve this, the app needs to:</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-494"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="bullet bullet--left bullet__type--dot bullet__color--infinum block-bullet__bullet" data-id="es-492">
			<div class="bullet__dot"></div>
		<div class="bullet__content">
		<p	class='typography typography--size-20-text-roman js-typography bullet__paragraph'
	data-id='es-493'
	>
	establish a connection to the light,</p>	</div>
</div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-497"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="bullet bullet--left bullet__type--dot bullet__color--infinum block-bullet__bullet" data-id="es-495">
			<div class="bullet__dot"></div>
		<div class="bullet__content">
		<p	class='typography typography--size-20-text-roman js-typography bullet__paragraph'
	data-id='es-496'
	>
	create a message containing the command bytes,</p>	</div>
</div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-500"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="bullet bullet--left bullet__type--dot bullet__color--infinum block-bullet__bullet" data-id="es-498">
			<div class="bullet__dot"></div>
		<div class="bullet__content">
		<p	class='typography typography--size-20-text-roman js-typography bullet__paragraph'
	data-id='es-499'
	>
	write those bytes to the appropriate characteristic (explained above).</p>	</div>
</div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-503"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-501">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-502'
	>
	The light needs to:</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-506"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="bullet bullet--left bullet__type--dot bullet__color--infinum block-bullet__bullet" data-id="es-504">
			<div class="bullet__dot"></div>
		<div class="bullet__content">
		<p	class='typography typography--size-20-text-roman js-typography bullet__paragraph'
	data-id='es-505'
	>
	receive the message,</p>	</div>
</div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-509"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="bullet bullet--left bullet__type--dot bullet__color--infinum block-bullet__bullet" data-id="es-507">
			<div class="bullet__dot"></div>
		<div class="bullet__content">
		<p	class='typography typography--size-20-text-roman js-typography bullet__paragraph'
	data-id='es-508'
	>
	establish a connection to the light, convert it into something its firmware can process,</p>	</div>
</div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-512"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="bullet bullet--left bullet__type--dot bullet__color--infinum block-bullet__bullet" data-id="es-510">
			<div class="bullet__dot"></div>
		<div class="bullet__content">
		<p	class='typography typography--size-20-text-roman js-typography bullet__paragraph'
	data-id='es-511'
	>
	tell the hardware to turn on.</p>	</div>
</div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-515"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-513">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-514'
	>
	If you look at the list of steps, you might see a potential problem here that applies to any kind of unsecured traffic – it can be sniffed and captured by various third-party tools like <a href="https://www.wireshark.org/" target="_blank" rel="noreferrer noopener">Wireshark</a> and used maliciously. We needed to find a way to shield the data we were sending between devices. </p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-518"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-516">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-517'
	>
	We came up with something similar to how <a href="https://en.wikipedia.org/wiki/Transport_Layer_Security" target="_blank" rel="noreferrer noopener">Transport Layer Security (TLS)</a> works with HTTPS traffic but applied to BLE &#8211; TLS over the BLE layer, one might call it. </p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-521"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-519">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-520'
	>
	To increase security, we added an additional part to the process of establishing connections between the app and the lights – <a href="https://en.wikipedia.org/wiki/Authenticated_Key_Exchange" target="_blank" rel="noreferrer noopener">Authenticated Key Exchange (AKE)</a>. It is a method used to establish secure communication between two parties that ensures only authorized parties can exchange keys and share messages.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-524"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-522">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-523'
	>
	AKE typically involves the use of a &#8220;shared secret&#8221; that is known only to the two parties involved in the communication. This shared secret is used to create a unique key that is then used to encrypt all following communication. The key is exchanged between the parties securely, ensuring that it is not intercepted or tampered with during the exchange.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-527"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-525">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-526'
	>
	After this authentication is done, the messages between the app and the devices are encrypted and, if needed, fragmented as well, to ensure they can be properly exchanged.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-530"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-528">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-529'
	>
	Doing this was no small feat, but making sure our systems can’t be tampered with makes it all worth it.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-533"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-531">
	<h2	class='typography typography--size-36-text js-typography block-heading__heading'
	data-id='es-532'
	>
	Daylight-utilizing and human-centric</h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-536"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-534">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-535'
	>
	Having covered the technical know-how, let’s move on to some elegant features. The system consists of more than just luminaires; we also have sensors and switches that integrate seamlessly. In case someone wants to push their setup to a higher level, there is also an option to add gateway support. </p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-538"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-highlighted-text">
	<p	class='typography typography--size-24-text js-typography block-highlighted-text__typography'
	data-id='es-537'
	>
	<strong>These functionalities enable us to increase the scope of features we bring to the market and make buildings more efficient – from cutting down the time and effort required to service the network and maximizing energy savings to creating a comfortable and adjustable environment for the people using the setups.</strong></p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-541"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-539">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-540'
	>
	I’d like to highlight two of those features: daylight-utilizing and human-centric lighting. They work hand-in-hand to increase the occupants’ well-being.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-544"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-542">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-543'
	>
	Daylight-utilizing works in combination with sensors that detect the level of daylight in the room and adjust the lighting accordingly, reducing unnecessary costs. Growing up, we all probably had our parents telling us to turn off the lights because nobody needs them and we are just wasting electricity (and we probably stubbornly argued otherwise). Having LED luminaires that can be configured to emit less light, saving power and creating a pleasant mood using natural light, would have helped in such situations.</p></div>	</div>
</div>
</div>		</div>
	</div>

<div
	class="wrapper"
	data-id="es-549"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="wrapper__inner">
			<div class="block-media">
	<div	class="media block-media__media media__border--none media__align--center-center"
	data-id="es-547"
	 data-media-type='image'>

	<figure class="image block-media__image-figure image--size-stretch" data-id="es-548">
	<picture class="image__picture block-media__image-picture">
								
			<source
				srcset=https://infinum.com/uploads/2023/02/MasterConnect_IoT_inarticle_image_2-1400x818.webp				media='(max-width: 699px)'
				type=image/webp								height="818"
												width="1400"
				 />
								
			<source
				srcset=https://infinum.com/uploads/2023/02/MasterConnect_IoT_inarticle_image_2-2400x1401.webp				media='(max-width: 1199px)'
				type=image/webp								height="1401"
												width="2400"
				 />
												<img
					src="https://infinum.com/uploads/2023/02/MasterConnect_IoT_inarticle_image_2.webp"
					class="image__img block-media__image-img"
					alt=""
										height="1600"
															width="2740"
										loading="lazy"
					 />
					</picture>

			<figcaption class="image__figcaption block-media__image-figcaption">
			Occupancy sensors allow for maximum energy efficiency		</figcaption>
	</figure></div></div>		</div>
	</div>

<div
	class="wrapper"
	data-id="es-576"
	 data-animation-target='inner-items'>
		
			<div class="wrapper__inner">
			<div class="block-blog-content js-block-blog-content">
	
<div class="block-blog-content-sidebar" data-id="es-550">
	</div>

<div class="block-blog-content-main">
	
<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-553"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-551">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-552'
	>
	Human-centric lighting directly correlates with our human circadian rhythm. Think of it as an internal biological clock that regulates our sleep-wake cycle and other physiological processes to match the external environment, ensuring that we are alert during the day and sleepy at night. You might have guessed it, light is a key factor in regulating that behavior.&nbsp;</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-556"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-554">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-555'
	>
	To help improve occupants’ well-being, tunable white luminaires from the Philips MasterConnect line can be configured to match the human circadian rhythm – they will emit blue light during the morning and change to warmer, less intense colors as the day passes.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-559"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-557">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-558'
	>
	Pretty cool, right?</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-562"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-560">
	<h2	class='typography typography--size-52-default js-typography block-heading__heading'
	data-id='es-561'
	>
	The future is looking bright</h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-565"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-563">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-564'
	>
	If you thought that we would do a blog post on lighting systems without a single pun about light, you probably didn’t read that many of our blog posts.&nbsp;&nbsp;</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-568"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-566">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-567'
	>
	We’ve shed some light on the inner workings of the Philips MasterConnect system – from the protocols used, hardware-software interaction, and security, all the way to benefits for people occupying the buildings and using the lights.&nbsp;</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-571"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-569">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-570'
	>
	Philips MasterConnect is not a standard <a href="https://infinum.com/custom-iot-solutions/">IoT system</a>. It is the result of years of innovation on all sides – hardware, firmware, cloud, and mobile. And we’re just getting started. The future is looking bright.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-574"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-572">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-573'
	>
	<em>To find out what else we can do in the Internet of Things realm, check out our <a href="https://infinum.com/custom-iot-solutions/" target="_blank" rel="noreferrer noopener">IoT solutions page</a>.</em></p></div>	</div>
</div>
</div>		</div>
	</div><p>The post <a href="https://infinum.com/blog/philips-masterconnect-innovation-iot/">Building Philips MasterConnect on BLE and Zigbee Protocols</a> appeared first on <a href="https://infinum.com">Infinum</a>.</p>
]]>
				</content:encoded>
			</item>
					<item>
				<image>
					<url>8082https://infinum.com/uploads/2020/09/swiftUI-2-0.webp</url>
				</image>
				<title>SwiftUI 2.0: The Future is Declarative</title>
				<link>https://infinum.com/blog/swiftui-2/</link>
				<pubDate>Thu, 10 Sep 2020 12:25:00 +0000</pubDate>
				<dc:creator>Goran Brlas</dc:creator>
				<guid isPermaLink="false">https://infinum.com/the-capsized-eight/swiftui-2/</guid>
				<description>
					<![CDATA[<p>Has SwiftUI overcome its initial shortcomings and brought significant improvements in the version 2.0?</p>
<p>The post <a href="https://infinum.com/blog/swiftui-2/">SwiftUI 2.0: The Future is Declarative</a> appeared first on <a href="https://infinum.com">Infinum</a>.</p>
]]>
				</description>
				<content:encoded>
					<![CDATA[<div
	class="wrapper"
	data-id="es-761"
	 data-animation-target='inner-items'>
		
			<div class="wrapper__inner">
			<div class="block-blog-content js-block-blog-content">
	
<div class="block-blog-content-sidebar" data-id="es-577">
	</div>

<div class="block-blog-content-main">
	
<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-580"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-578">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-579'
	>
	Since its introduction last year, SwiftUI has piqued the interest of most Apple ecosystem developers with its “learn once, apply everywhere” approach. After playing around with it for a bit, we wrote an <a href="https://infinum.com/blog/swiftui-is-here-to-knock-uikit-out-of-its-shoes/">overview of SwiftUI itself</a>, as well as looked into how <a href="https://infinum.com/blog/combine-makes-swiftui-shine/">Combine fits in the picture</a>.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-583"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-581">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-582'
	>
	It looked promising and made UI programming really fun. However, its <strong>initial shortcomings and imposed minimal OS support version prevented it from ever fully taking off</strong>.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-586"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-584">
	<h2	class='typography typography--size-52-default js-typography block-heading__heading'
	data-id='es-585'
	>
	A more mature SwiftUI</h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-589"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-587">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-588'
	>
	Improvements that came during this year’s WWDC, along with the maturation of the toolkit itself, mean more and more teams are going to slowly make a switch to a new way of building cross-platform user interface layers that work across iOS, iPadOS, macOS, tvOS, and even watchOS, using one set of tools and APIs.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-594"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="blockquote block-blockquote__blockquote" data-id="es-590">
	
	<div class="blockquote__content">
		<i
	class="icon blockquote__icon icon--size-16 icon--scale-100"
	 aria-hidden='true' data-name='blockquote-24' data-id='es-591'>
	<svg fill='none' height='24' viewBox='0 0 24 24' width='24' xmlns='http://www.w3.org/2000/svg'><path clip-rule='evenodd' d='m12 24c6.6274 0 12-5.3726 12-12 0-2.79685-.9568-5.37021-2.561-7.41062-.581.22951-1.0832.60583-1.5069 1.12898-.5132.60844-.7698 1.41969-.7698 2.43375v.07605h2.5789v5.59004h-5.6197v-5.01962c0-1.11547.154-2.06616.4619-2.85205.3336-.81125.757-1.48307 1.2702-2.01545.528-.52161 1.1175-.92155 1.7687-1.1998-2.0728-1.70651-4.7279-2.73128-7.6223-2.73128-6.62742 0-12 5.37258-12 12 0 6.6274 5.37258 12 12 12zm-3.53811-18.05347c-.30793.78589-.46189 1.73658-.46189 2.85205v5.01962h5.6197v-5.59004h-2.5789v-.07605c0-1.01406.2566-1.82531.7698-2.43375.5389-.63379 1.1804-1.05209 1.9245-1.2549v-2.28164c-.7441.07605-1.4626.25351-2.1555.53238-.6928.27887-1.3086.68449-1.84752 1.21688-.51321.53238-.9366 1.2042-1.27019 2.01545z' fill='currentColor' fill-rule='evenodd'/></svg></i><p	class='typography typography--size-36-text js-typography blockquote__quote'
	data-id='es-592'
	>
	The shift to a more declarative programming paradigm is coming, and we need to be ready for it.</p>
		<div class="blockquote__caption-wrap">
					</div>
	</div>
</div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-597"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-595">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-596'
	>
	I’ve talked about this very same topic at the recent Shift Remote E05: MOBILE event, and if you’d like, you can check out the recording of that talk <a href="https://www.youtube.com/watch?v=VuLELGztayY&amp;feature=youtu.be&amp;t=8665">here</a>.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-600"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-598">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-599'
	>
	<strong>Now, let’s see what SwiftUI promised, what it delivered, and where it’s going in the future</strong>. Grab a coffee, settle in and let’s begin.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-603"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-601">
	<h2	class='typography typography--size-52-default js-typography block-heading__heading'
	data-id='es-602'
	>
	Humble beginnings, not quite</h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-606"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-604">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-605'
	>
	When Apple first announced SwiftUI, they backed it up with some big claims regarding the changes it was going to bring to the development world of the Apple platform. Here are some of them.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-609"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-607">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-608'
	>
	They said that we would need to write <strong>less code</strong>.<br>Stuff like creating a <em>tableView</em> or a <em>collectionView</em> that before took a lot of boring, boilerplate code would become things of the past.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-612"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-610">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-611'
	>
	After that came <strong>adaptability</strong>, in all its forms:</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-615"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="lists" data-id="es-613">
	<ul	class='typography typography--size-16-text-roman js-typography lists__typography'
	data-id='es-614'
	>
	<li><strong>platform</strong> – our apps would behave as first class citizens on all Apple platforms, from our Macs all the way down to our iPhones and Apple watches. The code we write would adapt to take full use of their respective capabilities, e.g. elements like pickers would show up as scrolling wheels on iOS, but on macOS they would take the dropdown shape.</li><li><strong>light &amp; dark mode</strong> – by using features introduced in iOS 13 such as system colors, we could easily adapt our applications to light &amp; dark mode. I’ve actually written a <a href="https://infinum.com/blog/how-to-prepare-your-app-for-dark-mode-in-iOS-13/">handy how-to guide on adopting dark mode</a>. SwiftUI helps us here with the <em>@Environment</em> property wrapper which we could use to get the current environment value, as well as any updates to it.</li><li><strong>font scaling</strong> – fonts used by SwiftUI adapt to the scale that your users pick in the phone settings, and SwiftUI views like <em>Text</em> would in turn adjust their size to fit everything nicely.</li></ul></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-618"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-616">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-617'
	>
	Next things next. After adaptability improvements came something that would upgrade our development process, as well as increase the speed of our output – the ability to <strong>preview</strong> our UI at the same time as actually writing the code for it.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-621"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-619">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-620'
	>
	Technologies like Flutter or React Native had had this option for a while, and last year we were finally given a native alternative to the <em>build-install-run</em> dance that used to bite out a solid chunk of developers’ daily programming time. By using preview, the written code would automatically and immediately be seen in it, as well as all made changes. There was also an option to run a <strong>live preview</strong>, allowing for test user interaction or navigation testing, similarly to running the app in the Simulator/on a real device.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-624"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-622">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-623'
	>
	Code &amp; preview combination also meant that we now had a <strong>single point of truth</strong> for our UI; checking out storyboard/xib files and/or code to find out who has overwritten whom and caused our UI bugs was gone, going, gone. </p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-627"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-625">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-626'
	>
	Btw, if you&#8217;d like to know more about those hardships, we&#8217;ve got you covered with our article on the long-term <a href="https://infinum.com/blog/storyboard-code-ui-building-ios/">UI-building dilemma of choosing between storyboards and code</a>. </p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-630"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-628">
	<h2	class='typography typography--size-52-default js-typography block-heading__heading'
	data-id='es-629'
	>
	Finally, a native declarative way of writing apps for Apple platforms</h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-633"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-631">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-632'
	>
	Finally, we got a <strong>native, declarative way</strong> of writing our applications for Apple platforms. Imperative approach stood the battle of time, but with general advancements in UI development, as well as the increase in app complexity our users expect, we needed something fresh which allowed for faster iterations, as well as easier state management.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-636"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-634">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-635'
	>
	All those things were supposed to make SwiftUI great – Apple wrapped them up in a shiny wrapper and told us <em>“Here you go, play around with it.”</em>. Naturally, presented with something new and unfamiliar, we did just that, and it didn’t take long before articles were touting this as the end of Objective-C, UIKit/AppKit and the be-all and end-all way to go.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-639"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-637">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-638'
	>
	However, with the honeymoon period over and our rose-tinted glasses off, we started seeing there was still a lot of room for improvement. Preview was not always working and used to crash consistently. New Xcode/Swift versions would break the existing SwiftUI code. Navigation would sometimes break, too. Tab management was not preserving the navigation stack. UI elements that we were used to in the UIKit world were missing their SwiftUI counterparts.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-642"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-640">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-641'
	>
	Creating simple UIs was fast and fun, but doing anything remotely complex or adjusting some existing elements like <em>Lists</em> usually meant dipping back into UIKit/AppKit, which kinda defeated the whole declarative purpose.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-645"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-643">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-644'
	>
	Last but not least, SwiftUI requires iOS 13 as the minimum OS version. For large scale applications, that meant leaving a significant part of their user-base behind, and that wasn’t really an option. However, it got us thinking about state management, and the way its declarative nature goes around solving issues that popped up.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-648"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-646">
	<h2	class='typography typography--size-52-default js-typography block-heading__heading'
	data-id='es-647'
	>
	State management (is hard)</h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-651"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-649">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-650'
	>
	State management is hard.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-654"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-media">
	<div	class="media block-media__media media__border--none media__align--center-center"
	data-id="es-652"
	 data-media-type='image'>

	<figure class="image block-media__image-figure image--size-stretch" data-id="es-653">
	<picture class="image__picture block-media__image-picture">
												<img
					src="https://infinum.com/uploads/2020/09/swiftUI-2-1.webp"
					class="image__img block-media__image-img"
					alt=""
										height="567"
															width="282"
										loading="lazy"
					 />
					</picture>

			<figcaption class="image__figcaption block-media__image-figcaption">
			Apple mail in action		</figcaption>
	</figure></div></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-657"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-655">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-656'
	>
	Let’s take the screen above from the Apple’s Mail app as an example. There’s a list of data, driven by some data models (in this case emails), as well as some extra navigation options, filters and actions.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-660"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-658">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-659'
	>
	To create a screen like this, we need to connect our views with our models, and each one of these arrows seen in the image below represents a dependency.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-663"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-media">
	<div	class="media block-media__media media__border--none media__align--center-center"
	data-id="es-661"
	 data-media-type='image'>

	<figure class="image block-media__image-figure image--size-stretch" data-id="es-662">
	<picture class="image__picture block-media__image-picture">
								
			<source
				srcset=https://infinum.com/uploads/2020/09/swiftUI-2-2-1400x840.webp				media='(max-width: 699px)'
				type=image/webp								height="840"
												width="1400"
				 />
												<img
					src="https://infinum.com/uploads/2020/09/swiftUI-2-2.webp"
					class="image__img block-media__image-img"
					alt=""
										height="960"
															width="1600"
										loading="lazy"
					 />
					</picture>

			<figcaption class="image__figcaption block-media__image-figcaption">
			Dependencies of a single screen		</figcaption>
	</figure></div></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-666"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-664">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-665'
	>
	As you can see, there are a lot of interconnected elements here since UI actions can update our models, and in turn they can update our UI. If you think this is complicated, bear in mind that this is just a single screen, and today our applications have a lot of screens which can share the same models, which makes the whole picture even more convoluted.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-669"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-media">
	<div	class="media block-media__media media__border--none media__align--center-center"
	data-id="es-667"
	 data-media-type='image'>

	<figure class="image block-media__image-figure image--size-stretch" data-id="es-668">
	<picture class="image__picture block-media__image-picture">
								
			<source
				srcset=https://infinum.com/uploads/2020/09/swiftUI-2-3-1400x840.webp				media='(max-width: 699px)'
				type=image/webp								height="840"
												width="1400"
				 />
												<img
					src="https://infinum.com/uploads/2020/09/swiftUI-2-3.webp"
					class="image__img block-media__image-img"
					alt=""
										height="960"
															width="1600"
										loading="lazy"
					 />
					</picture>

			<figcaption class="image__figcaption block-media__image-figcaption">
			Dependencies between multiple screens		</figcaption>
	</figure></div></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-672"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-670">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-671'
	>
	This brings me back to the starting point of this section – state management is hard, and state management in large-scale applications that we usually build for our clients is getting harder each year. Supporting multiple device sizes, light &amp; dark modes, accessibility features, complex device features such as AR or Bluetooth, having a multiplayer mode and so much more – it all makes building apps in 2020 more challenging than ever. We work in bigger development teams, where each contributor comes with a different skill set that needs to be aligned in order to make a cohesive app.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-675"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-673">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-674'
	>
	Sure, it can be easy to put a custom button on a screen, but how does it respond to accessibility? Does it adjust properly to different device sizes and orientations? Does it break if the customer changes their font scale? Is the state that button updates properly propagated to all the screens that require it? Now do that for not just a single button, but for all the UI elements you have on a screen. Not so easy now, is it?</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-678"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-676">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-677'
	>
	As iOS developers, our job is to build applications that empower our users and adapt to their needs and potential disabilities. If we don’t, it can lead to a disappointing experience for our customers and can make the end product appear cheap and untrustworthy.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-683"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="blockquote block-blockquote__blockquote" data-id="es-679">
	
	<div class="blockquote__content">
		<i
	class="icon blockquote__icon icon--size-16 icon--scale-100"
	 aria-hidden='true' data-name='blockquote-24' data-id='es-680'>
	<svg fill='none' height='24' viewBox='0 0 24 24' width='24' xmlns='http://www.w3.org/2000/svg'><path clip-rule='evenodd' d='m12 24c6.6274 0 12-5.3726 12-12 0-2.79685-.9568-5.37021-2.561-7.41062-.581.22951-1.0832.60583-1.5069 1.12898-.5132.60844-.7698 1.41969-.7698 2.43375v.07605h2.5789v5.59004h-5.6197v-5.01962c0-1.11547.154-2.06616.4619-2.85205.3336-.81125.757-1.48307 1.2702-2.01545.528-.52161 1.1175-.92155 1.7687-1.1998-2.0728-1.70651-4.7279-2.73128-7.6223-2.73128-6.62742 0-12 5.37258-12 12 0 6.6274 5.37258 12 12 12zm-3.53811-18.05347c-.30793.78589-.46189 1.73658-.46189 2.85205v5.01962h5.6197v-5.59004h-2.5789v-.07605c0-1.01406.2566-1.82531.7698-2.43375.5389-.63379 1.1804-1.05209 1.9245-1.2549v-2.28164c-.7441.07605-1.4626.25351-2.1555.53238-.6928.27887-1.3086.68449-1.84752 1.21688-.51321.53238-.9366 1.2042-1.27019 2.01545z' fill='currentColor' fill-rule='evenodd'/></svg></i><p	class='typography typography--size-36-text js-typography blockquote__quote'
	data-id='es-681'
	>
	Remember, UI is all the end customer sees. If it sucks, they think the product sucks, no matter how good your backend &amp; foundational engineering work is.</p>
		<div class="blockquote__caption-wrap">
					</div>
	</div>
</div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-686"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-684">
	<h3	class='typography typography--size-36-text js-typography block-heading__heading'
	data-id='es-685'
	>
	The declarative solution</h3></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-689"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-687">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-688'
	>
	With SwiftUI, we don’t need to worry about how our app is going to transition between all those different states. The age-old problem probably every single engineer has stumbled upon of <em>animating updates to this set of content based on a diff</em> – gone. We <em>just</em> need to write the code to describe how each state should look and the system figures out the rest. Like magic.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-692"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-media">
	<div	class="media block-media__media media__border--none media__align--center-center"
	data-id="es-690"
	 data-media-type='image'>

	<figure class="image block-media__image-figure image--size-stretch" data-id="es-691">
	<picture class="image__picture block-media__image-picture">
								
			<source
				srcset=https://infinum.com/uploads/2020/09/swiftUI-2-4-1400x840.webp				media='(max-width: 699px)'
				type=image/webp								height="840"
												width="1400"
				 />
												<img
					src="https://infinum.com/uploads/2020/09/swiftUI-2-4.webp"
					class="image__img block-media__image-img"
					alt=""
										height="960"
															width="1600"
										loading="lazy"
					 />
					</picture>

			<figcaption class="image__figcaption block-media__image-figcaption">
			SwiftUI&#8217;s declarative approach to state management		</figcaption>
	</figure></div></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-695"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-693">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-694'
	>
	SwiftUI offers a declarative approach to user interface design. As you compose a hierarchy of views, you also indicate data dependencies for the views. When the data changes, either due to an external event like a notification or because of an action taken by the user, SwiftUI automatically updates the affected parts of the interface. As a result, the framework performs most of the work traditionally done by view controllers.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-698"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-696">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-697'
	>
	This unidirectional <strong><em>Action -&gt; State -&gt; View</em></strong> approach means that we no longer need to worry about keeping our UI and our data models in sync. Our state is the only one responsible for updating our <em>Views</em>, and <em>Actions</em> are in turn the only ones responsible of updating our <em>State</em>. Since our <em>Views</em> can’t update the <em>State</em> directly, the problem is automatically solved for us.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-701"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-699">
	<h2	class='typography typography--size-52-default js-typography block-heading__heading'
	data-id='es-700'
	>
	Paving the way forward</h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-704"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-702">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-703'
	>
	Having gone over how SwiftUI started and the problems it aimed to solve, we should now cover the novelties announced at this year’s WWDC and see where SwiftUI is heading in the future.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-707"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-705">
	<h3	class='typography typography--size-36-text js-typography block-heading__heading'
	data-id='es-706'
	>
	New UI elements and options</h3></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-710"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-708">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-709'
	>
	SwiftUI’s coverage of commonly used views has been greatly expanded this year, which is fantastic news both for developers who already have existing apps built with SwiftUI, and for people who are now getting started with the framework for the very first time.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-713"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-711">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-712'
	>
	What most of us were looking forward to is the inclusion of alternative UI elements we were used to, and I think it’s fair to say that we weren’t disappointed with what we got:</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-716"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="lists" data-id="es-714">
	<ul	class='typography typography--size-16-text-roman js-typography lists__typography'
	data-id='es-715'
	>
	<li><strong>TextEditor</strong> – offers a built-in way to add a larger text editing area to a UI, which is what makes it different from the TextField type that SwiftUI has been shipping with since its introduction. Wrapping UIKit’s UITextView is no longer needed, at least when looking to add a more basic set of text editing functionality to our applications</li><li><strong>ProgressView</strong> – platform-adaptable way of showing an appropriate default loading spinner, as well as an alternative version that can be used to show progress (e.g. for downloading some data)</li><li><strong>document-based apps support</strong> – we’ve been given two main types to work with: the <em>FileDocument</em> protocol to define what a document in our app looks like, and the <em>DocumentGroup</em> struct that gives us a default scene to let users create, open, and save documents.</li><li><strong>LazyHGrid &amp; LazyVGrid</strong> – collectionView alternative was something that was glaringly missing in the initial SwiftUI release, and these grids are what can be used to create similar layouts to what we were used to. They are container views that arrange their child views in a grid that grows horizontally and vertically respectively, creating items only as needed.</li></ul></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-719"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-717">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-718'
	>
	The concept of laziness is a big trend when it comes to this year’s SwiftUI changes, which is only solidified with the addition of <em>LazyHStack</em> and <em>LazyVStack</em> to their non-lazy counterparts. In general, implementations that are lazy don’t perform their work up-front, but rather at the time when it’s first needed. This can often lead to a ton of performance improvements, especially when dealing with larger collections and other heavy data.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-722"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-720">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-721'
	>
	There are also a host of other new things which could be a whole blog post for themselves like <strong>matchedGeometryEffect, ScrollViewReader, ColorPicker, DisclosureGroup</strong> etc. Stay tuned to Capsized Eight, I guess?</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-725"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-723">
	<h3	class='typography typography--size-36-text js-typography block-heading__heading'
	data-id='es-724'
	>
	New property wrappers</h3></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-728"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-726">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-727'
	>
	Adding to the existing host of property wrappers, we got some new ones which will make our lives a bit easier:</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-731"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="lists" data-id="es-729">
	<ul	class='typography typography--size-16-text-roman js-typography lists__typography'
	data-id='es-730'
	>
	<li><strong>@AppStorage</strong> – helps us read and write UserDefaults easily</li><li><strong>@ScaledMetric</strong> – scales values based on Dynamic Type settings</li><li><strong>@StateObject</strong> – safely creates reference types in views</li><li>and even more, such as <strong>@UIApplicationDelegateAdaptor, @Namespace, @SceneStorage</strong> etc.</li></ul></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-734"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-732">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-733'
	>
	On iOS 13, we had to use a UIHostingController (or NSHostingController on the Mac) to actually render out SwiftUI views, but now, our root view hierarchy can simply be embedded in a type conforming to the new <strong>App</strong> protocol, and by annotating that type with Swift’s new <strong>@main</strong> attribute, it’ll act as the entry point for our app – without the need for any app delegate or any other bootstrapping code:</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-736"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-code">
	<pre class="phiki language-swift github-light" data-language="swift" style="background-color: #fff;color: #24292e;"><code><span class="line"><span class="token" style="color: #d73a49;">@main</span><span class="token">
</span></span><span class="line"><span class="token">struct BlogPostApp</span><span class="token">:</span><span class="token"> </span><span class="token" style="color: #6f42c1;">App </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token">var body:</span><span class="token"> </span><span class="token" style="color: #d73a49;">some</span><span class="token"> Scene </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">        </span><span class="token">WindowGroup</span><span class="token"> </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">            </span><span class="token">ContentView(</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">        </span><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token">struct ContentView</span><span class="token">:</span><span class="token"> </span><span class="token" style="color: #6f42c1;">View </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token">var body:</span><span class="token"> </span><span class="token" style="color: #d73a49;">some</span><span class="token"> View </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">        </span><span class="token">Text(</span><span class="token" style="color: #032f62;">&quot;</span><span class="token" style="color: #032f62;">Hello, SwiftUI 2.0!</span><span class="token" style="color: #032f62;">&quot;</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">            .</span><span class="token">multilineTextAlignment(</span><span class="token">.</span><span class="token">center</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">            .</span><span class="token">padding(</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span></code></pre></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-739"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-737">
	<h2	class='typography typography--size-52-default js-typography block-heading__heading'
	data-id='es-738'
	>
	Not just an alternative</h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-742"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-740">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-741'
	>
	All of this brings me to my final point:</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-747"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="blockquote block-blockquote__blockquote" data-id="es-743">
	
	<div class="blockquote__content">
		<i
	class="icon blockquote__icon icon--size-16 icon--scale-100"
	 aria-hidden='true' data-name='blockquote-24' data-id='es-744'>
	<svg fill='none' height='24' viewBox='0 0 24 24' width='24' xmlns='http://www.w3.org/2000/svg'><path clip-rule='evenodd' d='m12 24c6.6274 0 12-5.3726 12-12 0-2.79685-.9568-5.37021-2.561-7.41062-.581.22951-1.0832.60583-1.5069 1.12898-.5132.60844-.7698 1.41969-.7698 2.43375v.07605h2.5789v5.59004h-5.6197v-5.01962c0-1.11547.154-2.06616.4619-2.85205.3336-.81125.757-1.48307 1.2702-2.01545.528-.52161 1.1175-.92155 1.7687-1.1998-2.0728-1.70651-4.7279-2.73128-7.6223-2.73128-6.62742 0-12 5.37258-12 12 0 6.6274 5.37258 12 12 12zm-3.53811-18.05347c-.30793.78589-.46189 1.73658-.46189 2.85205v5.01962h5.6197v-5.59004h-2.5789v-.07605c0-1.01406.2566-1.82531.7698-2.43375.5389-.63379 1.1804-1.05209 1.9245-1.2549v-2.28164c-.7441.07605-1.4626.25351-2.1555.53238-.6928.27887-1.3086.68449-1.84752 1.21688-.51321.53238-.9366 1.2042-1.27019 2.01545z' fill='currentColor' fill-rule='evenodd'/></svg></i><p	class='typography typography--size-36-text js-typography blockquote__quote'
	data-id='es-745'
	>
	SwiftUI is not just an alternative; it is the future.</p>
		<div class="blockquote__caption-wrap">
					</div>
	</div>
</div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-750"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-748">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-749'
	>
	Apple has already started pushing in the spotlight by making it the only way to create widgets for the newest OS versions. MacOS has also started using it prominently in some of its redesigned features, like the new notification center.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-753"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-751">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-752'
	>
	The new unified design language Apple is pushing forward, combined with the fact that Apple Silicon Macs will be able to run iOS/iPadOS applications as well, means that having a single UI framework that can be used to develop for all platforms makes perfect sense.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-756"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-754">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-755'
	>
	Barely over a year old, SwiftUI is just getting started. Armed with all the new announcements and improvements, it’s already packing quite a punch and is set to be the future of development for all current, as well as future Apple platforms.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-759"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-757">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-758'
	>
	Prove me wrong?</p></div>	</div>
</div>
</div>		</div>
	</div><p>The post <a href="https://infinum.com/blog/swiftui-2/">SwiftUI 2.0: The Future is Declarative</a> appeared first on <a href="https://infinum.com">Infinum</a>.</p>
]]>
				</content:encoded>
			</item>
					<item>
				<image>
					<url>7941https://infinum.com/uploads/2020/05/top-10-most-useful-iOS-libraries-0.webp</url>
				</image>
				<title>Top 10 Most Useful iOS Libraries in 2020</title>
				<link>https://infinum.com/blog/top-10-most-useful-ios-libraries/</link>
				<pubDate>Wed, 20 May 2020 17:36:00 +0000</pubDate>
				<dc:creator>Goran Brlas</dc:creator>
				<guid isPermaLink="false">https://infinum.com/the-capsized-eight/top-10-most-useful-ios-libraries/</guid>
				<description>
					<![CDATA[<p>A 2020 list of the top 10 libraries every iOS developer should know about, fresh off the press.</p>
<p>The post <a href="https://infinum.com/blog/top-10-most-useful-ios-libraries/">Top 10 Most Useful iOS Libraries in 2020</a> appeared first on <a href="https://infinum.com">Infinum</a>.</p>
]]>
				</description>
				<content:encoded>
					<![CDATA[<div
	class="wrapper"
	data-id="es-963"
	 data-animation-target='inner-items'>
		
			<div class="wrapper__inner">
			<div class="block-blog-content js-block-blog-content">
	
<div class="block-blog-content-sidebar" data-id="es-762">
	</div>

<div class="block-blog-content-main">
	
<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-765"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-763">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-764'
	>
	Nearly five years ago, we published an article listing the<a href="https://infinum.com/blog/top-10-ios-swift-libraries-every-ios-developer-should-know-about/"> top 10 libraries every iOS developer should know about</a>.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-768"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-766">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-767'
	>
	The article provided a great starting point for developers looking to increase their productivity and avoid reinventing the wheel.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-771"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-769">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-770'
	>
	Turns out it was a highly searched topic, and the blog post remained relevant a lot longer than we expected.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-776"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="blockquote block-blockquote__blockquote" data-id="es-772">
	
	<div class="blockquote__content">
		<i
	class="icon blockquote__icon icon--size-16 icon--scale-100"
	 aria-hidden='true' data-name='blockquote-24' data-id='es-773'>
	<svg fill='none' height='24' viewBox='0 0 24 24' width='24' xmlns='http://www.w3.org/2000/svg'><path clip-rule='evenodd' d='m12 24c6.6274 0 12-5.3726 12-12 0-2.79685-.9568-5.37021-2.561-7.41062-.581.22951-1.0832.60583-1.5069 1.12898-.5132.60844-.7698 1.41969-.7698 2.43375v.07605h2.5789v5.59004h-5.6197v-5.01962c0-1.11547.154-2.06616.4619-2.85205.3336-.81125.757-1.48307 1.2702-2.01545.528-.52161 1.1175-.92155 1.7687-1.1998-2.0728-1.70651-4.7279-2.73128-7.6223-2.73128-6.62742 0-12 5.37258-12 12 0 6.6274 5.37258 12 12 12zm-3.53811-18.05347c-.30793.78589-.46189 1.73658-.46189 2.85205v5.01962h5.6197v-5.59004h-2.5789v-.07605c0-1.01406.2566-1.82531.7698-2.43375.5389-.63379 1.1804-1.05209 1.9245-1.2549v-2.28164c-.7441.07605-1.4626.25351-2.1555.53238-.6928.27887-1.3086.68449-1.84752 1.21688-.51321.53238-.9366 1.2042-1.27019 2.01545z' fill='currentColor' fill-rule='evenodd'/></svg></i><p	class='typography typography--size-36-text js-typography blockquote__quote'
	data-id='es-774'
	>
	With changes introduced in every new iOS release, our development needs have changed as well, resulting in rethinking which libraries we use.</p>
		<div class="blockquote__caption-wrap">
					</div>
	</div>
</div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-779"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-777">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-778'
	>
	Some of them listed in that article have stood the test of time and are making a comeback here, but there are also some newcomers which make our day-to-day programming lives easier.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-782"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-780">
	<h2	class='typography typography--size-52-default js-typography block-heading__heading'
	data-id='es-781'
	>
	With great libraries comes great responsibility</h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-785"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-783">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-784'
	>
	Before we actually start going through the list, I’d like to bring up an important disclaimer – <strong>use third-party libraries responsibly</strong>.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-788"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-786">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-787'
	>
	Be sure to check whether the libraries you’re going to use are actively maintained and supported.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-791"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-789">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-790'
	>
	Working on a project a year or two down the line could prove to be troublesome if at some point it stops compiling because of a Swift or iOS change that breaks used libraries.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-794"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-792">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-793'
	>
	Also, <strong><em>please</em></strong>, don’t import libraries in your projects just for the sake of it if you’re only going to use a very small part of that library. A great quote I heard at one recent meetup comes to mind here: <em>”Don’t use an excavator where a shovel would suffice.”</em></p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-797"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-795">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-796'
	>
	Now that we’ve covered the disclaimer part, I’d also like to point out that this list was compiled and ordered by looking at <a href="https://infinum.com/work/">our recent projects</a> and needs, and does not reflect any official download numbers or rankings that could be found online.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-800"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-798">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-799'
	>
	Your mileage may vary depending on your project’s domain, but hopefully, you’ll find something of use here as well.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-803"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-801">
	<h2	class='typography typography--size-52-default js-typography block-heading__heading'
	data-id='es-802'
	>
	Top 10 most useful iOS libraries in 2020</h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-806"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-804">
	<h3	class='typography typography--size-36-text js-typography block-heading__heading'
	data-id='es-805'
	>
	1. <a href="https://github.com/Alamofire/Alamofire">Alamofire</a></h3></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-809"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-807">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-808'
	>
	Alamofire is an elegant and composable way to interface with HTTP network requests. It builds on top of Apple’s <a href="https://developer.apple.com/documentation/foundation/url_loading_system/">URL Loading System</a> provided by the Foundation framework. At the core of the system are <em>URLSession</em> and <em>URLSessionTask</em> subclasses.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-812"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-810">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-811'
	>
	Alamofire wraps these APIs, and many others, in an easy-to-use interface and provides a variety of functionality necessary for modern application development using HTTP networking.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-814"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-code">
	<pre class="phiki language-swift github-light" data-language="swift" style="background-color: #fff;color: #24292e;"><code><span class="line"><span class="token">AF
</span></span><span class="line"><span class="token">    .</span><span class="token">request(</span><span class="token" style="color: #032f62;">&quot;</span><span class="token" style="color: #032f62;">https://your.api.url</span><span class="token" style="color: #032f62;">&quot;</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">    .</span><span class="token">validate(</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">    .</span><span class="token">responseDecodable(</span><span class="token">of:</span><span class="token"> SomeDecodableObject.</span><span class="token" style="color: #d73a49;">self</span><span class="token">)</span><span class="token"> </span><span class="token">{</span><span class="token"> </span><span class="token">(</span><span class="token">response</span><span class="token">)</span><span class="token"> </span><span class="token" style="color: #d73a49;">in</span><span class="token">
</span></span><span class="line"><span class="token">        </span><span class="token" style="color: #d73a49;">guard</span><span class="token"> </span><span class="token" style="color: #d73a49;">let</span><span class="token"> object </span><span class="token" style="color: #d73a49;">=</span><span class="token"> response.</span><span class="token" style="color: #005cc5;">value</span><span class="token"> </span><span class="token" style="color: #d73a49;">else</span><span class="token"> </span><span class="token">{</span><span class="token"> </span><span class="token" style="color: #d73a49;">return</span><span class="token"> </span><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">        </span><span class="token" style="color: #005cc5;">print</span><span class="token">(</span><span class="token">object</span><span class="token">)</span><span class="token"> </span><span class="token" style="color: #6a737d;">//</span><span class="token" style="color: #6a737d;"> Your object, decoded and ready to use.</span><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span></code></pre></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-817"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-815">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-816'
	>
	From top to bottom, you request the endpoint, validate the response by ensuring the response returned an HTTP status code in the range 200–299 and decode the response into your data model. Easy peasy.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-820"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-818">
	<h3	class='typography typography--size-36-text js-typography block-heading__heading'
	data-id='es-819'
	>
	2. <a href="https://github.com/ReactiveX/RxSwift">RxSwift</a></h3></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-823"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-821">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-822'
	>
	This is a Swift version of <a href="https://github.com/Reactive-Extensions/Rx.NET">Rx</a>. It tries to port as many concepts from the original version as possible, but some of them were adapted for more pleasant and performant integration with iOS/macOS environment.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-826"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-824">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-825'
	>
	Like the original Rx, its intention is to enable easy composition of asynchronous operations and event/data streams. KVO observing, async operations, and streams are all unified under the abstraction of sequence. This is the reason why Rx is so simple, elegant, and powerful.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-829"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-827">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-828'
	>
	Here’s a simple example of how RxSwift can be used to create a logic for enabling a login button that checks two things – whether the username and password are both entered, and if the password is of appropriate minimum length.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-831"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-code">
	<pre class="phiki language-swift github-light" data-language="swift" style="background-color: #fff;color: #24292e;"><code><span class="line"><span class="token" style="color: #d73a49;">let</span><span class="token"> name </span><span class="token" style="color: #d73a49;">=</span><span class="token"> nameTextField.</span><span class="token">rx</span><span class="token">.</span><span class="token" style="color: #005cc5;">text</span><span class="token">.</span><span class="token">asDriver(</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token" style="color: #d73a49;">let</span><span class="token"> password </span><span class="token" style="color: #d73a49;">=</span><span class="token"> passwordTextField.</span><span class="token">rx</span><span class="token">.</span><span class="token" style="color: #005cc5;">text</span><span class="token">.</span><span class="token">asDriver(</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token" style="color: #d73a49;">let</span><span class="token"> isEnabled </span><span class="token" style="color: #d73a49;">=</span><span class="token"> Driver
</span></span><span class="line"><span class="token">    .</span><span class="token">combineLatest(</span><span class="token">
</span></span><span class="line"><span class="token">        </span><span class="token">name</span><span class="token">,
</span></span><span class="line"><span class="token">        </span><span class="token">password
</span></span><span class="line"><span class="token">    </span><span class="token">)</span><span class="token"> </span><span class="token">{</span><span class="token"> </span><span class="token" style="color: #d73a49;">!</span><span class="token" style="color: #005cc5;">$0</span><span class="token">.</span><span class="token" style="color: #005cc5;">isEmpty</span><span class="token"> </span><span class="token" style="color: #d73a49;">&amp;&amp;</span><span class="token"> </span><span class="token" style="color: #005cc5;">$1</span><span class="token">.</span><span class="token" style="color: #005cc5;">count</span><span class="token"> </span><span class="token" style="color: #d73a49;">&gt;=</span><span class="token"> </span><span class="token" style="color: #005cc5;">6</span><span class="token"> </span><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token">isEnabled
</span></span><span class="line"><span class="token">    .</span><span class="token">drive(</span><span class="token">loginButton.</span><span class="token">rx</span><span class="token">.</span><span class="token">isEnabled</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">    .</span><span class="token">disposed(</span><span class="token">by:</span><span class="token"> disposeBag</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span></code></pre></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-834"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-832">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-833'
	>
	This is just scratching RxSwift’s/RxCocoa’s surface, but you can already see how it can make your life easier. RxSwift has a steeper learning curve than most libraries you could include in your projects, but once you get the hang of it, you’ll be thankful you did and will probably never look back.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-837"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-835">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-836'
	>
	Note – <a href="https://developer.apple.com/documentation/combine">Combine</a> will probably at some point going to slowly start sunsetting RxSwift, but since it requires iOS 13 as a minimum OS version, that is still a couple of years away, and RxSwift will prevail until then.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-840"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-838">
	<h3	class='typography typography--size-36-text js-typography block-heading__heading'
	data-id='es-839'
	>
	3. <a href="https://github.com/onevcat/Kingfisher">Kingfisher</a></h3></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-843"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-841">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-842'
	>
	Kingfisher is a powerful, pure-Swift library for downloading and caching images from the web. It will download the image from url, send it to both memory cache and disk cache, and display it in an UIImageView, NSImageView, NSButton, or UIButton. When you try to retrieve an image with the same URL later, the image will be retrieved from the cache and shown immediately.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-845"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-code">
	<pre class="phiki language-swift github-light" data-language="swift" style="background-color: #fff;color: #24292e;"><code><span class="line"><span class="token" style="color: #6a737d;">//</span><span class="token" style="color: #6a737d;"> Basic version</span><span class="token">
</span></span><span class="line"><span class="token" style="color: #d73a49;">let</span><span class="token"> url </span><span class="token" style="color: #d73a49;">=</span><span class="token"> </span><span class="token">URL(</span><span class="token">string:</span><span class="token"> </span><span class="token" style="color: #032f62;">&quot;</span><span class="token" style="color: #032f62;">https://example.com/image.png</span><span class="token" style="color: #032f62;">&quot;</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">imageView.</span><span class="token">kf</span><span class="token">.</span><span class="token">setImage(</span><span class="token">with:</span><span class="token"> url</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token" style="color: #6a737d;">//</span><span class="token" style="color: #6a737d;"> SwiftUI version</span><span class="token">
</span></span><span class="line"><span class="token" style="color: #d73a49;">import</span><span class="token"> </span><span class="token" style="color: #6f42c1;">KingfisherSwiftUI</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token">var body:</span><span class="token"> </span><span class="token" style="color: #d73a49;">some</span><span class="token"> View </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token">KFImage(</span><span class="token">URL(</span><span class="token">string:</span><span class="token"> </span><span class="token" style="color: #032f62;">&quot;</span><span class="token" style="color: #032f62;">https://example.com/image.png</span><span class="token" style="color: #032f62;">&quot;</span><span class="token">)</span><span class="token" style="color: #d73a49;">!</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span></code></pre></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-848"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-846">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-847'
	>
	It also provides many powerful additional options such showing a system indicator and a placeholder image while downloading, built-in updating transitions, extensible image processing, formatting, and much more. A must-have if you’re working with remote images!</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-851"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-849">
	<h3	class='typography typography--size-36-text js-typography block-heading__heading'
	data-id='es-850'
	>
	4. <a href="https://github.com/airbnb/lottie-ios">Lottie</a></h3></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-854"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-852">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-853'
	>
	Let’s be honest, animations in an application make a huge difference. They grasp your user’s attention and steer them through your app’s flow, all the while providing a fun and memorable experience. Since creating animations by hand using <em>UIView</em> or <em>CoreGraphics</em> animations can prove to be quite challenging and time-consuming, Lottie provides us with a perfect tool to incorporate desinger creations into our applications.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-857"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-855">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-856'
	>
	Lottie loads and renders animations and vectors exported in the bodymovin JSON format. Bodymovin JSON can be created and exported from After Effects with <a href="https://github.com/bodymovin/bodymovin">bodymovin</a>, Sketch with <a href="https://github.com/buba447/Lottie-Sketch-Export">Lottie Sketch Export</a>, and from <a href="https://www.haiku.ai/">Haiku</a>.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-859"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-code">
	<pre class="phiki language-swift github-light" data-language="swift" style="background-color: #fff;color: #24292e;"><code><span class="line"><span class="token" style="color: #d73a49;">override</span><span class="token"> </span><span class="token">func viewDidLoad</span><span class="token">(</span><span class="token">)</span><span class="token"> </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token" style="color: #005cc5;">super</span><span class="token">.</span><span class="token">viewDidLoad(</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token">startAnimating(</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token">func startAnimating</span><span class="token">(</span><span class="token">)</span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">    animationView.</span><span class="token">setAnimation(</span><span class="token">named:</span><span class="token"> </span><span class="token" style="color: #032f62;">&quot;</span><span class="token" style="color: #032f62;">bird_flying</span><span class="token" style="color: #032f62;">&quot;</span><span class="token">)</span><span class="token"> </span><span class="token" style="color: #6a737d;">//</span><span class="token" style="color: #6a737d;"> &quot;bird_flying&quot; is an example animation that can be found here: https://lottiefiles.com/17655-bird-flying</span><span class="token">
</span></span><span class="line"><span class="token">    animationView.</span><span class="token">play(</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span></code></pre></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-862"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-860">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-861'
	>
	After importing Lottie into your project, this is all the code needed to add a beautiful animation to your app. Quite a timesaver.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-865"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-863">
	<h3	class='typography typography--size-36-text js-typography block-heading__heading'
	data-id='es-864'
	>
	5. <a href="https://github.com/realm/SwiftLint">SwiftLint</a></h3></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-868"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-866">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-867'
	>
	SwiftLint is a tool used to enforce Swift style and conventions, loosely based on <a href="https://github.com/github/swift-style-guide">GitHub’s Swift Style Guide</a>.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-871"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-869">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-870'
	>
	SwiftLint hooks into <a href="http://clang.llvm.org/">Clang</a> and <a href="http://www.jpsim.com/uncovering-sourcekit">SourceKit</a> and uses the <a href="http://clang.llvm.org/docs/IntroductionToTheClangAST.html">AST</a> representation of your source files for more accurate results.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-874"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-872">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-873'
	>
	Its <a href="https://realm.github.io/SwiftLint/rule-directory.html">rule list</a> is quite extensive and covers pretty much everything you would want to keep track of in a well-maintained project. It also has the option to disable rules per file or even per line, but use those responsibly. Silencing a warning about a 700-line file or a too long method is maybe not the best way to go around doing things.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-877"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-875">
	<h3	class='typography typography--size-36-text js-typography block-heading__heading'
	data-id='es-876'
	>
	6. <a href="https://github.com/SnapKit/SnapKit">SnapKit</a></h3></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-880"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-878">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-879'
	>
	SnapKit is an Auto Layout library that simplifies writing auto layout in code with a minimal amount of code needed without losing readability.<br />
It is type-safe by design to help you avoid programming errors while coding your user interface.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-882"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-code">
	<pre class="phiki language-swift github-light" data-language="swift" style="background-color: #fff;color: #24292e;"><code><span class="line"><span class="token" style="color: #d73a49;">let</span><span class="token"> box </span><span class="token" style="color: #d73a49;">=</span><span class="token"> </span><span class="token">UIView(</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token" style="color: #d73a49;">let</span><span class="token"> container </span><span class="token" style="color: #d73a49;">=</span><span class="token"> </span><span class="token">UIView(</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token">container.</span><span class="token">addSubview(</span><span class="token">box</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token">box.</span><span class="token">snp</span><span class="token">.</span><span class="token">makeConstraints</span><span class="token"> </span><span class="token">{</span><span class="token"> make </span><span class="token" style="color: #d73a49;">in</span><span class="token">
</span></span><span class="line"><span class="token">    make.</span><span class="token" style="color: #005cc5;">size</span><span class="token">.</span><span class="token">equalTo(</span><span class="token" style="color: #005cc5;">50</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">    make.</span><span class="token">center</span><span class="token">.</span><span class="token">equalTo(</span><span class="token">container</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span></code></pre></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-885"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-883">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-884'
	>
	It’s also very powerful when it comes to views whose constraints are updated frequently. Remaking constraints is much more pleasant than dealing with Auto Layout by hand:</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-887"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-code">
	<pre class="phiki language-swift github-light" data-language="swift" style="background-color: #fff;color: #24292e;"><code><span class="line"><span class="token">func updateBoxSize</span><span class="token">(</span><span class="token">to size</span><span class="token">: </span><span class="token">CGFloat</span><span class="token">)</span><span class="token"> </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">    box.</span><span class="token">snp</span><span class="token">.</span><span class="token">remakeConstraints</span><span class="token"> </span><span class="token">{</span><span class="token"> make </span><span class="token" style="color: #d73a49;">in</span><span class="token">
</span></span><span class="line"><span class="token">        make.</span><span class="token" style="color: #005cc5;">size</span><span class="token">.</span><span class="token">equalTo(</span><span class="token">size
</span></span><span class="line"><span class="token">    }
</span></span><span class="line"><span class="token">}
</span></span><span class="line"><span class="token">
</span></span></code></pre></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-890"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-888">
	<h3	class='typography typography--size-36-text js-typography block-heading__heading'
	data-id='es-889'
	>
	7. <a href="https://github.com/SwiftyBeaver/SwiftyBeaver">SwiftyBeaver</a></h3></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-893"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-891">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-892'
	>
	SwiftyBeaver is a colorful, flexible and lightweight library enabling easier logging during the development of your applications. Gone are the days of bland console outputs; using this library makes finding out what went wrong a breeze.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-895"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-code">
	<pre class="phiki language-swift github-light" data-language="swift" style="background-color: #fff;color: #24292e;"><code><span class="line"><span class="token" style="color: #d73a49;">let</span><span class="token"> log </span><span class="token" style="color: #d73a49;">=</span><span class="token"> SwiftyBeaver.</span><span class="token" style="color: #d73a49;">self</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token" style="color: #d73a49;">let</span><span class="token"> console </span><span class="token" style="color: #d73a49;">=</span><span class="token"> </span><span class="token">ConsoleDestination(</span><span class="token">)</span><span class="token">  </span><span class="token" style="color: #6a737d;">//</span><span class="token" style="color: #6a737d;"> log to Xcode Console</span><span class="token">
</span></span><span class="line"><span class="token">log.</span><span class="token">addDestination(</span><span class="token">console</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token" style="color: #6a737d;">//</span><span class="token" style="color: #6a737d;"> Now let’s log!</span><span class="token">
</span></span><span class="line"><span class="token">log.</span><span class="token">verbose(</span><span class="token" style="color: #032f62;">&quot;</span><span class="token" style="color: #032f62;">not so important</span><span class="token" style="color: #032f62;">&quot;</span><span class="token">)</span><span class="token">  </span><span class="token" style="color: #6a737d;">//</span><span class="token" style="color: #6a737d;"> prio 1, VERBOSE in silver</span><span class="token">
</span></span><span class="line"><span class="token">log.</span><span class="token">debug(</span><span class="token" style="color: #032f62;">&quot;</span><span class="token" style="color: #032f62;">something to debug</span><span class="token" style="color: #032f62;">&quot;</span><span class="token">)</span><span class="token">  </span><span class="token" style="color: #6a737d;">//</span><span class="token" style="color: #6a737d;"> prio 2, DEBUG in green</span><span class="token">
</span></span><span class="line"><span class="token">log.</span><span class="token">info(</span><span class="token" style="color: #032f62;">&quot;</span><span class="token" style="color: #032f62;">a nice information</span><span class="token" style="color: #032f62;">&quot;</span><span class="token">)</span><span class="token">   </span><span class="token" style="color: #6a737d;">//</span><span class="token" style="color: #6a737d;"> prio 3, INFO in blue</span><span class="token">
</span></span><span class="line"><span class="token">log.</span><span class="token">warning(</span><span class="token" style="color: #032f62;">&quot;</span><span class="token" style="color: #032f62;">oh no, that won’t be good</span><span class="token" style="color: #032f62;">&quot;</span><span class="token">)</span><span class="token">  </span><span class="token" style="color: #6a737d;">//</span><span class="token" style="color: #6a737d;"> prio 4, WARNING in yellow</span><span class="token">
</span></span><span class="line"><span class="token">log.</span><span class="token" style="color: #005cc5;">error</span><span class="token">(</span><span class="token" style="color: #032f62;">&quot;</span><span class="token" style="color: #032f62;">ouch, an error did occur!</span><span class="token" style="color: #032f62;">&quot;</span><span class="token">)</span><span class="token">  </span><span class="token" style="color: #6a737d;">//</span><span class="token" style="color: #6a737d;"> prio 5, ERROR in red</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span></code></pre></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-898"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-896">
	<h3	class='typography typography--size-36-text js-typography block-heading__heading'
	data-id='es-897'
	>
	8. <a href="https://github.com/kishikawakatsumi/KeychainAccess">KeychainAccess</a></h3></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-901"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-899">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-900'
	>
	KeychainAccess is a simple Swift wrapper for Keychain that works on iOS and macOS. It makes using Keychain APIs extremely easy and much more palatable to use in Swift.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-904"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-902">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-903'
	>
	Saving data to the Keychain and retrieving it has never been easier:</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-906"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-code">
	<pre class="phiki language-swift github-light" data-language="swift" style="background-color: #fff;color: #24292e;"><code><span class="line"><span class="token" style="color: #6a737d;">//</span><span class="token" style="color: #6a737d;"> Save to the keychain</span><span class="token">
</span></span><span class="line"><span class="token" style="color: #d73a49;">let</span><span class="token"> valueToSave </span><span class="token" style="color: #d73a49;">=</span><span class="token"> </span><span class="token" style="color: #032f62;">&quot;</span><span class="token" style="color: #032f62;">Important data</span><span class="token" style="color: #032f62;">&quot;</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token">Keychain(</span><span class="token">)</span><span class="token">.</span><span class="token" style="color: #005cc5;">set</span><span class="token">(</span><span class="token">valueToSave</span><span class="token">, </span><span class="token">key:</span><span class="token"> </span><span class="token" style="color: #032f62;">&quot;</span><span class="token" style="color: #032f62;">key</span><span class="token" style="color: #032f62;">&quot;</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token" style="color: #6a737d;">//</span><span class="token" style="color: #6a737d;"> Get from keychain</span><span class="token">
</span></span><span class="line"><span class="token" style="color: #d73a49;">let</span><span class="token"> savedValue </span><span class="token" style="color: #d73a49;">=</span><span class="token"> </span><span class="token" style="color: #d73a49;">try</span><span class="token" style="color: #d73a49;">?</span><span class="token"> </span><span class="token">Keychain(</span><span class="token">)</span><span class="token">.</span><span class="token">get(</span><span class="token" style="color: #032f62;">&quot;</span><span class="token" style="color: #032f62;">key</span><span class="token" style="color: #032f62;">&quot;</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span></code></pre></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-909"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-907">
	<h3	class='typography typography--size-36-text js-typography block-heading__heading'
	data-id='es-908'
	>
	9. <a href="https://github.com/HeroTransitions/Hero">Hero</a></h3></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-912"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-910">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-911'
	>
	Hero is a library for building iOS view controller transitions. It provides a declarative layer on top of the UIKit’s cumbersome transition APIs — making custom transitions an easy task for us.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-915"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-913">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-914'
	>
	It works similar to Keynote’s Magic Move. It checks the <em>heroID</em> property on all source and destination views. Every matched view pair is then automatically transitioned from its old state to its new state.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-918"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-916">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-917'
	>
	Hero can also construct animations for unmatched views. It is easy to define these animations via the heroModifiers property. Hero will run these animations alongside the Magic Move animations. All of these animations can be interactively controlled by user gestures.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-920"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-code">
	<pre class="phiki language-swift github-light" data-language="swift" style="background-color: #fff;color: #24292e;"><code><span class="line"><span class="token" style="color: #6a737d;">//</span><span class="token" style="color: #6a737d;"> First viewController - VC1</span><span class="token">
</span></span><span class="line"><span class="token">redView.</span><span class="token">hero</span><span class="token">.</span><span class="token">id</span><span class="token"> </span><span class="token" style="color: #d73a49;">=</span><span class="token"> </span><span class="token" style="color: #032f62;">&quot;</span><span class="token" style="color: #032f62;">ironMan</span><span class="token" style="color: #032f62;">&quot;</span><span class="token">
</span></span><span class="line"><span class="token">blackView.</span><span class="token">hero</span><span class="token">.</span><span class="token">id</span><span class="token"> </span><span class="token" style="color: #d73a49;">=</span><span class="token"> </span><span class="token" style="color: #032f62;">&quot;</span><span class="token" style="color: #032f62;">batMan</span><span class="token" style="color: #032f62;">&quot;</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token" style="color: #6a737d;">//</span><span class="token" style="color: #6a737d;"> Second viewController - VC2</span><span class="token">
</span></span><span class="line"><span class="token" style="color: #005cc5;">self</span><span class="token">.</span><span class="token">hero</span><span class="token">.</span><span class="token">isEnabled</span><span class="token"> </span><span class="token" style="color: #d73a49;">=</span><span class="token"> </span><span class="token" style="color: #005cc5;">true</span><span class="token">
</span></span><span class="line"><span class="token">redView.</span><span class="token">hero</span><span class="token">.</span><span class="token">id</span><span class="token"> </span><span class="token" style="color: #d73a49;">=</span><span class="token"> </span><span class="token" style="color: #032f62;">&quot;</span><span class="token" style="color: #032f62;">ironMan</span><span class="token" style="color: #032f62;">&quot;</span><span class="token">
</span></span><span class="line"><span class="token">blackView.</span><span class="token">hero</span><span class="token">.</span><span class="token">id</span><span class="token"> </span><span class="token" style="color: #d73a49;">=</span><span class="token"> </span><span class="token" style="color: #032f62;">&quot;</span><span class="token" style="color: #032f62;">batMan</span><span class="token" style="color: #032f62;">&quot;</span><span class="token">
</span></span><span class="line"><span class="token">whiteView.</span><span class="token">hero</span><span class="token">.</span><span class="token">modifiers</span><span class="token"> </span><span class="token" style="color: #d73a49;">=</span><span class="token"> [.</span><span class="token">translate(</span><span class="token">y:</span><span class="token"> </span><span class="token" style="color: #005cc5;">100</span><span class="token">)</span><span class="token">]
</span></span><span class="line"><span class="token">
</span></span></code></pre></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-923"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-921">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-922'
	>
	As you can see, Hero does a lot of heavy lifting in order to provide us with a simple API to create powerful animations.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-926"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-924">
	<h3	class='typography typography--size-36-text js-typography block-heading__heading'
	data-id='es-925'
	>
	10. <a href="https://github.com/AliSoftware/OHHTTPStubs">OHTTPStubs</a></h3></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-929"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-927">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-928'
	>
	OHTTPStubs is a library designed to stub network requests by using method swizzling. It works with <em>NSURLConnection</em>, <em>NSURLSession</em>, <em>AFNetworking</em>, <em>Alamofire,</em> or any networking framework that uses Cocoa’s URL Loading System.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-931"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-code">
	<pre class="phiki language-swift github-light" data-language="swift" style="background-color: #fff;color: #24292e;"><code><span class="line"><span class="token">stub(</span><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token">condition:</span><span class="token"> </span><span class="token">{</span><span class="token"> </span><span class="token">(</span><span class="token">request:</span><span class="token"> URLRequest</span><span class="token">)</span><span class="token"> </span><span class="token" style="color: #d73a49;">-&gt;</span><span class="token"> </span><span class="token" style="color: #005cc5;">Bool</span><span class="token"> </span><span class="token" style="color: #d73a49;">in</span><span class="token">
</span></span><span class="line"><span class="token">        </span><span class="token" style="color: #6a737d;">//</span><span class="token" style="color: #6a737d;"> check whether this api call should be mocked by using the response closure</span><span class="token">
</span></span><span class="line"><span class="token">        </span><span class="token" style="color: #6a737d;">//</span><span class="token" style="color: #6a737d;"> return false if it shouldn’t</span><span class="token">
</span></span><span class="line"><span class="token">        </span><span class="token" style="color: #d73a49;">return</span><span class="token"> </span><span class="token" style="color: #005cc5;">true</span><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token">}</span><span class="token">,
</span></span><span class="line"><span class="token">    </span><span class="token">response:</span><span class="token"> </span><span class="token">{</span><span class="token"> </span><span class="token" style="color: #005cc5;">_</span><span class="token"> </span><span class="token" style="color: #d73a49;">-&gt;</span><span class="token"> OHHTTPStubsResponse </span><span class="token" style="color: #d73a49;">in</span><span class="token">
</span></span><span class="line"><span class="token">        </span><span class="token" style="color: #d73a49;">let</span><span class="token"> path </span><span class="token" style="color: #d73a49;">=</span><span class="token"> </span><span class="token" style="color: #032f62;">&quot;</span><span class="token" style="color: #032f62;">...path_to_your_file.json</span><span class="token" style="color: #032f62;">&quot;</span><span class="token">
</span></span><span class="line"><span class="token">        </span><span class="token" style="color: #d73a49;">return</span><span class="token"> </span><span class="token">fixture(</span><span class="token">filePath:</span><span class="token"> path</span><span class="token">, </span><span class="token">status:</span><span class="token"> </span><span class="token" style="color: #005cc5;">200</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span></code></pre></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-934"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-932">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-933'
	>
	This library comes in handy in several situations:</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-937"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="lists" data-id="es-935">
	<ul	class='typography typography--size-16-text-roman js-typography lists__typography'
	data-id='es-936'
	>
	<li>mocking different API responses while the app is in development to check if our UI handles every case correctly,</li><li>easier integration testing by providing baked in responses to your testing suite,</li><li>implementing a demo mode inside your application that doesn’t reach the actual server, but uses baked-in responses.</li></ul></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-940"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-938">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-939'
	>
	I’ve written about implementing such a demo mode in <a href="https://infinum.com/blog/easy-way-to-implement-demo-mode-in-ios-apps/">one of my previous articles</a>, so be sure to check it out if you’d like to learn more about it.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-943"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-941">
	<h2	class='typography typography--size-52-default js-typography block-heading__heading'
	data-id='es-942'
	>
	Honorable mentions</h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-946"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-944">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-945'
	>
	There are a few more libraries we use in most of our projects, but since these are our own open-source projects it didn’t seem fitting that they steal the spotlight of other popular third-party solutions.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-949"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-947">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-948'
	>
	However, since they could prove to be of use to you, we should also list them here as well:</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-952"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="lists" data-id="es-950">
	<ul	class='typography typography--size-16-text-roman js-typography lists__typography'
	data-id='es-951'
	>
	<li><a href="https://github.com/infinum/iOS-prince-of-versions">Prince of Versions</a> – used for easier versioning of your applications, allowing you to prompt your users to update the app to the newest version.</li><li><a href="https://github.com/infinum/iOS-Loggie">Loggie</a> – used for capturing all HTTP/S requests the app makes and showing them in a simple table view, enabling easier API debugging.</li><li><a href="https://github.com/infinum/Japx">Japx</a> – lightweight <a href="https://jsonapi.org/">JSON:API</a> parser that flattens complex JSON:API structure and turns it into simple JSON and vice versa.</li><li><a href="https://github.com/infinum/Locker">Locker</a> – a lightweight library for handling sensitive data (<em>String</em> type) in Keychain using iOS Biometric features.</li></ul></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-955"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-953">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-954'
	>
	While we’re at it, you can also check out <a href="https://github.com/infinum/iOS-Nuts-And-Bolts">Nuts &amp; Bolts</a>, our repo containing a centralized collection of commonly shared and reused code throughout the Infinum iOS team.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-958"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-956">
	<h2	class='typography typography--size-52-default js-typography block-heading__heading'
	data-id='es-957'
	>
	What’s your take on our list?</h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-961"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-959">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-960'
	>
	Do you agree with us? Got some other libraries you find useful that you would like to share? Leave a comment or contact us on social media. We’re eager to learn about new things and interesting ways of easing common iOS pain points.</p></div>	</div>
</div>
</div>		</div>
	</div><p>The post <a href="https://infinum.com/blog/top-10-most-useful-ios-libraries/">Top 10 Most Useful iOS Libraries in 2020</a> appeared first on <a href="https://infinum.com">Infinum</a>.</p>
]]>
				</content:encoded>
			</item>
					<item>
				<image>
					<url>8088https://infinum.com/uploads/2020/03/forget-the-year-of-the-rat-2020-belongs-to-flutter-0.webp</url>
				</image>
				<title>Forget the Year of the Rat, 2020 Belongs to Flutter</title>
				<link>https://infinum.com/blog/forget-the-year-of-the-rat-2020-belongs-to-flutter/</link>
				<pubDate>Fri, 06 Mar 2020 14:10:00 +0000</pubDate>
				<dc:creator>Goran Brlas</dc:creator>
				<guid isPermaLink="false">https://infinum.com/the-capsized-eight/forget-the-year-of-the-rat-2020-belongs-to-flutter/</guid>
				<description>
					<![CDATA[<p>One cross-platform technology has recently taken mobile development by storm. Why are Flutter apps special? Should businesses invest in Flutter-powered software?</p>
<p>The post <a href="https://infinum.com/blog/forget-the-year-of-the-rat-2020-belongs-to-flutter/">Forget the Year of the Rat, 2020 Belongs to Flutter</a> appeared first on <a href="https://infinum.com">Infinum</a>.</p>
]]>
				</description>
				<content:encoded>
					<![CDATA[<div
	class="wrapper"
	data-id="es-1182"
	 data-animation-target='inner-items'>
		
			<div class="wrapper__inner">
			<div class="block-blog-content js-block-blog-content">
	
<div class="block-blog-content-sidebar" data-id="es-964">
	</div>

<div class="block-blog-content-main">
	
<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-967"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-965">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-966'
	>
	Brands introducing mobile apps may have been innovative a couple of years back. Fast forward to 2020 and modern businesses without a mobile app connecting them to end-users are missing out.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-970"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-968">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-969'
	>
	Your local supermarket chain? They have an app. The bakery down the street that you visit every so often? Their doors are plastered with stickers imploring you to download their app to collect membership points.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-973"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-971">
	<h2	class='typography typography--size-52-default js-typography block-heading__heading'
	data-id='es-972'
	>
	Okay, I want a mobile app for my business</h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-976"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-974">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-975'
	>
	The simplicity and convenience of mobile apps attracts clients and users, who in turn bring in financial profitability and security. What’s not to like?</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-979"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-977">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-978'
	>
	Deciding you want an app for your business is the easy part. Figuring out which technology should power your app is a daunting task, especially if you’re new to mobile development.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-984"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="blockquote block-blockquote__blockquote" data-id="es-980">
	
	<div class="blockquote__content">
		<i
	class="icon blockquote__icon icon--size-16 icon--scale-100"
	 aria-hidden='true' data-name='blockquote-24' data-id='es-981'>
	<svg fill='none' height='24' viewBox='0 0 24 24' width='24' xmlns='http://www.w3.org/2000/svg'><path clip-rule='evenodd' d='m12 24c6.6274 0 12-5.3726 12-12 0-2.79685-.9568-5.37021-2.561-7.41062-.581.22951-1.0832.60583-1.5069 1.12898-.5132.60844-.7698 1.41969-.7698 2.43375v.07605h2.5789v5.59004h-5.6197v-5.01962c0-1.11547.154-2.06616.4619-2.85205.3336-.81125.757-1.48307 1.2702-2.01545.528-.52161 1.1175-.92155 1.7687-1.1998-2.0728-1.70651-4.7279-2.73128-7.6223-2.73128-6.62742 0-12 5.37258-12 12 0 6.6274 5.37258 12 12 12zm-3.53811-18.05347c-.30793.78589-.46189 1.73658-.46189 2.85205v5.01962h5.6197v-5.59004h-2.5789v-.07605c0-1.01406.2566-1.82531.7698-2.43375.5389-.63379 1.1804-1.05209 1.9245-1.2549v-2.28164c-.7441.07605-1.4626.25351-2.1555.53238-.6928.27887-1.3086.68449-1.84752 1.21688-.51321.53238-.9366 1.2042-1.27019 2.01545z' fill='currentColor' fill-rule='evenodd'/></svg></i><p	class='typography typography--size-36-text js-typography blockquote__quote'
	data-id='es-982'
	>
	As an experienced design &amp; development agency, we’ve worked with a wide range of technologies and frameworks over the years, looking for the optimal fit for a product.</p>
		<div class="blockquote__caption-wrap">
					</div>
	</div>
</div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-987"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-985">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-986'
	>
	One technology that has stood out on the mobile development horizon lately is a cross-platform technology <a href="https://flutter.dev">Flutter</a>.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-990"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-988">
	<h2	class='typography typography--size-52-default js-typography block-heading__heading'
	data-id='es-989'
	>
	Flutter – The right technology for your app?</h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-993"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-991">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-992'
	>
	From the perspective of a company wanting to build their app, these are the things that you’re interested in:&nbsp;</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-996"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="lists" data-id="es-994">
	<ul	class='typography typography--size-16-text-roman js-typography lists__typography'
	data-id='es-995'
	>
	<li>app production cost (software development is not cheap),</li><li>speed of development,</li><li>UI and UX that will inspire users to use your application.</li></ul></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-999"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-997">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-998'
	>
	In the following paragraphs, we’ll put Flutter through the test and examine how it responds to the requirements above.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1002"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-1000">
	<h3	class='typography typography--size-36-text js-typography block-heading__heading'
	data-id='es-1001'
	>
	Covering all the business logic with just one codebase</h3></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1005"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-1003">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-1004'
	>
	When using Flutter, developers need to write only one codebase, which will cover all the business logic, as well as the UI on both the iOS and Android platforms.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1010"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="blockquote block-blockquote__blockquote" data-id="es-1006">
	
	<div class="blockquote__content">
		<i
	class="icon blockquote__icon icon--size-16 icon--scale-100"
	 aria-hidden='true' data-name='blockquote-24' data-id='es-1007'>
	<svg fill='none' height='24' viewBox='0 0 24 24' width='24' xmlns='http://www.w3.org/2000/svg'><path clip-rule='evenodd' d='m12 24c6.6274 0 12-5.3726 12-12 0-2.79685-.9568-5.37021-2.561-7.41062-.581.22951-1.0832.60583-1.5069 1.12898-.5132.60844-.7698 1.41969-.7698 2.43375v.07605h2.5789v5.59004h-5.6197v-5.01962c0-1.11547.154-2.06616.4619-2.85205.3336-.81125.757-1.48307 1.2702-2.01545.528-.52161 1.1175-.92155 1.7687-1.1998-2.0728-1.70651-4.7279-2.73128-7.6223-2.73128-6.62742 0-12 5.37258-12 12 0 6.6274 5.37258 12 12 12zm-3.53811-18.05347c-.30793.78589-.46189 1.73658-.46189 2.85205v5.01962h5.6197v-5.59004h-2.5789v-.07605c0-1.01406.2566-1.82531.7698-2.43375.5389-.63379 1.1804-1.05209 1.9245-1.2549v-2.28164c-.7441.07605-1.4626.25351-2.1555.53238-.6928.27887-1.3086.68449-1.84752 1.21688-.51321.53238-.9366 1.2042-1.27019 2.01545z' fill='currentColor' fill-rule='evenodd'/></svg></i><p	class='typography typography--size-36-text js-typography blockquote__quote'
	data-id='es-1008'
	>
	Flutter doesn’t have any platform dependencies because it provides its own widgets and designs, meaning that you can run the same app on both platforms. </p>
		<div class="blockquote__caption-wrap">
					</div>
	</div>
</div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1013"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-1011">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-1012'
	>
	However, if you still want some differentiation between them and provide the native feel the users are expecting, that’s more than possible with the use of both <a href="https://flutter.dev/docs/development/ui/widgets/material">Material Components widgets</a>, as well as <a href="https://flutter.dev/docs/development/ui/widgets/cupertino">Cupertino widgets</a>.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1016"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-1014">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-1015'
	>
	Those will provide that specific Android and iOS look &amp; feel you’re after.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1019"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-media">
	<div	class="media block-media__media media__border--none media__align--center-center"
	data-id="es-1017"
	 data-media-type='image'>

	<figure class="image block-media__image-figure image--size-stretch" data-id="es-1018">
	<picture class="image__picture block-media__image-picture">
												<img
					src="https://infinum.com/uploads/2020/02/forget-the-year-of-the-rat-2020-belongs-to-flutter-1.gif"
					class="image__img block-media__image-img"
					alt=""
										height="456"
															width="600"
										loading="lazy"
					 />
					</picture>

			<figcaption class="image__figcaption block-media__image-figcaption">
			Platform-specific look &amp; feel		</figcaption>
	</figure></div></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1022"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-1020">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-1021'
	>
	Having a single codebase also simplifies organizing the workload, as it’s easier to align work on a single codebase powering multiple platforms than it is to align multiple developers, each working on their own platform.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1025"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-1023">
	<h3	class='typography typography--size-36-text js-typography block-heading__heading'
	data-id='es-1024'
	>
	Simplifying the quality assurance process</h3></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1028"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-1026">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-1027'
	>
	One codebase also means faster testing. Developers will need to write unit and integration tests only once, not once for each platform which was the case previously.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1033"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="blockquote block-blockquote__blockquote" data-id="es-1029">
	
	<div class="blockquote__content">
		<i
	class="icon blockquote__icon icon--size-16 icon--scale-100"
	 aria-hidden='true' data-name='blockquote-24' data-id='es-1030'>
	<svg fill='none' height='24' viewBox='0 0 24 24' width='24' xmlns='http://www.w3.org/2000/svg'><path clip-rule='evenodd' d='m12 24c6.6274 0 12-5.3726 12-12 0-2.79685-.9568-5.37021-2.561-7.41062-.581.22951-1.0832.60583-1.5069 1.12898-.5132.60844-.7698 1.41969-.7698 2.43375v.07605h2.5789v5.59004h-5.6197v-5.01962c0-1.11547.154-2.06616.4619-2.85205.3336-.81125.757-1.48307 1.2702-2.01545.528-.52161 1.1175-.92155 1.7687-1.1998-2.0728-1.70651-4.7279-2.73128-7.6223-2.73128-6.62742 0-12 5.37258-12 12 0 6.6274 5.37258 12 12 12zm-3.53811-18.05347c-.30793.78589-.46189 1.73658-.46189 2.85205v5.01962h5.6197v-5.59004h-2.5789v-.07605c0-1.01406.2566-1.82531.7698-2.43375.5389-.63379 1.1804-1.05209 1.9245-1.2549v-2.28164c-.7441.07605-1.4626.25351-2.1555.53238-.6928.27887-1.3086.68449-1.84752 1.21688-.51321.53238-.9366 1.2042-1.27019 2.01545z' fill='currentColor' fill-rule='evenodd'/></svg></i><p	class='typography typography--size-36-text js-typography blockquote__quote'
	data-id='es-1031'
	>
	Your QA’s will also spend less time testing because they effectively only have one application to check.</p>
		<div class="blockquote__caption-wrap">
					</div>
	</div>
</div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1036"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-1034">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-1035'
	>
	Of course, if you decide that your apps will have some platform-specific differences, those will need to be double-checked, but the bulk of the business logic will remain shared.&nbsp;</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1039"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-1037">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-1038'
	>
	This will result in an expedited QA process which doesn’t cut any corners or compromise the app’s quality.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1042"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-1040">
	<h3	class='typography typography--size-36-text js-typography block-heading__heading'
	data-id='es-1041'
	>
	Developing user interface faster</h3></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1045"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-1043">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-1044'
	>
	When talking about mobile development, Flutter has rapidly become a synonym for speed.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1048"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-1046">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-1047'
	>
	When building the app’s UI, it’s possible to <strong>make quick alterations in the source code</strong> which will make all changes immediately visible with the help of the hot reload feature.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1053"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="blockquote block-blockquote__blockquote" data-id="es-1049">
	
	<div class="blockquote__content">
		<i
	class="icon blockquote__icon icon--size-16 icon--scale-100"
	 aria-hidden='true' data-name='blockquote-24' data-id='es-1050'>
	<svg fill='none' height='24' viewBox='0 0 24 24' width='24' xmlns='http://www.w3.org/2000/svg'><path clip-rule='evenodd' d='m12 24c6.6274 0 12-5.3726 12-12 0-2.79685-.9568-5.37021-2.561-7.41062-.581.22951-1.0832.60583-1.5069 1.12898-.5132.60844-.7698 1.41969-.7698 2.43375v.07605h2.5789v5.59004h-5.6197v-5.01962c0-1.11547.154-2.06616.4619-2.85205.3336-.81125.757-1.48307 1.2702-2.01545.528-.52161 1.1175-.92155 1.7687-1.1998-2.0728-1.70651-4.7279-2.73128-7.6223-2.73128-6.62742 0-12 5.37258-12 12 0 6.6274 5.37258 12 12 12zm-3.53811-18.05347c-.30793.78589-.46189 1.73658-.46189 2.85205v5.01962h5.6197v-5.59004h-2.5789v-.07605c0-1.01406.2566-1.82531.7698-2.43375.5389-.63379 1.1804-1.05209 1.9245-1.2549v-2.28164c-.7441.07605-1.4626.25351-2.1555.53238-.6928.27887-1.3086.68449-1.84752 1.21688-.51321.53238-.9366 1.2042-1.27019 2.01545z' fill='currentColor' fill-rule='evenodd'/></svg></i><p	class='typography typography--size-36-text js-typography blockquote__quote'
	data-id='es-1051'
	>
	Teams can add features, fix bugs, and build prototypes in a matter of minutes. </p>
		<div class="blockquote__caption-wrap">
					</div>
	</div>
</div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1056"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-1054">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-1055'
	>
	Hot reload also comes very handy in the cooperation between developers and designers, where the end goal is to improve or experiment with an app’s look and check the effects on the spot.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1059"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-1057">
	<h3	class='typography typography--size-36-text js-typography block-heading__heading'
	data-id='es-1058'
	>
	Creating a customized user interface</h3></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1062"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-1060">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-1061'
	>
	Flutter renders all parts of the interface using internal graphics engine called <a href="https://skia.org">Skia</a>  –  a 2D graphics rendering library, the same one that is used in browsers such as Chrome OS, Android, and Mozilla Firefox. Even though Flutter is a UI framework in its core, it runs on top of the native hardware allowing it to use all of its potential.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1065"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-1063">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-1064'
	>
	With this core technology, apps will get the benefits of compilation to native code. The UI is refreshed at 60fps  (or even higher on devices which support it) mostly using the GPU , and every pixel on the screen is owned by the Skia canvas which leads to a smooth, highly customizable UI.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1068"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-1066">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-1067'
	>
	Creating great-looking and custom UI elements is easy and fun, and will <strong>work and look great on both Android and iOS</strong>. This makes Flutter a great choice for apps with advanced, custom UI designs.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1071"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-media">
	<div	class="media block-media__media media__border--none media__align--center-center"
	data-id="es-1069"
	 data-media-type='image'>

	<figure class="image block-media__image-figure image--size-stretch" data-id="es-1070">
	<picture class="image__picture block-media__image-picture">
								
			<source
				srcset=https://infinum.com/uploads/2020/03/forget-the-year-of-the-rat-2020-belongs-to-flutter-2-1400x875.webp				media='(max-width: 699px)'
				type=image/webp								height="875"
												width="1400"
				 />
												<img
					src="https://infinum.com/uploads/2020/03/forget-the-year-of-the-rat-2020-belongs-to-flutter-2.webp"
					class="image__img block-media__image-img"
					alt=""
										height="1000"
															width="1600"
										loading="lazy"
					 />
					</picture>

	</figure></div></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1074"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-1072">
	<h3	class='typography typography--size-36-text js-typography block-heading__heading'
	data-id='es-1073'
	>
	Already tested by the big players</h3></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1077"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-1075">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-1076'
	>
	Although Flutter is still relatively new (the first stable version was published on Dec 4th, 2018), it has already been field tested by giant companies.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1080"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-1078">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-1079'
	>
	We’re talking <strong>Google</strong> (Ads and Greentea apps, an interface of NEST Hub device), Chinese wholesale &amp; e-commerce giant <strong>Alibaba</strong> with their <a href="https://itsallwidgets.com/alibaba">Xianyu app</a> (used by more than 10 million users every day), and <strong>Tencent</strong>, world’s largest gaming company.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1083"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-1081">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-1082'
	>
	Another great example worth mentioning is <a href="https://www.tonal.com">Tonal</a>, a company whose product is a wall mounted workout machine with an integrated screen, which is accompanied by iOS and Android applications built using Flutter.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1086"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-1084">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-1085'
	>
	If you’re more of a visual type, Flutter’s development team has created a great showcase of apps which have taken flight with it, which you can check out <a href="https://flutter.dev/showcase">here</a>.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1089"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-1087">
	<h3	class='typography typography--size-36-text js-typography block-heading__heading'
	data-id='es-1088'
	>
	Not likely to vanish into thin air</h3></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1092"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-1090">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-1091'
	>
	For some time now (since 2016), there have been reports that Google is working on a <strong>new operating system called <a href="https://fuchsia.dev">Fuchsia</a></strong>. Flutter is also a native framework for Fuchsia apps, which means that if you write an application in Flutter, it will be ready for release on Fuchsia from day one.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1097"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="blockquote block-blockquote__blockquote" data-id="es-1093">
	
	<div class="blockquote__content">
		<i
	class="icon blockquote__icon icon--size-16 icon--scale-100"
	 aria-hidden='true' data-name='blockquote-24' data-id='es-1094'>
	<svg fill='none' height='24' viewBox='0 0 24 24' width='24' xmlns='http://www.w3.org/2000/svg'><path clip-rule='evenodd' d='m12 24c6.6274 0 12-5.3726 12-12 0-2.79685-.9568-5.37021-2.561-7.41062-.581.22951-1.0832.60583-1.5069 1.12898-.5132.60844-.7698 1.41969-.7698 2.43375v.07605h2.5789v5.59004h-5.6197v-5.01962c0-1.11547.154-2.06616.4619-2.85205.3336-.81125.757-1.48307 1.2702-2.01545.528-.52161 1.1175-.92155 1.7687-1.1998-2.0728-1.70651-4.7279-2.73128-7.6223-2.73128-6.62742 0-12 5.37258-12 12 0 6.6274 5.37258 12 12 12zm-3.53811-18.05347c-.30793.78589-.46189 1.73658-.46189 2.85205v5.01962h5.6197v-5.59004h-2.5789v-.07605c0-1.01406.2566-1.82531.7698-2.43375.5389-.63379 1.1804-1.05209 1.9245-1.2549v-2.28164c-.7441.07605-1.4626.25351-2.1555.53238-.6928.27887-1.3086.68449-1.84752 1.21688-.51321.53238-.9366 1.2042-1.27019 2.01545z' fill='currentColor' fill-rule='evenodd'/></svg></i><p	class='typography typography--size-36-text js-typography blockquote__quote'
	data-id='es-1095'
	>
	This can give your app an early adopter boost that might give you an edge over your competitors.</p>
		<div class="blockquote__caption-wrap">
					</div>
	</div>
</div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1100"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-1098">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-1099'
	>
	Flutter’s goals don’t end with mobile development. Its sights are set much higher, with <strong>currently ongoing development in support for both web and desktop</strong>. These are still in their beta and alpha phases respectively, but taking current rapid development into account, we might see their first stable versions soon.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1103"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-1101">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-1102'
	>
	<strong>Internet of Things</strong> is also getting bigger by the day, and Flutter is a viable choice here as well. A cool example is this <a href="https://flutter.dev/clock">competition from Google</a>, where they asked developers to build a beautiful clock face UI for the Lenovo Smart Clock.&nbsp;</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1106"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-1104">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-1105'
	>
	This is just a taste of things to come, and soon we’ll start seeing more and more apps on all those mentioned platforms built using Flutter.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1109"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-1107">
	<h2	class='typography typography--size-52-default js-typography block-heading__heading'
	data-id='es-1108'
	>
	Downsides of Flutter to consider</h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1112"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-1110">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-1111'
	>
	Google’s support for Flutter is impressive, and they have provided us with a great starting kit full of available libraries and functionalites.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1115"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-1113">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-1114'
	>
	However, since Flutter is still relatively new, not everything you’re used to having while using native apps will be available, which will take some additional development time. In most cases, this won’t be a major problem but it should be taken into consideration.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1118"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-1116">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-1117'
	>
	Another potential problem is a pain that comes with every new technology – the possibility that it will evolve in the way which doesn’t align with your visions, and the ever-existing risk that the creator could abandon the project. Looking at you, <a href="https://killedbygoogle.com">Google</a>.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1121"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-1119">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-1120'
	>
	However, considering the fact that Google plan to use Flutter in their new OS and that it’s open source, that’s unlikely.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1124"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-1122">
	<h2	class='typography typography--size-52-default js-typography block-heading__heading'
	data-id='es-1123'
	>
	To Native or to Cross-platform, that is the question</h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1127"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-1125">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-1126'
	>
	As you surely know, when building a mobile app, even before a single line of code is written, a lot of consideration goes into deciding which approach to use . There’s <strong>native</strong> or the <strong>cross-platform</strong> one.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1130"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-1128">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-1129'
	>
	In the paragraphs above, we’ve covered Flutter and explained why we think it is shaping up to be a very exciting and productive technology.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1133"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-media">
	<div	class="media block-media__media media__border--none media__align--center-center"
	data-id="es-1131"
	 data-media-type='image'>

	<figure class="image block-media__image-figure image--size-stretch" data-id="es-1132">
	<picture class="image__picture block-media__image-picture">
								
			<source
				srcset=https://infinum.com/uploads/2020/03/forget-the-year-of-the-rat-2020-belongs-to-flutter-3-1400x622.webp				media='(max-width: 699px)'
				type=image/webp								height="622"
												width="1400"
				 />
												<img
					src="https://infinum.com/uploads/2020/03/forget-the-year-of-the-rat-2020-belongs-to-flutter-3.webp"
					class="image__img block-media__image-img"
					alt=""
										height="711"
															width="1600"
										loading="lazy"
					 />
					</picture>

			<figcaption class="image__figcaption block-media__image-figcaption">
			Native vs cross-platform &#8211; the choice might not be as obvious as it seems		</figcaption>
	</figure></div></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1138"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="blockquote block-blockquote__blockquote" data-id="es-1134">
	
	<div class="blockquote__content">
		<i
	class="icon blockquote__icon icon--size-16 icon--scale-100"
	 aria-hidden='true' data-name='blockquote-24' data-id='es-1135'>
	<svg fill='none' height='24' viewBox='0 0 24 24' width='24' xmlns='http://www.w3.org/2000/svg'><path clip-rule='evenodd' d='m12 24c6.6274 0 12-5.3726 12-12 0-2.79685-.9568-5.37021-2.561-7.41062-.581.22951-1.0832.60583-1.5069 1.12898-.5132.60844-.7698 1.41969-.7698 2.43375v.07605h2.5789v5.59004h-5.6197v-5.01962c0-1.11547.154-2.06616.4619-2.85205.3336-.81125.757-1.48307 1.2702-2.01545.528-.52161 1.1175-.92155 1.7687-1.1998-2.0728-1.70651-4.7279-2.73128-7.6223-2.73128-6.62742 0-12 5.37258-12 12 0 6.6274 5.37258 12 12 12zm-3.53811-18.05347c-.30793.78589-.46189 1.73658-.46189 2.85205v5.01962h5.6197v-5.59004h-2.5789v-.07605c0-1.01406.2566-1.82531.7698-2.43375.5389-.63379 1.1804-1.05209 1.9245-1.2549v-2.28164c-.7441.07605-1.4626.25351-2.1555.53238-.6928.27887-1.3086.68449-1.84752 1.21688-.51321.53238-.9366 1.2042-1.27019 2.01545z' fill='currentColor' fill-rule='evenodd'/></svg></i><p	class='typography typography--size-36-text js-typography blockquote__quote'
	data-id='es-1136'
	>
	Even though it’s still very young, Flutter has already shown that it is destined to become a cross-platform behemoth.</p>
		<div class="blockquote__caption-wrap">
					</div>
	</div>
</div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1141"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-1139">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-1140'
	>
	If you’re opting for a cross-platform solution in 2020, your other possible options would be the Facebook backed <strong><a href="https://facebook.github.io/react-native/">React Native</a></strong> or Microsoft’s <strong><a href="https://dotnet.microsoft.com/apps/xamarin">Xamarin</a></strong>.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1144"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-1142">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-1143'
	>
	There used to be some other solutions but most of them are either dead, or about to draw their last breath.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1147"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-1145">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-1146'
	>
	There have been a plethora of well-written technical articles explaining the differences between those mentioned technologies (e.g. <a href="https://infinum.com/blog/flutter-might-be-your-technology-of-choice-for-mobile-in-2020/">this one </a>), so there’s no need to get into that here.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1150"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-1148">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-1149'
	>
	What you need to know is that all of them <strong>focus on providing “next-to-native” performance</strong>. Sure, not everything will be as pixel-perfect when compared to a fully native approach. However, nowadays, you really have to pixel-peep to find those wrinkles.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1153"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-1151">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-1152'
	>
	The existence of such cross-platform technologies doesn’t mean there is no more use for completely native ones. They provide you with a (still) unparalleled look and feel, but also require a significant amount of work to build both the iOS and Android versions. It’s up to you to decide which option fits your needs better.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1156"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-1154">
	<h3	class='typography typography--size-36-text js-typography block-heading__heading'
	data-id='es-1155'
	>
	Scenarios that require a native approach</h3></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1159"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-1157">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-1158'
	>
	Something you should also keep in mind when making that decision is that <strong>there are cases for which a native approach is a must</strong>, and it doesn’t seem likely this will change in the foreseeable future. These would be apps that:</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1162"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="lists" data-id="es-1160">
	<ul	class='typography typography--size-16-text-roman js-typography lists__typography'
	data-id='es-1161'
	>
	<li>integrate multiple other frameworks and SDKs (like some large scale banking apps),</li><li>communicate with any external hardware by using low-level technologies such as Bluetooth, NFC etc.,</li><li>depend on platform-specific APIs (e.g. AR apps or apps which use Apple Pay).</li></ul></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1165"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-1163">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-1164'
	>
	If your app doesn’t fit any of those descriptions, cross-platform might be the solution you’re looking for. We believe this approach <strong>works best for small and medium size applications</strong>, or when your content and basic features require constant iteration.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1168"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-1166">
	<h2	class='typography typography--size-52-default js-typography block-heading__heading'
	data-id='es-1167'
	>
	Let’s build something beautiful with Flutter</h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1171"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-1169">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-1170'
	>
	As you can see, there are no silver bullets when it comes to programming, as well as general problem solving. Every project we encounter requires careful architectural planning, as well as choosing the right technology which will lay at its foundation.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1174"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-1172">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-1173'
	>
	In the past, we’ve mostly gone for the native approach, but seeing how <strong>Flutter is shaping up to be a worthy solution for many possible use cases</strong>, we’ve started offering it to our clients as well.&nbsp;</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1177"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-1175">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-1176'
	>
	If you’re inspired to make a leap forward in 2020 and build something exciting and beautiful, don’t hesitate to <a href="https://infinum.com/contact/">drop us a line</a>.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1180"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-1178">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-1179'
	>
	After all, the future of your business lies in the smart utilization of technology and software, not the horoscope.</p></div>	</div>
</div>
</div>		</div>
	</div><p>The post <a href="https://infinum.com/blog/forget-the-year-of-the-rat-2020-belongs-to-flutter/">Forget the Year of the Rat, 2020 Belongs to Flutter</a> appeared first on <a href="https://infinum.com">Infinum</a>.</p>
]]>
				</content:encoded>
			</item>
					<item>
				<image>
					<url>8110https://infinum.com/uploads/2019/11/easy-way-to-implement-demo-mode-in-ios-apps-0.webp</url>
				</image>
				<title>Easy Way to Implement Demo Mode in iOS Apps</title>
				<link>https://infinum.com/blog/easy-way-to-implement-demo-mode-in-ios-apps/</link>
				<pubDate>Wed, 20 Nov 2019 12:10:00 +0000</pubDate>
				<dc:creator>Goran Brlas</dc:creator>
				<guid isPermaLink="false">https://infinum.com/the-capsized-eight/easy-way-to-implement-demo-mode-in-ios-apps/</guid>
				<description>
					<![CDATA[<p>Ever thought about adding demo mode to your application?Probably not. But there are many scenarios when the demo mode comes in handy.</p>
<p>The post <a href="https://infinum.com/blog/easy-way-to-implement-demo-mode-in-ios-apps/">Easy Way to Implement Demo Mode in iOS Apps</a> appeared first on <a href="https://infinum.com">Infinum</a>.</p>
]]>
				</description>
				<content:encoded>
					<![CDATA[<div
	class="wrapper"
	data-id="es-1322"
	 data-animation-target='inner-items'>
		
			<div class="wrapper__inner">
			<div class="block-blog-content js-block-blog-content">
	
<div class="block-blog-content-sidebar" data-id="es-1183">
	</div>

<div class="block-blog-content-main">
	
<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1186"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-1184">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-1185'
	>
	Ever thought about adding demo mode to your application? If I were guessing, I’d say most of you probably haven’t. It’s not a bad thing, it just means you haven’t yet encountered a problem or use case requiring you to build one. However, there are a lot of scenarios when the demo mode comes in handy.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1189"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-1187">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-1188'
	>
	In this article, I’ll show you that <strong>implementing a demo mode doesn’t require a lot of time</strong>, all the while keeping your existing logic pretty much intact. While we’re at it, the solution I’m going to show you will also make your development life easier in cases where the API is still work in progress, or just flat out refusing to cooperate.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1192"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-1190">
	<h2	class='typography typography--size-52-default js-typography block-heading__heading'
	data-id='es-1191'
	>
	Demo mode use cases</h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1195"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-1193">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-1194'
	>
	One example that comes to mind would be in AppStore reviews for apps which require a login but can’t really provide a test user. Think of all the banking apps that require users to be legal entities in the app’s origination country.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1198"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-1196">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-1197'
	>
	Other use cases could be apps that would like to show off their premium features without providing a trial period, or maybe those with sensitive data management that would like to familiarize their users with the application’s feature flow before throwing them into the “lion’s den”.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1201"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-1199">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-1200'
	>
	My team has encountered similar cases in the projects we’ve worked on, so we had to come up with a <strong>scalable and maintainable</strong> way of making it work.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1204"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-1202">
	<h2	class='typography typography--size-52-default js-typography block-heading__heading'
	data-id='es-1203'
	>
	Implementing demo mode inside an app</h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1207"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-1205">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-1206'
	>
	When starting to think about implementing demo mode inside an app, your first thought might be to add an additional parameter to your API call site specifying whether the call should be executed or mocked.&nbsp;</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1210"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-1208">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-1209'
	>
	This would work, but it would also require a lot of “copypasta”, and every new API call you implement should also have the same logic. Since we’re aiming for scalability and maintainability, this approach isn’t the way to go. As your app grows, it would introduce a lot of switch-cases and logic duplication and frankly, it would get tiring quickly.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1213"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-1211">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-1212'
	>
	That is why we’ve decided to make something better  -  a <strong>demo manager</strong>.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1218"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="blockquote block-blockquote__blockquote" data-id="es-1214">
	
	<div class="blockquote__content">
		<i
	class="icon blockquote__icon icon--size-16 icon--scale-100"
	 aria-hidden='true' data-name='blockquote-24' data-id='es-1215'>
	<svg fill='none' height='24' viewBox='0 0 24 24' width='24' xmlns='http://www.w3.org/2000/svg'><path clip-rule='evenodd' d='m12 24c6.6274 0 12-5.3726 12-12 0-2.79685-.9568-5.37021-2.561-7.41062-.581.22951-1.0832.60583-1.5069 1.12898-.5132.60844-.7698 1.41969-.7698 2.43375v.07605h2.5789v5.59004h-5.6197v-5.01962c0-1.11547.154-2.06616.4619-2.85205.3336-.81125.757-1.48307 1.2702-2.01545.528-.52161 1.1175-.92155 1.7687-1.1998-2.0728-1.70651-4.7279-2.73128-7.6223-2.73128-6.62742 0-12 5.37258-12 12 0 6.6274 5.37258 12 12 12zm-3.53811-18.05347c-.30793.78589-.46189 1.73658-.46189 2.85205v5.01962h5.6197v-5.59004h-2.5789v-.07605c0-1.01406.2566-1.82531.7698-2.43375.5389-.63379 1.1804-1.05209 1.9245-1.2549v-2.28164c-.7441.07605-1.4626.25351-2.1555.53238-.6928.27887-1.3086.68449-1.84752 1.21688-.51321.53238-.9366 1.2042-1.27019 2.01545z' fill='currentColor' fill-rule='evenodd'/></svg></i><p	class='typography typography--size-36-text js-typography blockquote__quote'
	data-id='es-1216'
	>
	You’re probably thinking “Another manager? But I’ve already got a ton of them and I’ve read several blog posts telling me that they’re bad”.</p>
		<div class="blockquote__caption-wrap">
					</div>
	</div>
</div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1221"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-1219">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-1220'
	>
	This could be a common response to my proposal since developers like to introduce managers everywhere, even in places where they don’t really make much sense. But bear with me for a minute, this is a use case where a manager fits like a glove.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1224"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-1222">
	<h2	class='typography typography--size-52-default js-typography block-heading__heading'
	data-id='es-1223'
	>
	The hidden gems</h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1227"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-1225">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-1226'
	>
	Our demo manager appears quite basic when you look at it from the outside. After all, it only has a single state parameter <code>isEnabled</code> telling us whether our API calls are being actively mocked or not. However, its <em>”hidden”</em> responsibilities are where the money’s at, so let’s take a look at them.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1230"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-1228">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-1229'
	>
	The first responsibility is <strong>hooking onto every API call</strong> your application makes, while the second one builds upon the first one by <strong>filtering those API calls</strong> in the following way:</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1233"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="lists" data-id="es-1231">
	<ul	class='typography typography--size-16-text-roman js-typography lists__typography'
	data-id='es-1232'
	>
	<li>if it should be mocked -&gt; read the response from a stored file and forward it as a response to your business logic,</li><li>if it shouldn’t be mocked -&gt; make an API call to the server (same as before).</li></ul></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1236"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-1234">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-1235'
	>
	For API call mocking, we’re going to use <a href="https://github.com/AliSoftware/OHHTTPStubs">OHTTPStubs</a>, a library designed to stub network requests by using method swizzling. It works with <code>NSURLConnection, NSURLSession, AFNetworking, Alamofire</code> or any networking framework that uses Cocoa’s URL Loading System, so it’s perfect for our use case.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1239"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-1237">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-1238'
	>
	Of course, if you don’t like adding pods to your projects, you could implement your own hooking logic, but that isn’t the point of this tutorial so I’ll leave that to the brave.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1242"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-1240">
	<h2	class='typography typography--size-52-default js-typography block-heading__heading'
	data-id='es-1241'
	>
	Getting down to the code</h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1245"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-1243">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-1244'
	>
	Now that we’ve covered the <em>what</em> and <em>why</em>, let’s move on to the <em>how</em>. We’ll start with the top-down approach, building our demo manager in several steps.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1247"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-code">
	<pre class="phiki language-swift github-light" data-language="swift" style="background-color: #fff;color: #24292e;"><code><span class="line"><span class="token" style="color: #d73a49;">import</span><span class="token"> </span><span class="token" style="color: #6f42c1;">UIKit</span><span class="token">
</span></span><span class="line"><span class="token" style="color: #d73a49;">import</span><span class="token"> </span><span class="token" style="color: #6f42c1;">OHHTTPStubs</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token">class DemoManager</span><span class="token"> </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token" style="color: #d73a49;">static</span><span class="token"> </span><span class="token" style="color: #d73a49;">var</span><span class="token"> instance </span><span class="token" style="color: #d73a49;">=</span><span class="token"> </span><span class="token">DemoManager(</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token">var isEnabled:</span><span class="token"> </span><span class="token" style="color: #005cc5;">Bool</span><span class="token"> </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">        </span><span class="token" style="color: #d73a49;">get</span><span class="token"> </span><span class="token">{</span><span class="token"> </span><span class="token" style="color: #d73a49;">return</span><span class="token"> </span><span class="token" style="color: #d73a49;">!</span><span class="token">OHHTTPStubs.</span><span class="token">allStubs(</span><span class="token">)</span><span class="token">.</span><span class="token" style="color: #005cc5;">isEmpty</span><span class="token"> </span><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">        </span><span class="token" style="color: #d73a49;">set</span><span class="token"> </span><span class="token">(</span><span class="token">newValue</span><span class="token">)</span><span class="token"> </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">            </span><span class="token" style="color: #d73a49;">switch</span><span class="token"> newValue </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">            </span><span class="token" style="color: #d73a49;">case</span><span class="token"> </span><span class="token" style="color: #005cc5;">true</span><span class="token" style="color: #d73a49;">:</span><span class="token"> </span><span class="token">setupStubResponses(</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">            </span><span class="token" style="color: #d73a49;">case</span><span class="token"> </span><span class="token" style="color: #005cc5;">false</span><span class="token" style="color: #d73a49;">:</span><span class="token"> OHHTTPStubs.</span><span class="token">removeAllStubs(</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">            </span><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">        </span><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token" style="color: #d73a49;">private</span><span class="token"> </span><span class="token" style="color: #d73a49;">init</span><span class="token">(</span><span class="token">)</span><span class="token"> </span><span class="token">{</span><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span></code></pre></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1250"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-1248">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-1249'
	>
	As you can see, our demo manager is a singleton, with one variable for switching the mocking on/off. It might look simple, but this single point of entry provides us with great flexibility . If you want to mock everything in the application, all you have to do is just set the <code>isEnabled</code> parameter to true when the application starts and you’re golden.&nbsp;</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1253"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-1251">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-1252'
	>
	However, if you want a bit more specificity, you have free reign to do so. For example, your API call mocking can start only when you get to a screen which still doesn’t have an API implementation ready on the backend side, and can be turned off when you navigate off this screen.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1255"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-code">
	<pre class="phiki language-swift github-light" data-language="swift" style="background-color: #fff;color: #24292e;"><code><span class="line"><span class="token" style="color: #d73a49;">private</span><span class="token"> </span><span class="token" style="color: #d73a49;">extension</span><span class="token"> </span><span class="token" style="color: #6f42c1;">DemoManager</span><span class="token"> </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token">func setupStubResponses</span><span class="token">(</span><span class="token">)</span><span class="token"> </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">        </span><span class="token">stubSomething(</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">        </span><span class="token">stubUpdatingSomething(</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">        </span><span class="token">stubSomethingWithPagination(</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token">func stubSomething</span><span class="token">(</span><span class="token">)</span><span class="token"> </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">        </span><span class="token">stubResponse(</span><span class="token">
</span></span><span class="line"><span class="token">            </span><span class="token">containing:</span><span class="token"> </span><span class="token" style="color: #032f62;">&quot;</span><span class="token" style="color: #032f62;">/apiPath/somethingMockedPath</span><span class="token" style="color: #032f62;">&quot;</span><span class="token">,
</span></span><span class="line"><span class="token">            </span><span class="token">statusCode:</span><span class="token"> </span><span class="token" style="color: #005cc5;">200</span><span class="token">,
</span></span><span class="line"><span class="token">            </span><span class="token">from:</span><span class="token"> </span><span class="token" style="color: #032f62;">&quot;</span><span class="token" style="color: #032f62;">something_mocked</span><span class="token" style="color: #032f62;">&quot;</span><span class="token">
</span></span><span class="line"><span class="token">        </span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token">func stubUpdatingSomething</span><span class="token">(</span><span class="token">)</span><span class="token"> </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">        </span><span class="token">stubResponse(</span><span class="token">
</span></span><span class="line"><span class="token">            </span><span class="token">containing:</span><span class="token"> </span><span class="token" style="color: #032f62;">&quot;</span><span class="token" style="color: #032f62;">/apiPath/somethingToUpdate</span><span class="token" style="color: #032f62;">&quot;</span><span class="token">,
</span></span><span class="line"><span class="token">            </span><span class="token">method:</span><span class="token"> .</span><span class="token">patch</span><span class="token">,
</span></span><span class="line"><span class="token">            </span><span class="token">statusCode:</span><span class="token"> </span><span class="token" style="color: #005cc5;">200</span><span class="token">
</span></span><span class="line"><span class="token">        </span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token">func stubSomethingWithPagination</span><span class="token">(</span><span class="token">)</span><span class="token"> </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">        </span><span class="token">stubResponse(</span><span class="token">
</span></span><span class="line"><span class="token">            </span><span class="token">containing:</span><span class="token"> </span><span class="token" style="color: #032f62;">&quot;</span><span class="token" style="color: #032f62;">/apiPath/somethingPaginated</span><span class="token" style="color: #032f62;">&quot;</span><span class="token">,
</span></span><span class="line"><span class="token">            </span><span class="token">queryParamPart:</span><span class="token"> </span><span class="token" style="color: #032f62;">&quot;</span><span class="token" style="color: #032f62;">cursor=0</span><span class="token" style="color: #032f62;">&quot;</span><span class="token">,
</span></span><span class="line"><span class="token">            </span><span class="token">statusCode:</span><span class="token"> </span><span class="token" style="color: #005cc5;">200</span><span class="token">,
</span></span><span class="line"><span class="token">            </span><span class="token">from:</span><span class="token"> </span><span class="token" style="color: #032f62;">&quot;</span><span class="token" style="color: #032f62;">something_paginated_first_page</span><span class="token" style="color: #032f62;">&quot;</span><span class="token">
</span></span><span class="line"><span class="token">        </span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token">        </span><span class="token">stubResponse(</span><span class="token">
</span></span><span class="line"><span class="token">            </span><span class="token">containing:</span><span class="token"> </span><span class="token" style="color: #032f62;">&quot;</span><span class="token" style="color: #032f62;">/apiPath/somethingPaginated</span><span class="token" style="color: #032f62;">&quot;</span><span class="token">,
</span></span><span class="line"><span class="token">            </span><span class="token">queryParamPart:</span><span class="token"> </span><span class="token" style="color: #032f62;">&quot;</span><span class="token" style="color: #032f62;">cursor=1</span><span class="token" style="color: #032f62;">&quot;</span><span class="token">,
</span></span><span class="line"><span class="token">            </span><span class="token">statusCode:</span><span class="token"> </span><span class="token" style="color: #005cc5;">200</span><span class="token">,
</span></span><span class="line"><span class="token">            </span><span class="token">from:</span><span class="token"> </span><span class="token" style="color: #032f62;">&quot;</span><span class="token" style="color: #032f62;">something_paginated_second_page</span><span class="token" style="color: #032f62;">&quot;</span><span class="token">
</span></span><span class="line"><span class="token">        </span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span></code></pre></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1258"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-1256">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-1257'
	>
	Here we can see the implementation of our <code>setupStubResponses()</code> method.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1261"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-1259">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-1260'
	>
	It stubs different API calls with responses from JSON files – <em>something_mocked</em>, <em>something_paginated_first_page</em> and <em>something_paginated_second_page</em>, while the second call is mocked with just a 200 code telling us that the update was successful.&nbsp;</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1264"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-1262">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-1263'
	>
	Each call is mocked using the <code>stubResponse()</code> method with individual filtering parameters. To understand that there isn’t some black box magic involved, let’s take a look at what’s going on under the hood here.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1266"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-code">
	<pre class="phiki language-swift github-light" data-language="swift" style="background-color: #fff;color: #24292e;"><code><span class="line"><span class="token" style="color: #d73a49;">private</span><span class="token"> </span><span class="token" style="color: #d73a49;">extension</span><span class="token"> </span><span class="token" style="color: #6f42c1;">DemoManager</span><span class="token"> </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token">     </span><span class="token" style="color: #6a737d;">/**</span><span class="token" style="color: #6a737d;">
</span></span><span class="line"><span class="token" style="color: #6a737d;">     Used for creating stubs for API mocking.
</span></span><span class="line"><span class="token" style="color: #6a737d;">     For distinguishing which stub should be used for which API call you should use the following parameters:
</span></span><span class="line"><span class="token" style="color: #6a737d;">        - `urlPart`
</span></span><span class="line"><span class="token" style="color: #6a737d;">        - `queryParamPart`
</span></span><span class="line"><span class="token" style="color: #6a737d;">        - `requiredHeaderValues`
</span></span><span class="line"><span class="token" style="color: #6a737d;">        - `method`
</span></span><span class="line"><span class="token" style="color: #6a737d;">     Successfuly mocked response is defined by:
</span></span><span class="line"><span class="token" style="color: #6a737d;">        - `statusCode`
</span></span><span class="line"><span class="token" style="color: #6a737d;">        - `headers`
</span></span><span class="line"><span class="token" style="color: #6a737d;">        - `fileName`
</span></span><span class="line"><span class="token" style="color: #6a737d;">     - Parameter urlPart: Specifies URL path that should be mocked
</span></span><span class="line"><span class="token" style="color: #6a737d;">     - Parameter queryParamPart: Used for mocking calls with specific query parameters
</span></span><span class="line"><span class="token" style="color: #6a737d;">     - Parameter requiredHeaderValues: Used for mocking calls with specific header values, i.e. can be used for differentiating multiple API calls only by the values in their headers
</span></span><span class="line"><span class="token" style="color: #6a737d;">     - Parameter body: Used for mocking calls with specific parameters in their body
</span></span><span class="line"><span class="token" style="color: #6a737d;">     - Parameter method: The HTTP request method
</span></span><span class="line"><span class="token" style="color: #6a737d;">     - Parameter statusCode: Mocked response status code (can be used for mocking errors)
</span></span><span class="line"><span class="token" style="color: #6a737d;">     - Parameter headers: Header values sent in mocked response
</span></span><span class="line"><span class="token" style="color: #6a737d;">     - Parameter fileName: JSON file from which response data should be read
</span></span><span class="line"><span class="token" style="color: #6a737d;">     </span><span class="token" style="color: #6a737d;">*/</span><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token">func stubResponse</span><span class="token">(</span><span class="token">
</span></span><span class="line"><span class="token">        </span><span class="token">containing urlPart</span><span class="token">: </span><span class="token" style="color: #005cc5;">String</span><span class="token">,
</span></span><span class="line"><span class="token">        </span><span class="token">queryParamPart</span><span class="token">: </span><span class="token" style="color: #005cc5;">String</span><span class="token" style="color: #d73a49;">?</span><span class="token"> </span><span class="token" style="color: #d73a49;">=</span><span class="token"> </span><span class="token" style="color: #005cc5;">nil</span><span class="token">,
</span></span><span class="line"><span class="token">        </span><span class="token">requiredHeaderValues</span><span class="token">: </span><span class="token" style="color: #005cc5;">String</span><span class="token" style="color: #d73a49;">?</span><span class="token" style="color: #d73a49;">...</span><span class="token">,
</span></span><span class="line"><span class="token">        </span><span class="token">bodyPart</span><span class="token">: </span><span class="token">[</span><span class="token" style="color: #005cc5;">String</span><span class="token">]</span><span class="token" style="color: #d73a49;">?</span><span class="token"> </span><span class="token" style="color: #d73a49;">=</span><span class="token"> </span><span class="token" style="color: #005cc5;">nil</span><span class="token">,
</span></span><span class="line"><span class="token">        </span><span class="token">method</span><span class="token">: </span><span class="token">HTTPMethod</span><span class="token" style="color: #d73a49;">?</span><span class="token"> </span><span class="token" style="color: #d73a49;">=</span><span class="token"> .</span><span class="token">get</span><span class="token">,
</span></span><span class="line"><span class="token">        </span><span class="token">statusCode</span><span class="token">: </span><span class="token" style="color: #005cc5;">Int32</span><span class="token"> </span><span class="token" style="color: #d73a49;">=</span><span class="token"> </span><span class="token" style="color: #005cc5;">200</span><span class="token">,
</span></span><span class="line"><span class="token">        </span><span class="token">headers</span><span class="token">: </span><span class="token">[</span><span class="token" style="color: #005cc5;">AnyHashable</span><span class="token"> </span><span class="token">:</span><span class="token"> </span><span class="token" style="color: #005cc5;">Any</span><span class="token">]</span><span class="token" style="color: #d73a49;">?</span><span class="token"> </span><span class="token" style="color: #d73a49;">=</span><span class="token"> [</span><span class="token" style="color: #032f62;">&quot;</span><span class="token" style="color: #032f62;">Content-Type</span><span class="token" style="color: #032f62;">&quot;</span><span class="token" style="color: #d73a49;">:</span><span class="token"> </span><span class="token" style="color: #032f62;">&quot;</span><span class="token" style="color: #032f62;">application/json</span><span class="token" style="color: #032f62;">&quot;</span><span class="token">]</span><span class="token">,
</span></span><span class="line"><span class="token">        </span><span class="token">from fileName</span><span class="token">: </span><span class="token" style="color: #005cc5;">String</span><span class="token" style="color: #d73a49;">?</span><span class="token"> </span><span class="token" style="color: #d73a49;">=</span><span class="token"> </span><span class="token" style="color: #005cc5;">nil</span><span class="token">
</span></span><span class="line"><span class="token">        </span><span class="token">)</span><span class="token"> </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token">        </span><span class="token">stub(</span><span class="token">
</span></span><span class="line"><span class="token">            </span><span class="token">condition:</span><span class="token"> </span><span class="token">{</span><span class="token"> </span><span class="token">(</span><span class="token">request:</span><span class="token"> URLRequest</span><span class="token">)</span><span class="token"> </span><span class="token" style="color: #d73a49;">-&gt;</span><span class="token"> </span><span class="token" style="color: #005cc5;">Bool</span><span class="token"> </span><span class="token" style="color: #d73a49;">in</span><span class="token">
</span></span><span class="line"><span class="token">                </span><span class="token" style="color: #6a737d;">//</span><span class="token" style="color: #6a737d;">Method</span><span class="token">
</span></span><span class="line"><span class="token">                </span><span class="token" style="color: #d73a49;">if</span><span class="token"> </span><span class="token" style="color: #d73a49;">let</span><span class="token"> method </span><span class="token" style="color: #d73a49;">=</span><span class="token"> method</span><span class="token" style="color: #d73a49;">?</span><span class="token">.</span><span class="token" style="color: #005cc5;">rawValue</span><span class="token">.</span><span class="token" style="color: #005cc5;">uppercased</span><span class="token">(</span><span class="token">)</span><span class="token">, 
</span></span><span class="line"><span class="token">                        request.httpMethod</span><span class="token" style="color: #d73a49;">?</span><span class="token">.</span><span class="token" style="color: #005cc5;">uppercased</span><span class="token">(</span><span class="token">)</span><span class="token"> </span><span class="token" style="color: #d73a49;">!=</span><span class="token"> method 
</span></span><span class="line"><span class="token">                        </span><span class="token">{</span><span class="token"> </span><span class="token" style="color: #d73a49;">return</span><span class="token"> </span><span class="token" style="color: #005cc5;">false</span><span class="token"> </span><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token">                </span><span class="token" style="color: #6a737d;">//</span><span class="token" style="color: #6a737d;">URL, query</span><span class="token">
</span></span><span class="line"><span class="token">                </span><span class="token" style="color: #d73a49;">if</span><span class="token"> </span><span class="token" style="color: #d73a49;">!</span><span class="token">(</span><span class="token">request.</span><span class="token" style="color: #005cc5;">url</span><span class="token" style="color: #d73a49;">?</span><span class="token">.</span><span class="token">absoluteString</span><span class="token">.</span><span class="token" style="color: #005cc5;">contains</span><span class="token">(</span><span class="token">urlPart</span><span class="token">)</span><span class="token"> </span><span class="token" style="color: #d73a49;">??</span><span class="token"> </span><span class="token" style="color: #005cc5;">false</span><span class="token">)</span><span class="token"> </span><span class="token">{</span><span class="token"> </span><span class="token" style="color: #d73a49;">return</span><span class="token"> </span><span class="token" style="color: #005cc5;">false</span><span class="token"> </span><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">                </span><span class="token" style="color: #d73a49;">if</span><span class="token"> </span><span class="token" style="color: #d73a49;">let</span><span class="token"> part </span><span class="token" style="color: #d73a49;">=</span><span class="token"> queryParamPart, 
</span></span><span class="line"><span class="token">                        </span><span class="token" style="color: #d73a49;">!</span><span class="token">(</span><span class="token">request.</span><span class="token" style="color: #005cc5;">url</span><span class="token" style="color: #d73a49;">?</span><span class="token">.</span><span class="token">absoluteString</span><span class="token">.</span><span class="token" style="color: #005cc5;">contains</span><span class="token">(</span><span class="token">part</span><span class="token">)</span><span class="token"> </span><span class="token" style="color: #d73a49;">??</span><span class="token"> </span><span class="token" style="color: #005cc5;">false</span><span class="token">)</span><span class="token"> 
</span></span><span class="line"><span class="token">                        </span><span class="token">{</span><span class="token"> </span><span class="token" style="color: #d73a49;">return</span><span class="token"> </span><span class="token" style="color: #005cc5;">false</span><span class="token"> </span><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token">                </span><span class="token" style="color: #6a737d;">//</span><span class="token" style="color: #6a737d;">Body</span><span class="token">
</span></span><span class="line"><span class="token">                </span><span class="token" style="color: #d73a49;">if</span><span class="token"> </span><span class="token" style="color: #d73a49;">let</span><span class="token"> parts </span><span class="token" style="color: #d73a49;">=</span><span class="token"> bodyPart,
</span></span><span class="line"><span class="token">                    </span><span class="token" style="color: #d73a49;">let</span><span class="token"> data </span><span class="token" style="color: #d73a49;">=</span><span class="token"> request.httpBody,
</span></span><span class="line"><span class="token">                    </span><span class="token" style="color: #d73a49;">let</span><span class="token"> body </span><span class="token" style="color: #d73a49;">=</span><span class="token"> </span><span class="token" style="color: #005cc5;">String</span><span class="token">(</span><span class="token">data:</span><span class="token"> data</span><span class="token">, </span><span class="token">encoding:</span><span class="token"> .</span><span class="token" style="color: #005cc5;">utf8</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">                </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">                    </span><span class="token" style="color: #d73a49;">let</span><span class="token"> bodyPartsPresent </span><span class="token" style="color: #d73a49;">=</span><span class="token"> parts
</span></span><span class="line"><span class="token">                        .</span><span class="token" style="color: #005cc5;">map</span><span class="token"> </span><span class="token">{</span><span class="token"> body.</span><span class="token" style="color: #005cc5;">contains</span><span class="token">(</span><span class="token" style="color: #005cc5;">$0</span><span class="token">)</span><span class="token"> </span><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">                        .</span><span class="token" style="color: #005cc5;">reduce</span><span class="token">(</span><span class="token" style="color: #005cc5;">true</span><span class="token">)</span><span class="token"> </span><span class="token">{</span><span class="token"> </span><span class="token" style="color: #005cc5;">$0</span><span class="token"> </span><span class="token" style="color: #d73a49;">&amp;&amp;</span><span class="token"> </span><span class="token" style="color: #005cc5;">$1</span><span class="token"> </span><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token">                    </span><span class="token" style="color: #d73a49;">if</span><span class="token"> </span><span class="token" style="color: #d73a49;">!</span><span class="token">bodyPartsPresent </span><span class="token">{</span><span class="token"> </span><span class="token" style="color: #d73a49;">return</span><span class="token"> </span><span class="token" style="color: #005cc5;">false</span><span class="token"> </span><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">                </span><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token">                </span><span class="token" style="color: #6a737d;">//</span><span class="token" style="color: #6a737d;">Headers</span><span class="token">
</span></span><span class="line"><span class="token">                </span><span class="token" style="color: #d73a49;">let</span><span class="token"> headers </span><span class="token" style="color: #d73a49;">=</span><span class="token"> request.</span><span class="token">allHTTPHeaderFields</span><span class="token"> </span><span class="token" style="color: #d73a49;">??</span><span class="token"> [</span><span class="token" style="color: #d73a49;">:</span><span class="token">]
</span></span><span class="line"><span class="token">                </span><span class="token" style="color: #d73a49;">let</span><span class="token"> headersOk </span><span class="token" style="color: #d73a49;">=</span><span class="token"> requiredHeaderValues
</span></span><span class="line"><span class="token">                    .</span><span class="token">compactMap</span><span class="token"> </span><span class="token">{</span><span class="token"> </span><span class="token" style="color: #005cc5;">$0</span><span class="token"> </span><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">                    .</span><span class="token" style="color: #005cc5;">map</span><span class="token"> </span><span class="token">{</span><span class="token"> </span><span class="token">(</span><span class="token">headerValue</span><span class="token">)</span><span class="token"> </span><span class="token" style="color: #d73a49;">in</span><span class="token"> headers.</span><span class="token" style="color: #005cc5;">contains</span><span class="token"> </span><span class="token">{</span><span class="token"> </span><span class="token" style="color: #005cc5;">$0</span><span class="token">.</span><span class="token" style="color: #005cc5;">value</span><span class="token"> </span><span class="token" style="color: #d73a49;">==</span><span class="token"> headerValue </span><span class="token">}</span><span class="token"> </span><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">                    .</span><span class="token" style="color: #005cc5;">reduce</span><span class="token">(</span><span class="token" style="color: #005cc5;">true</span><span class="token">)</span><span class="token"> </span><span class="token">{</span><span class="token"> </span><span class="token" style="color: #005cc5;">$0</span><span class="token"> </span><span class="token" style="color: #d73a49;">&amp;&amp;</span><span class="token"> </span><span class="token" style="color: #005cc5;">$1</span><span class="token"> </span><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token">                </span><span class="token" style="color: #d73a49;">if</span><span class="token"> </span><span class="token" style="color: #d73a49;">!</span><span class="token">headersOk </span><span class="token">{</span><span class="token"> </span><span class="token" style="color: #d73a49;">return</span><span class="token"> </span><span class="token" style="color: #005cc5;">false</span><span class="token"> </span><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token">                </span><span class="token" style="color: #d73a49;">return</span><span class="token"> </span><span class="token" style="color: #005cc5;">true</span><span class="token">
</span></span><span class="line"><span class="token">            </span><span class="token">}</span><span class="token">,
</span></span><span class="line"><span class="token">            </span><span class="token">response:</span><span class="token"> </span><span class="token">{</span><span class="token"> </span><span class="token" style="color: #005cc5;">_</span><span class="token"> </span><span class="token" style="color: #d73a49;">-&gt;</span><span class="token"> OHHTTPStubsResponse </span><span class="token" style="color: #d73a49;">in</span><span class="token">
</span></span><span class="line"><span class="token">                </span><span class="token" style="color: #d73a49;">guard</span><span class="token"> </span><span class="token" style="color: #d73a49;">let</span><span class="token"> _fileName </span><span class="token" style="color: #d73a49;">=</span><span class="token"> fileName </span><span class="token" style="color: #d73a49;">else</span><span class="token"> </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">                    </span><span class="token" style="color: #d73a49;">return</span><span class="token"> </span><span class="token">OHHTTPStubsResponse(</span><span class="token">data:</span><span class="token"> </span><span class="token">Data(</span><span class="token">)</span><span class="token">, </span><span class="token">statusCode:</span><span class="token"> statusCode</span><span class="token">, </span><span class="token">headers:</span><span class="token"> </span><span class="token" style="color: #005cc5;">nil</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">                </span><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token">                </span><span class="token" style="color: #d73a49;">let</span><span class="token"> path </span><span class="token" style="color: #d73a49;">=</span><span class="token"> Bundle.</span><span class="token">main</span><span class="token">.</span><span class="token">path(</span><span class="token">forResource:</span><span class="token"> _fileName</span><span class="token">, </span><span class="token">ofType:</span><span class="token"> </span><span class="token" style="color: #032f62;">&quot;</span><span class="token" style="color: #032f62;">json</span><span class="token" style="color: #032f62;">&quot;</span><span class="token">)</span><span class="token"> </span><span class="token" style="color: #d73a49;">??</span><span class="token"> </span><span class="token" style="color: #032f62;">&quot;</span><span class="token" style="color: #032f62;">&quot;</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token">                </span><span class="token" style="color: #d73a49;">return</span><span class="token"> </span><span class="token">fixture(</span><span class="token">filePath:</span><span class="token"> path</span><span class="token">, </span><span class="token">status:</span><span class="token"> statusCode</span><span class="token">, </span><span class="token">headers:</span><span class="token"> headers</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">            </span><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">        </span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span></code></pre></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1269"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-1267">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-1268'
	>
	This method is basically what you’ve been waiting for. It calls <a href="https://github.com/AliSoftware/OHHTTPStubs">OHTTPStubs’s</a> <code>stub()</code> method which does the API call mocking using a <strong>condition closure</strong> and a <strong>response closure</strong>. Each of them plays a major part in mocking your calls, so let’s see what they’re all about.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1272"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-1270">
	<h3	class='typography typography--size-36-text js-typography block-heading__heading'
	data-id='es-1271'
	>
	Condition closure</h3></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1275"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-1273">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-1274'
	>
	You can <strong>think of the condition closure as a robust version of filtering</strong>. If it returns <strong>true</strong>, the response closure will be executed, the API call will be mocked and it will never reach the real server. Otherwise, if the condition closure results in <strong>false</strong>, the API call will be executed, just like before.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1278"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-1276">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-1277'
	>
	In our implementation, we go through several major pillars of every API call in order to determine whether we should mock it:</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1281"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="lists" data-id="es-1279">
	<ul	class='typography typography--size-16-text-roman js-typography lists__typography'
	data-id='es-1280'
	>
	<li><strong>API call URL</strong> – the only required parameter in our <code>stubResponse()</code> implementation, and it should match the one in the call itself. We’re using <code>contains()</code> to provide more flexibility here, but you can implement it using letter-to-letter precision or regexes if you wish to.</li><li><strong>queryParamPart</strong> – an optional parameter that defines whether the specific query parameter should appear in the API call in order to be mocked.</li><li><strong>requiredHeaderValues</strong> – optional array of header values that are required to be in the call, otherwise it shouldn’t be mocked.</li><li><strong>bodyPart</strong>  –  optional array of request body values, perfect for cases where your calls are only differentiated by their body parameters.</li><li><strong>method</strong> – specifies the request method, <code>GET</code> is set by default since it’s the most used one.</li></ul></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1284"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-1282">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-1283'
	>
	If all our checks are successful, our API call is filtered as <strong><em>”good for mocking”</em></strong> and the response closure is then finally called to mock the API call. Otherwise, if the condition closure fails at any of the the aforementioned conditions, the call is forwarded to the server – business as usual.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1287"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-1285">
	<h3	class='typography typography--size-36-text js-typography block-heading__heading'
	data-id='es-1286'
	>
	Response closure</h3></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1290"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-1288">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-1289'
	>
	The response closure is used to create the mocked response, and it uses three parameters passed into the <code>stubResponse()</code> – <code>statusCode</code>, <code>method</code> and <code>fileName</code>. We load our mocked response from the file in our bundle using the specified file name, set the headers to the provided values and create the mocked response using the status code.&nbsp;</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1293"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-1291">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-1292'
	>
	This allows us to test our implementation with several responses rather quickly. Want to know how your UI behaves if the array of products you’re expecting is empty? What’s going to happen if the API starts coughing up and returns <em>4xx</em> or <em>5xx</em>?</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1296"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-1294">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-1295'
	>
	Using the flexibility of call mocking shown here, you can run through all your test scenarios in a breeze, leaving you more time to focus on more important parts of your app.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1299"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-1297">
	<h2	class='typography typography--size-52-default js-typography block-heading__heading'
	data-id='es-1298'
	>
	One more thing</h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1302"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-1300">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-1301'
	>
	One thing not mentioned above is the usefulness of <a href="https://github.com/AliSoftware/OHHTTPStubs">OHTTPStubs</a> for writing unit tests (which all of us are doing, right?)</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1305"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-1303">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-1304'
	>
	It comes as a real time-saver when testing your business logic that depends on API call results, and all you need to make it happen is the <code>stubResponse()</code> implementation inside your testing environment.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1308"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-1306">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-1307'
	>
	You can do that in no time with the knowledge you’ve accrued. Doing that will not only help you with testing, but also make your apps more stable, resulting in happier customers and better app ratings.&nbsp;</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1311"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-1309">
	<h2	class='typography typography--size-52-default js-typography block-heading__heading'
	data-id='es-1310'
	>
	Wrapping it&nbsp;up</h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1314"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-1312">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-1313'
	>
	You’ve just witnessed that the demo manager really is a jack of all trades. It has a wide variety of uses, from showing everything your application has to offer without firing a single “real” API call, to making development faster while waiting for the API team to do their part by mocking the responses based on the agreed specification.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1317"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-1315">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-1316'
	>
	The best part is that it’s not difficult to implement, so give it a go and reap the benefits of the demo mode in your project.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1320"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-1318">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-1319'
	>
	Until next time, happy coding!</p></div>	</div>
</div>
</div>		</div>
	</div><p>The post <a href="https://infinum.com/blog/easy-way-to-implement-demo-mode-in-ios-apps/">Easy Way to Implement Demo Mode in iOS Apps</a> appeared first on <a href="https://infinum.com">Infinum</a>.</p>
]]>
				</content:encoded>
			</item>
					<item>
				<image>
					<url>7878https://infinum.com/uploads/2019/10/repository-full-of-our-best-practices-in-ios-development-0.webp</url>
				</image>
				<title>A Repository Full of Our Best Practices in iOS Development</title>
				<link>https://infinum.com/blog/repository-full-of-our-best-practices-in-ios-development/</link>
				<pubDate>Thu, 10 Oct 2019 11:27:00 +0000</pubDate>
				<dc:creator>Goran Brlas</dc:creator>
				<guid isPermaLink="false">https://infinum.com/the-capsized-eight/repository-full-of-our-best-practices-in-ios-development/</guid>
				<description>
					<![CDATA[<p>iOS projects come in all shapes and sizes, but the same pesky problems in them reappear like in that bunny hammer game.</p>
<p>The post <a href="https://infinum.com/blog/repository-full-of-our-best-practices-in-ios-development/">A Repository Full of Our Best Practices in iOS Development</a> appeared first on <a href="https://infinum.com">Infinum</a>.</p>
]]>
				</description>
				<content:encoded>
					<![CDATA[<div
	class="wrapper"
	data-id="es-1440"
	 data-animation-target='inner-items'>
		
			<div class="wrapper__inner">
			<div class="block-blog-content js-block-blog-content">
	
<div class="block-blog-content-sidebar" data-id="es-1323">
	</div>

<div class="block-blog-content-main">
	
<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1326"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-1324">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-1325'
	>
	Here’s a scenario fellow iOS developers will find familiar: iOS development projects you work on come in all shapes and sizes, but as varied as they get, the same pesky problems in them appear repeatedly. And just when you’ve solved a problem in one project, it reappears in the next one, like in that bunny hammer game.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1329"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-1327">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-1328'
	>
	We’ve had this happen time and time again at Infinum. Project after project, we would go through best practices and fixes we’ve implemented in the past (and which Apple still hasn’t implemented), copying the solution that worked in the last project into the new one, making any neccessary modifications.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1332"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-1330">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-1331'
	>
	Over time, this has morphed into a <strong>knowledge base that became our reference point for upcoming development projects</strong>. Now, we’re sharing it with the world so that other developers can stop copy/pasting from project to project, and find the solution in a centralized repository instead.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1335"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-1333">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-1334'
	>
	Say hello to <strong><a href="https://github.com/infinum/iOS-Nuts-And-Bolts">Nuts &amp; Bolts</a></strong>!</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1338"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-1336">
	<h2	class='typography typography--size-52-default js-typography block-heading__heading'
	data-id='es-1337'
	>
	All about that feature&nbsp;life</h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1341"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-1339">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-1340'
	>
	If you look at the repository, you’ll be able to find all the features inside the <strong>Sources</strong> folder. Each feature has its sample inside the catalog list which can be run and/or tests written for it, where you can find more info on the specific feature usage.&nbsp;</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1344"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-1342">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-1343'
	>
	Those features are currently split into 5 main domains, and we’ll go through the contents of each one.&nbsp;</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1347"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-1345">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-1346'
	>
	Most of these are written in Swift since that’s what we mostly use nowadays, but if you’re still using Obj-C don’t fret. There are some useful things in there for you to use as well. Also, if you have an Obj-C implementation which you think could be useful, please open a PR–we’re always open for suggestions.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1350"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-1348">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-1349'
	>
	Before we continue, please note that we <em>are</em> using some third party integrations through <a href="https://cocoapods.org">CocoaPods</a> to make our lives easier–we don’t always need to reinvent the wheel.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1353"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-1351">
	<h3	class='typography typography--size-36-text js-typography block-heading__heading'
	data-id='es-1352'
	>
	Networking made simple</h3></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1356"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-1354">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-1355'
	>
	As we all know, pretty much every app we build or use depends on some kind of networking in order to provide its full functionality to the user. From complex apps like banking ones all the way to simple workout tracking, networking is pretty much a must. In order to make it a breeze, we’ve added several useful properties to this feature folder:</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1359"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="lists" data-id="es-1357">
	<ul	class='typography typography--size-16-text-roman js-typography lists__typography'
	data-id='es-1358'
	>
	<li><strong>Router</strong>–Built on top of <em>Alamofire’s URLRequestConvertible</em>, <em>Routers</em> allow for easier separation of concerns when it comes to different API calls your application needs to make.</li><li><strong>Encoding</strong>–Used in conjuction with <em>Routers</em>, encoding features are used for creating request params with associated encoding.</li><li><strong>Adapters</strong>– For the times you need to athenticate your users. Our two adapters allow you to do just that, with support for basic authentication, as well as token-based ones.</li><li><strong>Service</strong>–Base protocol for API networking communication uses the previously desribed <em>Router</em> to make API calls.</li><li><strong>RxService</strong>–Reactive implementation of the Service mentioned above, where API calls are wrapped in <em>Singles</em> and <em>Completables</em>, whichever better fits your reactive needs.</li><li><strong>JSONAPI</strong>–Everything necessary to make your life easier when working with the <a href="https://jsonapi.org">JSON:API</a> standard.</li></ul></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1362"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-1360">
	<h3	class='typography typography--size-36-text js-typography block-heading__heading'
	data-id='es-1361'
	>
	RxSwift</h3></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1365"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-1363">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-1364'
	>
	We’re big fans of reactive programming here, and we use it in pretty much every project we’re currently supporting.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1368"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-1366">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-1367'
	>
	We know that <em>Combine</em> is knocking on the door, but the majority of the projects we’re actively working on will have a <strong>minimum device support lower than iOS 13 for some time</strong>, which is why RxSwift is here to stay for some time. Since it’s such a central tool in our toolbox, we decided to make it even better with some improvements.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1371"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-1369">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-1370'
	>
	<em>Observables</em> are their main building blocks, and with these they become even better:</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1373"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-code">
	<pre class="phiki language-swift github-light" data-language="swift" style="background-color: #fff;color: #24292e;"><code><span class="line"><span class="token" style="color: #d73a49;">public</span><span class="token"> </span><span class="token" style="color: #d73a49;">extension</span><span class="token"> </span><span class="token" style="color: #6f42c1;">ObservableType</span><span class="token"> </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token" style="color: #6a737d;">///</span><span class="token" style="color: #6a737d;"> Maps each sequence elements to given value.</span><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token" style="color: #6a737d;">///</span><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token" style="color: #6a737d;">///</span><span class="token" style="color: #6a737d;"> - Parameter value: Value to map</span><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token" style="color: #6a737d;">///</span><span class="token" style="color: #6a737d;"> - Returns: Sequence where all elements are given value.</span><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token">func mapTo</span><span class="token">&lt;</span><span class="token" style="color: #005cc5;">T</span><span class="token">&gt;</span><span class="token">(</span><span class="token">_ value</span><span class="token">: </span><span class="token">T</span><span class="token">)</span><span class="token"> </span><span class="token" style="color: #d73a49;">-&gt;</span><span class="token"> </span><span class="token">Observable</span><span class="token">&lt;</span><span class="token">T</span><span class="token">&gt;</span><span class="token"> </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">        </span><span class="token" style="color: #d73a49;">return</span><span class="token"> </span><span class="token">map</span><span class="token"> </span><span class="token">{</span><span class="token"> </span><span class="token" style="color: #005cc5;">_</span><span class="token"> </span><span class="token" style="color: #d73a49;">in</span><span class="token"> value </span><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token" style="color: #6a737d;">///</span><span class="token" style="color: #6a737d;"> Behaves like `take(n)`, but with predicate rather then a fixed number of next events.</span><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token" style="color: #6a737d;">///</span><span class="token" style="color: #6a737d;"> It will complete once predicate returns `false`.</span><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token" style="color: #6a737d;">///</span><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token" style="color: #6a737d;">///</span><span class="token" style="color: #6a737d;"> - Parameter predicate: Predicate function that will decide if we should continue or complete</span><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token" style="color: #6a737d;">///</span><span class="token" style="color: #6a737d;"> - Returns: Observable of type `E`.</span><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token">func takeUntil</span><span class="token">(</span><span class="token">predicate</span><span class="token">: </span><span class="token" style="color: #d73a49;">@escaping</span><span class="token"> </span><span class="token">(</span><span class="token" style="color: #005cc5;">Element</span><span class="token">)</span><span class="token"> </span><span class="token" style="color: #d73a49;">-&gt;</span><span class="token"> </span><span class="token" style="color: #005cc5;">Bool</span><span class="token">)</span><span class="token"> </span><span class="token" style="color: #d73a49;">-&gt;</span><span class="token"> </span><span class="token">Observable</span><span class="token">&lt;</span><span class="token" style="color: #005cc5;">Element</span><span class="token">&gt;</span><span class="token"> </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">        </span><span class="token" style="color: #d73a49;">return</span><span class="token"> Observable.</span><span class="token">create</span><span class="token"> </span><span class="token">{</span><span class="token"> observer </span><span class="token" style="color: #d73a49;">in</span><span class="token">
</span></span><span class="line"><span class="token">            </span><span class="token" style="color: #d73a49;">return</span><span class="token"> </span><span class="token" style="color: #005cc5;">self</span><span class="token">.</span><span class="token">subscribe</span><span class="token"> </span><span class="token">{</span><span class="token"> event </span><span class="token" style="color: #d73a49;">in</span><span class="token">
</span></span><span class="line"><span class="token">                </span><span class="token" style="color: #d73a49;">switch</span><span class="token"> event </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">                </span><span class="token" style="color: #d73a49;">case</span><span class="token"> .</span><span class="token" style="color: #005cc5;">next</span><span class="token">(</span><span class="token" style="color: #d73a49;">let</span><span class="token"> value</span><span class="token">)</span><span class="token" style="color: #d73a49;">:</span><span class="token">
</span></span><span class="line"><span class="token">                    observer.</span><span class="token">on(</span><span class="token">.</span><span class="token" style="color: #005cc5;">next</span><span class="token">(</span><span class="token">value</span><span class="token">)</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">                    </span><span class="token" style="color: #d73a49;">if</span><span class="token"> </span><span class="token" style="color: #d73a49;">!</span><span class="token">predicate(</span><span class="token">value</span><span class="token">)</span><span class="token"> </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">                        observer.</span><span class="token">on(</span><span class="token">.</span><span class="token">completed</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">                    </span><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">                </span><span class="token" style="color: #d73a49;">case</span><span class="token"> .</span><span class="token" style="color: #005cc5;">error</span><span class="token">(</span><span class="token" style="color: #d73a49;">let</span><span class="token"> error</span><span class="token">)</span><span class="token" style="color: #d73a49;">:</span><span class="token">
</span></span><span class="line"><span class="token">                    observer.</span><span class="token">on(</span><span class="token">.</span><span class="token" style="color: #005cc5;">error</span><span class="token">(</span><span class="token">error</span><span class="token">)</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">                </span><span class="token" style="color: #d73a49;">case</span><span class="token"> .</span><span class="token">completed</span><span class="token" style="color: #d73a49;">:</span><span class="token">
</span></span><span class="line"><span class="token">                    observer.</span><span class="token">on(</span><span class="token">.</span><span class="token">completed</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">                </span><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">            </span><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">        </span><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span></code></pre></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1376"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-1374">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-1375'
	>
	We haven’t forgotten about <em>Singles</em>, so be sure to give them some much needed love when you take a look at what’s in there.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1379"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-1377">
	<h3	class='typography typography--size-36-text js-typography block-heading__heading'
	data-id='es-1378'
	>
	RxCocoa</h3></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1382"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-1380">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-1381'
	>
	When talking about reactive programming for iOS, we can’t forget <em>RxCocoa</em>. It provides extensions to all things Cocoa, allowing them to take advantage of the reactive world.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1385"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-1383">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-1384'
	>
	If you use <em>Drivers</em> in your everyday life, these could be just what you’ve been looking for to drive your projects further than ever before. As you’ve probably noticed, we love our puns.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1387"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-code">
	<pre class="phiki language-swift github-light" data-language="swift" style="background-color: #fff;color: #24292e;"><code><span class="line"><span class="token" style="color: #6a737d;">///</span><span class="token" style="color: #6a737d;"> Safely unwraps optional value from chain</span><span class="token">
</span></span><span class="line"><span class="token">func unwrap</span><span class="token">&lt;</span><span class="token" style="color: #005cc5;">T</span><span class="token">&gt;</span><span class="token">(</span><span class="token">)</span><span class="token"> </span><span class="token" style="color: #d73a49;">-&gt;</span><span class="token"> </span><span class="token">Driver</span><span class="token">&lt;</span><span class="token">T</span><span class="token">&gt;</span><span class="token"> </span><span class="token" style="color: #d73a49;">where</span><span class="token"> </span><span class="token" style="color: #005cc5;">Element</span><span class="token"> </span><span class="token" style="color: #d73a49;">==</span><span class="token"> </span><span class="token" style="color: #005cc5;">Optional</span><span class="token">&lt;</span><span class="token">T</span><span class="token">&gt;</span><span class="token"> </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token" style="color: #d73a49;">return</span><span class="token"> </span><span class="token" style="color: #005cc5;">self</span><span class="token">
</span></span><span class="line"><span class="token">        .</span><span class="token" style="color: #005cc5;">filter</span><span class="token"> </span><span class="token">{</span><span class="token"> </span><span class="token" style="color: #005cc5;">$0</span><span class="token"> </span><span class="token" style="color: #d73a49;">!=</span><span class="token"> </span><span class="token" style="color: #005cc5;">nil</span><span class="token"> </span><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">        .</span><span class="token" style="color: #005cc5;">map</span><span class="token"> </span><span class="token">{</span><span class="token"> </span><span class="token" style="color: #005cc5;">$0</span><span class="token" style="color: #d73a49;">!</span><span class="token"> </span><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token" style="color: #6a737d;">///</span><span class="token" style="color: #6a737d;"> Creates new subscription and sends elements to `PublishRelay`.</span><span class="token">
</span></span><span class="line"><span class="token" style="color: #6a737d;">///</span><span class="token">
</span></span><span class="line"><span class="token" style="color: #6a737d;">///</span><span class="token" style="color: #6a737d;"> - Parameter relay: PublishRelay instance</span><span class="token">
</span></span><span class="line"><span class="token" style="color: #6a737d;">///</span><span class="token" style="color: #6a737d;"> - Returns: Disposable for current subscription</span><span class="token">
</span></span><span class="line"><span class="token">func drive</span><span class="token">(</span><span class="token">_ relay</span><span class="token">: </span><span class="token">PublishRelay</span><span class="token">&lt;</span><span class="token" style="color: #005cc5;">Element</span><span class="token">&gt;</span><span class="token">)</span><span class="token"> </span><span class="token" style="color: #d73a49;">-&gt;</span><span class="token"> </span><span class="token">Disposable </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token" style="color: #d73a49;">return</span><span class="token"> </span><span class="token">drive(</span><span class="token">onNext:</span><span class="token"> </span><span class="token">{</span><span class="token"> e </span><span class="token" style="color: #d73a49;">in</span><span class="token"> relay.</span><span class="token">accept(</span><span class="token">e</span><span class="token">)</span><span class="token"> </span><span class="token">}</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token" style="color: #6a737d;">///</span><span class="token" style="color: #6a737d;"> Maps each sequence elements to given value.</span><span class="token">
</span></span><span class="line"><span class="token" style="color: #6a737d;">///</span><span class="token">
</span></span><span class="line"><span class="token" style="color: #6a737d;">///</span><span class="token" style="color: #6a737d;"> - Parameter value: Value to map</span><span class="token">
</span></span><span class="line"><span class="token" style="color: #6a737d;">///</span><span class="token" style="color: #6a737d;"> - Returns: Sequence where all elements are given value.</span><span class="token">
</span></span><span class="line"><span class="token">func mapTo</span><span class="token">&lt;</span><span class="token" style="color: #005cc5;">T</span><span class="token">&gt;</span><span class="token">(</span><span class="token">_ value</span><span class="token">: </span><span class="token">T</span><span class="token">)</span><span class="token"> </span><span class="token" style="color: #d73a49;">-&gt;</span><span class="token"> </span><span class="token">Driver</span><span class="token">&lt;</span><span class="token">T</span><span class="token">&gt;</span><span class="token"> </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token" style="color: #d73a49;">return</span><span class="token"> </span><span class="token">map</span><span class="token"> </span><span class="token">{</span><span class="token"> </span><span class="token" style="color: #005cc5;">_</span><span class="token"> </span><span class="token" style="color: #d73a49;">in</span><span class="token"> value </span><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span></code></pre></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1390"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-1388">
	<h3	class='typography typography--size-36-text js-typography block-heading__heading'
	data-id='es-1389'
	>
	Foundation</h3></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1393"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-1391">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-1392'
	>
	This feature folder contains a wide range of useful extensions and computed properties covering many commonly used Foundation features: <em>Arrays</em>, <em>Strings</em>, <em>Bools</em>, <em>Date</em>, <em>Optional</em> and many others.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1395"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-code">
	<pre class="phiki language-swift github-light" data-language="swift" style="background-color: #fff;color: #24292e;"><code><span class="line"><span class="token" style="color: #d73a49;">public</span><span class="token"> </span><span class="token" style="color: #d73a49;">extension</span><span class="token"> </span><span class="token" style="color: #005cc5;">Array</span><span class="token"> </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token" style="color: #6a737d;">///</span><span class="token" style="color: #6a737d;"> Returns object at provided index, if an index is in bounds of array indices,</span><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token" style="color: #6a737d;">///</span><span class="token" style="color: #6a737d;"> otherwise, returns nil.</span><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token" style="color: #6a737d;">///</span><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token" style="color: #6a737d;">///</span><span class="token" style="color: #6a737d;"> - Parameter index: Index of the object that you want to get.</span><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token" style="color: #d73a49;">subscript</span><span class="token"> </span><span class="token">(</span><span class="token">safe index</span><span class="token">: </span><span class="token" style="color: #005cc5;">Int</span><span class="token">)</span><span class="token"> </span><span class="token" style="color: #d73a49;">-&gt;</span><span class="token"> </span><span class="token" style="color: #005cc5;">Element</span><span class="token" style="color: #d73a49;">?</span><span class="token"> </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">        </span><span class="token" style="color: #d73a49;">return</span><span class="token"> indices </span><span class="token" style="color: #d73a49;">~=</span><span class="token"> index </span><span class="token" style="color: #d73a49;">?</span><span class="token"> </span><span class="token" style="color: #005cc5;">self</span><span class="token">[</span><span class="token">index</span><span class="token">]</span><span class="token"> </span><span class="token" style="color: #d73a49;">:</span><span class="token"> </span><span class="token" style="color: #005cc5;">nil</span><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token" style="color: #d73a49;">public</span><span class="token"> </span><span class="token" style="color: #d73a49;">extension</span><span class="token"> </span><span class="token" style="color: #005cc5;">Optional</span><span class="token"> </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token" style="color: #6a737d;">///</span><span class="token" style="color: #6a737d;"> Executes `function` if optional is .some, otherwise nothing happens.</span><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token" style="color: #6a737d;">///</span><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token" style="color: #6a737d;">///</span><span class="token" style="color: #6a737d;"> - Parameter function: Function to be executed.</span><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token">func forValue</span><span class="token">(</span><span class="token">do function</span><span class="token">: </span><span class="token">(</span><span class="token">Wrapped</span><span class="token">)</span><span class="token"> </span><span class="token" style="color: #d73a49;">-&gt;</span><span class="token"> </span><span class="token">(</span><span class="token">)</span><span class="token">)</span><span class="token"> </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">        </span><span class="token" style="color: #d73a49;">if</span><span class="token"> </span><span class="token" style="color: #d73a49;">let</span><span class="token"> value </span><span class="token" style="color: #d73a49;">=</span><span class="token"> </span><span class="token" style="color: #005cc5;">self</span><span class="token"> </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">            </span><span class="token">function(</span><span class="token">value</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">        </span><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token" style="color: #d73a49;">public</span><span class="token"> </span><span class="token" style="color: #d73a49;">extension</span><span class="token"> </span><span class="token" style="color: #005cc5;">Bool</span><span class="token"> </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token" style="color: #6a737d;">///</span><span class="token" style="color: #6a737d;"> If the bool is `true` the provided object is returned, otherwise `nil` is returned.</span><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token" style="color: #6a737d;">///</span><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token" style="color: #6a737d;">///</span><span class="token" style="color: #6a737d;"> - Parameter object: Object to be returned if the bool is `true`.</span><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token" style="color: #6a737d;">///</span><span class="token" style="color: #6a737d;"> - Returns: `object` if `true`, `nil` otherwise.</span><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token">func mapTrue</span><span class="token">&lt;</span><span class="token" style="color: #005cc5;">T</span><span class="token">&gt;</span><span class="token">(</span><span class="token">to object</span><span class="token">: </span><span class="token">T</span><span class="token">)</span><span class="token"> </span><span class="token" style="color: #d73a49;">-&gt;</span><span class="token"> </span><span class="token">T</span><span class="token" style="color: #d73a49;">?</span><span class="token"> </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">        </span><span class="token" style="color: #d73a49;">return</span><span class="token"> </span><span class="token" style="color: #005cc5;">self</span><span class="token"> </span><span class="token" style="color: #d73a49;">?</span><span class="token"> object </span><span class="token" style="color: #d73a49;">:</span><span class="token"> </span><span class="token" style="color: #005cc5;">nil</span><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token" style="color: #d73a49;">public</span><span class="token"> </span><span class="token" style="color: #d73a49;">extension</span><span class="token"> </span><span class="token" style="color: #005cc5;">String</span><span class="token"> </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token" style="color: #6a737d;">///</span><span class="token" style="color: #6a737d;"> Checks if string is empty or contains only whitespaces and newlines</span><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token" style="color: #6a737d;">///</span><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token" style="color: #6a737d;">///</span><span class="token" style="color: #6a737d;"> Returns `true` if string is empty or contains only whitespaces and newlines</span><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token">var isBlank:</span><span class="token"> </span><span class="token" style="color: #005cc5;">Bool</span><span class="token"> </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">        </span><span class="token" style="color: #d73a49;">return</span><span class="token"> </span><span class="token">trimmingCharacters(</span><span class="token">in:</span><span class="token"> .</span><span class="token">whitespacesAndNewlines</span><span class="token">)</span><span class="token">.</span><span class="token" style="color: #005cc5;">isEmpty</span><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span></code></pre></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1398"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-1396">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-1397'
	>
	These are just a taste of what we have available there, so be sure to check them out. We’re willing to bet that you will find something of use there.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1401"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-1399">
	<h3	class='typography typography--size-36-text js-typography block-heading__heading'
	data-id='es-1400'
	>
	UI</h3></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1404"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-1402">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-1403'
	>
	This one is centered around <strong>UIKit</strong>–mproving it, as well as fixing some issues which we think should come out-of-the-box.&nbsp;</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1407"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-1405">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-1406'
	>
	Ever wanted to initialize colors more easily, or generate their hex values on the fly? Look no further.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1409"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-code">
	<pre class="phiki language-swift github-light" data-language="swift" style="background-color: #fff;color: #24292e;"><code><span class="line"><span class="token" style="color: #d73a49;">public</span><span class="token"> </span><span class="token" style="color: #d73a49;">extension</span><span class="token"> </span><span class="token" style="color: #6f42c1;">UIColor</span><span class="token"> </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token" style="color: #6a737d;">///</span><span class="token" style="color: #6a737d;"> Initializes a UIColor object with red, green and blue values,</span><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token" style="color: #6a737d;">///</span><span class="token" style="color: #6a737d;"> without the need for dividing the value (red, green or blue) with 255.0,</span><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token" style="color: #6a737d;">///</span><span class="token" style="color: #6a737d;"> because this function does that for you.</span><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token" style="color: #6a737d;">///</span><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token" style="color: #6a737d;">///</span><span class="token" style="color: #6a737d;"> - Parameters:</span><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token" style="color: #6a737d;">///</span><span class="token" style="color: #6a737d;">   - r: Red value.</span><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token" style="color: #6a737d;">///</span><span class="token" style="color: #6a737d;">   - g: Green value.</span><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token" style="color: #6a737d;">///</span><span class="token" style="color: #6a737d;">   - b: Blue value.</span><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token" style="color: #6a737d;">///</span><span class="token" style="color: #6a737d;">   - alpha: Alpha value of the color.</span><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token" style="color: #d73a49;">convenience</span><span class="token"> </span><span class="token" style="color: #d73a49;">init</span><span class="token">(</span><span class="token">r</span><span class="token">: </span><span class="token">CGFloat</span><span class="token">, </span><span class="token">g</span><span class="token">: </span><span class="token">CGFloat</span><span class="token">, </span><span class="token">b</span><span class="token">: </span><span class="token">CGFloat</span><span class="token">, </span><span class="token">alpha</span><span class="token">: </span><span class="token">CGFloat </span><span class="token" style="color: #d73a49;">=</span><span class="token"> </span><span class="token" style="color: #005cc5;">1</span><span class="token">)</span><span class="token"> </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">        </span><span class="token" style="color: #005cc5;">self</span><span class="token">.</span><span class="token" style="color: #d73a49;">init</span><span class="token">(</span><span class="token">red:</span><span class="token"> r</span><span class="token" style="color: #032f62;">/255</span><span class="token" style="color: #005cc5;">.</span><span class="token" style="color: #032f62;">0, green: g/</span><span class="token" style="color: #005cc5;">255.0</span><span class="token">, </span><span class="token">blue:</span><span class="token"> b</span><span class="token" style="color: #d73a49;">/</span><span class="token" style="color: #005cc5;">255.0</span><span class="token">, </span><span class="token">alpha:</span><span class="token"> alpha</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token">        </span><span class="token" style="color: #6a737d;">///</span><span class="token" style="color: #6a737d;"> Generates a Hex string, from a current color value.</span><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token" style="color: #6a737d;">///</span><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token" style="color: #6a737d;">///</span><span class="token" style="color: #6a737d;"> - Parameter includeAlpha: Boolean value indicating whether the alpha channel should be included in a hex string. Default is false.</span><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token" style="color: #6a737d;">///</span><span class="token" style="color: #6a737d;"> - Returns: Hex color string, generated from a current color value.</span><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token">func getHex</span><span class="token">(</span><span class="token">withAlpha includeAlpha</span><span class="token">: </span><span class="token" style="color: #005cc5;">Bool</span><span class="token"> </span><span class="token" style="color: #d73a49;">=</span><span class="token"> </span><span class="token" style="color: #005cc5;">false</span><span class="token">)</span><span class="token"> </span><span class="token" style="color: #d73a49;">-&gt;</span><span class="token"> </span><span class="token" style="color: #005cc5;">String</span><span class="token" style="color: #d73a49;">?</span><span class="token"> </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">        </span><span class="token" style="color: #d73a49;">guard</span><span class="token"> </span><span class="token" style="color: #d73a49;">let</span><span class="token"> components </span><span class="token" style="color: #d73a49;">=</span><span class="token"> cgColor.components, components.</span><span class="token" style="color: #005cc5;">count</span><span class="token"> </span><span class="token" style="color: #d73a49;">&gt;=</span><span class="token"> </span><span class="token" style="color: #005cc5;">3</span><span class="token"> </span><span class="token" style="color: #d73a49;">else</span><span class="token"> </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">            </span><span class="token" style="color: #d73a49;">return</span><span class="token"> </span><span class="token" style="color: #005cc5;">nil</span><span class="token">
</span></span><span class="line"><span class="token">        </span><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token">        </span><span class="token" style="color: #d73a49;">let</span><span class="token"> r </span><span class="token" style="color: #d73a49;">=</span><span class="token"> </span><span class="token" style="color: #005cc5;">Float</span><span class="token">(</span><span class="token">components</span><span class="token">[</span><span class="token" style="color: #005cc5;">0</span><span class="token">]</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">        </span><span class="token" style="color: #d73a49;">let</span><span class="token"> g </span><span class="token" style="color: #d73a49;">=</span><span class="token"> </span><span class="token" style="color: #005cc5;">Float</span><span class="token">(</span><span class="token">components</span><span class="token">[</span><span class="token" style="color: #005cc5;">1</span><span class="token">]</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">        </span><span class="token" style="color: #d73a49;">let</span><span class="token"> b </span><span class="token" style="color: #d73a49;">=</span><span class="token"> </span><span class="token" style="color: #005cc5;">Float</span><span class="token">(</span><span class="token">components</span><span class="token">[</span><span class="token" style="color: #005cc5;">2</span><span class="token">]</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">        </span><span class="token" style="color: #d73a49;">let</span><span class="token"> a </span><span class="token" style="color: #d73a49;">=</span><span class="token"> </span><span class="token" style="color: #005cc5;">Float</span><span class="token">(</span><span class="token">components.</span><span class="token" style="color: #005cc5;">count</span><span class="token"> </span><span class="token" style="color: #d73a49;">&gt;=</span><span class="token"> </span><span class="token" style="color: #005cc5;">4</span><span class="token"> </span><span class="token" style="color: #d73a49;">?</span><span class="token"> components</span><span class="token">[</span><span class="token" style="color: #005cc5;">3</span><span class="token">]</span><span class="token"> </span><span class="token" style="color: #d73a49;">:</span><span class="token"> </span><span class="token" style="color: #005cc5;">1</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token">        </span><span class="token" style="color: #d73a49;">if</span><span class="token"> includeAlpha </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">            </span><span class="token" style="color: #d73a49;">return</span><span class="token"> </span><span class="token" style="color: #005cc5;">String</span><span class="token">(</span><span class="token">format:</span><span class="token"> </span><span class="token" style="color: #032f62;">&quot;</span><span class="token" style="color: #032f62;">#%02lX%02lX%02lX%02lX</span><span class="token" style="color: #032f62;">&quot;</span><span class="token">, </span><span class="token">lroundf(</span><span class="token">r </span><span class="token" style="color: #d73a49;">*</span><span class="token"> </span><span class="token" style="color: #005cc5;">255</span><span class="token">)</span><span class="token">, </span><span class="token">lroundf(</span><span class="token">g </span><span class="token" style="color: #d73a49;">*</span><span class="token"> </span><span class="token" style="color: #005cc5;">255</span><span class="token">)</span><span class="token">, </span><span class="token">lroundf(</span><span class="token">b </span><span class="token" style="color: #d73a49;">*</span><span class="token"> </span><span class="token" style="color: #005cc5;">255</span><span class="token">)</span><span class="token">, </span><span class="token">lroundf(</span><span class="token">a </span><span class="token" style="color: #d73a49;">*</span><span class="token"> </span><span class="token" style="color: #005cc5;">255</span><span class="token">)</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">        </span><span class="token">}</span><span class="token"> </span><span class="token" style="color: #d73a49;">else</span><span class="token"> </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">            </span><span class="token" style="color: #d73a49;">return</span><span class="token"> </span><span class="token" style="color: #005cc5;">String</span><span class="token">(</span><span class="token">format:</span><span class="token"> </span><span class="token" style="color: #032f62;">&quot;</span><span class="token" style="color: #032f62;">#%02lX%02lX%02lX</span><span class="token" style="color: #032f62;">&quot;</span><span class="token">, </span><span class="token">lroundf(</span><span class="token">r </span><span class="token" style="color: #d73a49;">*</span><span class="token"> </span><span class="token" style="color: #005cc5;">255</span><span class="token">)</span><span class="token">, </span><span class="token">lroundf(</span><span class="token">g </span><span class="token" style="color: #d73a49;">*</span><span class="token"> </span><span class="token" style="color: #005cc5;">255</span><span class="token">)</span><span class="token">, </span><span class="token">lroundf(</span><span class="token">b </span><span class="token" style="color: #d73a49;">*</span><span class="token"> </span><span class="token" style="color: #005cc5;">255</span><span class="token">)</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">        </span><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span></code></pre></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1412"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-1410">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-1411'
	>
	Need to remove insets from your <em>UITextView</em>? We got you covered.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1414"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-code">
	<pre class="phiki language-swift github-light" data-language="swift" style="background-color: #fff;color: #24292e;"><code><span class="line"><span class="token" style="color: #d73a49;">public</span><span class="token"> </span><span class="token" style="color: #d73a49;">extension</span><span class="token"> </span><span class="token" style="color: #6f42c1;">UITextView</span><span class="token"> </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token" style="color: #6a737d;">///</span><span class="token" style="color: #6a737d;"> Removes all insets from a textView, so it can act more like a label.</span><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token">func removeAllInsets</span><span class="token">(</span><span class="token">)</span><span class="token"> </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">        textContainer.</span><span class="token">lineFragmentPadding</span><span class="token"> </span><span class="token" style="color: #d73a49;">=</span><span class="token"> </span><span class="token" style="color: #005cc5;">0</span><span class="token">
</span></span><span class="line"><span class="token">        textContainerInset </span><span class="token" style="color: #d73a49;">=</span><span class="token"> .</span><span class="token">zero</span><span class="token">
</span></span><span class="line"><span class="token">        contentInset </span><span class="token" style="color: #d73a49;">=</span><span class="token"> .</span><span class="token">zero</span><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span></code></pre></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1417"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-1415">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-1416'
	>
	This is the biggest feature folder–for a reason. We love working on UI and strive to make user experience the best it can be, so focusing on improving the tools at our disposal is the least we can do.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1420"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-1418">
	<h2	class='typography typography--size-52-default js-typography block-heading__heading'
	data-id='es-1419'
	>
	Not our first&nbsp;rodeo</h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1423"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-1421">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-1422'
	>
	If things metioned in this article have sparked your interest, you’ll maybe also want to take a peek inside our other open-source iOS stuff:</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1426"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="lists" data-id="es-1424">
	<ul	class='typography typography--size-16-text-roman js-typography lists__typography'
	data-id='es-1425'
	>
	<li><strong><a href="https://github.com/infinum/iOS-VIPER-Xcode-Templates">VIPER Xcode templates</a></strong>–Our template generator used to quickly generate all files and structures needed for implementing VIPER app arhitecture.</li><li><strong><a href="https://github.com/infinum/FBAnnotationClustering">FBAnnotationClustering</a></strong>–A library for clustering map annotations in an easy and performant way, which also has an accompanying <a href="https://infinum.com/blog/a-blazingly-fast-open-source-algorithm-for-poi-clustering-on-ios/">blog post</a>.</li><li><strong><a href="https://github.com/infinum/Japx">Japx</a></strong>–A lightweight JSON:API parser that flattens complex <a href="https://jsonapi.org">JSON:API</a> structure and turns it into simple JSON and vice versa.</li><li><strong><a href="https://github.com/infinum/iOS-prince-of-versions">Prince of Versions</a></strong>–A library used for easier versioning of your applications, allowing you to prompt your users to update the app to the newest version.</li><li><strong><a href="https://github.com/infinum/iOS-Loggie">Loggie</a></strong>–Used for capturing all HTTP/S requests the app makes and showing them in a simple table view, enabling easier API debugging.</li></ul></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1429"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-1427">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-1428'
	>
	Your contributions and support is what keeps them evolving as iOS evolves, and we hope that it will continue to be the case.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1432"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-1430">
	<h2	class='typography typography--size-52-default js-typography block-heading__heading'
	data-id='es-1431'
	>
	Go nuts with it</h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1435"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-1433">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-1434'
	>
	We hope all of these are going to be helpful to you. If you have any suggestions of your own, feel free to open a PR by following steps detailed <a href="https://github.com/infinum/iOS-Nuts-And-Bolts#adding-a-new-feature">here</a>. We’re always looking forward to learning new things, and can’t wait to see wait to see what other tips &amp; tricks our community can come up with.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1438"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-1436">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-1437'
	>
	Until next time, happy coding!</p></div>	</div>
</div>
</div>		</div>
	</div><p>The post <a href="https://infinum.com/blog/repository-full-of-our-best-practices-in-ios-development/">A Repository Full of Our Best Practices in iOS Development</a> appeared first on <a href="https://infinum.com">Infinum</a>.</p>
]]>
				</content:encoded>
			</item>
					<item>
				<image>
					<url>7934https://infinum.com/uploads/2019/09/how-to-prepare-your-app-for-dark-mode-in-iOS-13-0.webp</url>
				</image>
				<title>How to Prepare Your App for Dark Mode in iOS 13</title>
				<link>https://infinum.com/blog/how-to-prepare-your-app-for-dark-mode-in-ios-13/</link>
				<pubDate>Fri, 13 Sep 2019 13:15:00 +0000</pubDate>
				<dc:creator>Goran Brlas</dc:creator>
				<guid isPermaLink="false">https://infinum.com/the-capsized-eight/how-to-prepare-your-app-for-dark-mode-in-ios-13/</guid>
				<description>
					<![CDATA[<p>After what seems like forever, iOS is officially getting a feature its users have been crying for: a system-wide dark mode.</p>
<p>The post <a href="https://infinum.com/blog/how-to-prepare-your-app-for-dark-mode-in-ios-13/">How to Prepare Your App for Dark Mode in iOS 13</a> appeared first on <a href="https://infinum.com">Infinum</a>.</p>
]]>
				</description>
				<content:encoded>
					<![CDATA[<div
	class="wrapper"
	data-id="es-1731"
	 data-animation-target='inner-items'>
		
			<div class="wrapper__inner">
			<div class="block-blog-content js-block-blog-content">
	
<div class="block-blog-content-sidebar" data-id="es-1441">
	</div>

<div class="block-blog-content-main">
	
<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1444"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-1442">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-1443'
	>
	After waiting for what seems like an eternity, iOS is officially getting a feature its users have been crying for: a system-wide dark mode. As it sees the light of day, Android users should finally stop gloating over their advantage!</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1447"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-1445">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-1446'
	>
	The wait has been long but it’s been worth it. Dark mode suits iOS well, as is evident from the settings app screenshot below.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1450"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-media">
	<div	class="media block-media__media media__border--none media__align--center-center"
	data-id="es-1448"
	 data-media-type='image'>

	<figure class="image block-media__image-figure image--size-auto" data-id="es-1449">
	<picture class="image__picture block-media__image-picture">
								
			<source
				srcset=https://infinum.com/uploads/2019/09/how-to-prepare-your-app-for-dark-mode-in-iOS-13-1-1400x875.webp				media='(max-width: 699px)'
				type=image/webp								height="875"
												width="1400"
				 />
												<img
					src="https://infinum.com/uploads/2019/09/how-to-prepare-your-app-for-dark-mode-in-iOS-13-1.webp"
					class="image__img block-media__image-img"
					alt=""
										height="1000"
															width="1600"
										loading="lazy"
					 />
					</picture>

	</figure></div></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1453"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-1451">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-1452'
	>
	Beg to differ? Well, even if you’re not digging the new color scheme, you should still try it out as it’s not only a visual update–it comes with more hidden benefits.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1456"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-1454">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-1455'
	>
	Dark mode can help <strong>preserve battery life on OLED screens</strong> since true black (#000000) color means turned off pixels. It’s not much, but if you need every little bit of the energy juice available, it’s worth considering. Also, late-night texters will appreciate the dark color causing <strong>less strain</strong> than default white.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1459"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-1457">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-1458'
	>
	Chances are these benefits have sparked the interest of mobile users, so in this article we’ll cover everything you need to know in order to <strong>make your app a dark mode native</strong>.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1462"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-1460">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-1461'
	>
	By the way, adding dark mode support becomes much easier when you put our <a href="https://infinum.com/blog/color-naming-system-ios/" target="_blank" rel="noreferrer noopener">Bullet-Proof Color-Naming System for iOS Development</a> to use. </p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1465"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-1463">
	<h2	class='typography typography--size-52-default js-typography block-heading__heading'
	data-id='es-1464'
	>
	Requirements</h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1468"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-1466">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-1467'
	>
	Before diving in, there are a couple of requirements you must meet in order to actually make your app dark-mode compliant.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1471"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="lists" data-id="es-1469">
	<ul	class='typography typography--size-16-text-roman js-typography lists__typography'
	data-id='es-1470'
	>
	<li>It must be built and released using <strong>Xcode 11</strong></li><li>It must run on a device running <strong>iOS 13.0 or later</strong></li></ul></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1474"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-1472">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-1473'
	>
	If you built your app using any older Xcode, the app will always display its normal appearance, even on devices which support dark mode. The exact same is true for apps built using Xcode 11 but running on older versions of iOS–these new features will not apply and the app will retain its default appearance.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1477"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-1475">
	<h2	class='typography typography--size-52-default js-typography block-heading__heading'
	data-id='es-1476'
	>
	Getting our hands dirty</h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1480"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-1478">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-1479'
	>
	Now that we’ve gotten the prerequisites out of the way, let’s get started. If you turn dark mode on, it will automatically be applied to all system UI elements and all Apple apps.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1483"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-1481">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-1482'
	>
	Install your application on a device running iOS 13, and you’ll quickly see that it falls into one of the following categories.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1486"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="lists" data-id="es-1484">
	<ul	class='typography typography--size-16-text-roman js-typography lists__typography'
	data-id='es-1485'
	>
	<li>App is ready for dark mode on day one. Kudos to you, you can kick back and enjoy the fruits of your labor.</li><li>App is a Frankenstein-like mix of light and dark modes. Yikes…</li><li>App does not support dark mode at all. Uh-oh!</li></ul></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1489"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-1487">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-1488'
	>
	But even if your app falls in the bottom two categories, don’t worry. You will learn how to leverage <strong>trait collections, dynamic colors and dynamic images</strong> in order to successfully transform your application into a versatile theming champion.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1492"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-1490">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-1491'
	>
	The scope of the work on your plate depends on the size of the app, the amount of custom elements used, and your project structure. However, the adoption steps will mostly remain the same. Let’s check them out.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1495"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-1493">
	<h2	class='typography typography--size-52-default js-typography block-heading__heading'
	data-id='es-1494'
	>
	1. Understanding trait collection</h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1498"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-1496">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-1497'
	>
	It’s worth noting that <em>traitCollection</em> property was introduced over 5 years ago in iOS 8, as a part of the <em>UITraitEnvironment</em> protocol adopted by <em>UIScreen</em>, <em>UIWindow</em>, <em>UIViewController</em>, <em>UIPresentationController</em> and <em>UIView</em>.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1501"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-1499">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-1500'
	>
	It can be used to provide information about the iOS interface environment to your apps such as device type, device size class and display scale, but with iOS 13, we get a new property–<strong><em>userInterfaceStyle</em></strong>, which is used to determine the view’s appearance style.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1503"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-code">
	<pre class="phiki language-swift github-light" data-language="swift" style="background-color: #fff;color: #24292e;"><code><span class="line"><span class="token">enum UIUserInterfaceStyle</span><span class="token">:</span><span class="token"> </span><span class="token" style="color: #6f42c1;">Int </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">   </span><span class="token" style="color: #d73a49;">case</span><span class="token"> </span><span class="token">unspecified
</span></span><span class="line"><span class="token">   </span><span class="token" style="color: #d73a49;">case</span><span class="token"> </span><span class="token">light
</span></span><span class="line"><span class="token">   </span><span class="token" style="color: #d73a49;">case</span><span class="token"> </span><span class="token">dark
</span></span><span class="line"><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span></code></pre></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1506"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-1504">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-1505'
	>
	Furthermore, <em>.unspecified</em> case is used to say that the object will inherit its style from its superview (or the system in case of a UIScreen), and <em>.light</em> and <em>.dark</em> styles are pretty self-explanatory.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1509"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-1507">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-1508'
	>
	This <em>traitCollection</em> information is passed through the interface hierarchy, as can be seen here:</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1512"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-media">
	<div	class="media block-media__media media__border--none media__align--center-center"
	data-id="es-1510"
	 data-media-type='image'>

	<figure class="image block-media__image-figure image--size-stretch" data-id="es-1511">
	<picture class="image__picture block-media__image-picture">
												<img
					src="https://infinum.com/uploads/2019/09/how-to-prepare-your-app-for-dark-mode-in-iOS-13-2.webp"
					class="image__img block-media__image-img"
					alt=""
										height="600"
															width="900"
										loading="lazy"
					 />
					</picture>

			<figcaption class="image__figcaption block-media__image-figcaption">
			iOS 13 trait collection UIKit flow		</figcaption>
	</figure></div></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1515"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-1513">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-1514'
	>
	<em>UIScreen</em> gets the <em>userInterfaceStyle</em> property from the system and passes it onto the window scene, which propagates it to the window etc., etc. You get the idea.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1518"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-1516">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-1517'
	>
	This propagation means that the theme which should be used is not being read from the system on each hierarchical level, which allows us to <strong>override system appearance mode whenever we choose</strong>. For example, we can define a different interface style for just one view controller inside our app, and that style is then passed onto each of its child views, while unrelated views remain unaffected.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1521"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-media">
	<div	class="media block-media__media media__border--none media__align--center-center"
	data-id="es-1519"
	 data-media-type='image'>

	<figure class="image block-media__image-figure image--size-stretch" data-id="es-1520">
	<picture class="image__picture block-media__image-picture">
												<img
					src="https://infinum.com/uploads/2019/09/how-to-prepare-your-app-for-dark-mode-in-iOS-13-3.webp"
					class="image__img block-media__image-img"
					alt=""
										height="600"
															width="900"
										loading="lazy"
					 />
					</picture>

			<figcaption class="image__figcaption block-media__image-figcaption">
			iOS 13 override system appearance		</figcaption>
	</figure></div></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1524"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-1522">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-1523'
	>
	With iOS 13, <em>UIView</em>, <em>UIViewController</em>, and <em>UIWindow</em> have gained a new <strong><em>overrideUserInterfaceStyle</em></strong> property that lets us override the system appearance:</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1526"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-code">
	<pre class="phiki language-swift github-light" data-language="swift" style="background-color: #fff;color: #24292e;"><code><span class="line"><span class="token" style="color: #6a737d;">//</span><span class="token" style="color: #6a737d;"> Always light.</span><span class="token">
</span></span><span class="line"><span class="token" style="color: #d73a49;">let</span><span class="token"> lightView </span><span class="token" style="color: #d73a49;">=</span><span class="token"> </span><span class="token">UIView(</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">lightView.</span><span class="token">overrideUserInterfaceStyle</span><span class="token"> </span><span class="token" style="color: #d73a49;">=</span><span class="token"> .</span><span class="token">light</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token" style="color: #6a737d;">//</span><span class="token" style="color: #6a737d;"> Always dark.</span><span class="token">
</span></span><span class="line"><span class="token" style="color: #d73a49;">let</span><span class="token"> darkView </span><span class="token" style="color: #d73a49;">=</span><span class="token"> </span><span class="token">UIView(</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">darkView.</span><span class="token">overrideUserInterfaceStyle</span><span class="token"> </span><span class="token" style="color: #d73a49;">=</span><span class="token"> .</span><span class="token">dark</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token" style="color: #6a737d;">//</span><span class="token" style="color: #6a737d;"> Follows the appearance of its superview.</span><span class="token">
</span></span><span class="line"><span class="token" style="color: #d73a49;">let</span><span class="token"> view </span><span class="token" style="color: #d73a49;">=</span><span class="token"> </span><span class="token">UIView(</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">view.</span><span class="token">overrideUserInterfaceStyle</span><span class="token"> </span><span class="token" style="color: #d73a49;">=</span><span class="token"> .</span><span class="token">unspecified</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span></code></pre></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1529"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-1527">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-1528'
	>
	This will get applied to the view at question, but also to all its subviews, so be careful when doing so and make sure it’s what you really want.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1532"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-1530">
	<h2	class='typography typography--size-52-default js-typography block-heading__heading'
	data-id='es-1531'
	>
	2. Dynamic colors</h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1535"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-1533">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-1534'
	>
	Until now, both images and colors were static, which meant that they were always the same, independent of the environment. For example, if we added our own theming before, we would have to specify x different colors or images, with x being the number of themes we support.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1538"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-1536">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-1537'
	>
	Let’s see what has changed here.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1541"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-1539">
	<h3	class='typography typography--size-36-text js-typography block-heading__heading'
	data-id='es-1540'
	>
	Dynamic system colors</h3></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1544"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-1542">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-1543'
	>
	Starting from iOS 13, <strong>UIColors can be dynamic</strong>, which means they contain one set of RGB values for light mode, and another for dark.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1547"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-1545">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-1546'
	>
	Whenever users change the system appearance, the <em>UIScreen</em> trait collection is changed, and the UI objects in the hierarchy are notified. If any view in the hierarchy contains elements which are using dynamic colors, such as labels or buttons, everything will automatically update to the appropriate color instantaneously, without us doing any work.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1550"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-media">
	<div	class="media block-media__media media__border--none media__align--center-center"
	data-id="es-1548"
	 data-media-type='image'>

	<figure class="image block-media__image-figure image--size-stretch" data-id="es-1549">
	<picture class="image__picture block-media__image-picture">
												<img
					src="https://infinum.com/uploads/2019/09/how-to-prepare-your-app-for-dark-mode-in-iOS-13-4.webp"
					class="image__img block-media__image-img"
					alt=""
										height="374"
															width="1103"
										loading="lazy"
					 />
					</picture>

			<figcaption class="image__figcaption block-media__image-figcaption">
			iOS 13 dynamic system colors		</figcaption>
	</figure></div></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1553"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-1551">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-1552'
	>
	As you can see from the picture above, contrary to the old static colors, system colors are slightly different for each mode, sporting a shade specifically made to look better on light or dark mode, respectively.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1556"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-1554">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-1555'
	>
	Same as with the static colors before, these can be easily selected from the storyboard/xib:</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1559"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-media">
	<div	class="media block-media__media media__border--none media__align--center-center"
	data-id="es-1557"
	 data-media-type='image'>

	<figure class="image block-media__image-figure image--size-auto" data-id="es-1558">
	<picture class="image__picture block-media__image-picture">
												<img
					src="https://infinum.com/uploads/2019/09/how-to-prepare-your-app-for-dark-mode-in-iOS-13-5.webp"
					class="image__img block-media__image-img"
					alt=""
										height="681"
															width="315"
										loading="lazy"
					 />
					</picture>

			<figcaption class="image__figcaption block-media__image-figcaption">
			iOS 13 system colors in the storyboard		</figcaption>
	</figure></div></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1562"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-1560">
	<h3	class='typography typography--size-36-text js-typography block-heading__heading'
	data-id='es-1561'
	>
	Dynamic semantic colors</h3></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1565"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-1563">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-1564'
	>
	What makes semantic colors different from regular ones? Naming convention based on purpose. Instead of telling us what color they’re representing, these colors are named with their use in mind.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1568"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-1566">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-1567'
	>
	Previous Xcode versions offered two static colors which were semantically named – <em>.lightText</em> and <em>.darkText</em>. Since they are static, they don’t play nicely with the dark mode. Lucky for us, Xcode 11 provides us with a full new suite of semantic colors such as <em>UIColor.label</em>, <em>UIColor.secondaryLabel</em>, <em>UIColor.headline</em> and many others which do!</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1571"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-1569">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-1570'
	>
	The most important take here is that using them ensures your app’s appearance will look familiar to the rest of the system. <em>UIColor.label</em> will look the same in all system apps, and using it in your app as well will <strong>make it feel native</strong>, which is always the best experience for the user.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1574"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-1572">
	<h3	class='typography typography--size-36-text js-typography block-heading__heading'
	data-id='es-1573'
	>
	Asset catalog dynamic colors</h3></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1577"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-1575">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-1576'
	>
	Asset catalog provides us with an option to create a different color set, which can later be used in both code and storyboards/xibs. When you create a new color set, choose the attributes inspector and in the appearance section select <em>“Any, Light, Dark”</em> and add appropriate colors for all styles.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1580"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-media">
	<div	class="media block-media__media media__border--none media__align--center-center"
	data-id="es-1578"
	 data-media-type='image'>

	<figure class="image block-media__image-figure image--size-auto" data-id="es-1579">
	<picture class="image__picture block-media__image-picture">
								
			<source
				srcset=https://infinum.com/uploads/2019/09/how-to-prepare-your-app-for-dark-mode-in-iOS-13-6-1400x210.webp				media='(max-width: 699px)'
				type=image/webp								height="210"
												width="1400"
				 />
												<img
					src="https://infinum.com/uploads/2019/09/how-to-prepare-your-app-for-dark-mode-in-iOS-13-6.webp"
					class="image__img block-media__image-img"
					alt=""
										height="240"
															width="1600"
										loading="lazy"
					 />
					</picture>

			<figcaption class="image__figcaption block-media__image-figcaption">
			iOS 13 custom dynamic image		</figcaption>
	</figure></div></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1585"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="blockquote block-blockquote__blockquote" data-id="es-1581">
	
	<div class="blockquote__content">
		<i
	class="icon blockquote__icon icon--size-16 icon--scale-100"
	 aria-hidden='true' data-name='blockquote-24' data-id='es-1582'>
	<svg fill='none' height='24' viewBox='0 0 24 24' width='24' xmlns='http://www.w3.org/2000/svg'><path clip-rule='evenodd' d='m12 24c6.6274 0 12-5.3726 12-12 0-2.79685-.9568-5.37021-2.561-7.41062-.581.22951-1.0832.60583-1.5069 1.12898-.5132.60844-.7698 1.41969-.7698 2.43375v.07605h2.5789v5.59004h-5.6197v-5.01962c0-1.11547.154-2.06616.4619-2.85205.3336-.81125.757-1.48307 1.2702-2.01545.528-.52161 1.1175-.92155 1.7687-1.1998-2.0728-1.70651-4.7279-2.73128-7.6223-2.73128-6.62742 0-12 5.37258-12 12 0 6.6274 5.37258 12 12 12zm-3.53811-18.05347c-.30793.78589-.46189 1.73658-.46189 2.85205v5.01962h5.6197v-5.59004h-2.5789v-.07605c0-1.01406.2566-1.82531.7698-2.43375.5389-.63379 1.1804-1.05209 1.9245-1.2549v-2.28164c-.7441.07605-1.4626.25351-2.1555.53238-.6928.27887-1.3086.68449-1.84752 1.21688-.51321.53238-.9366 1.2042-1.27019 2.01545z' fill='currentColor' fill-rule='evenodd'/></svg></i><p	class='typography typography--size-36-text js-typography blockquote__quote'
	data-id='es-1583'
	>
	Note that this approach will not work in iOS 10 since it doesn’t support color declarations in the asset catalog.</p>
		<div class="blockquote__caption-wrap">
					</div>
	</div>
</div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1588"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-1586">
	<h3	class='typography typography--size-36-text js-typography block-heading__heading'
	data-id='es-1587'
	>
	Code</h3></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1591"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-1589">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-1590'
	>
	If that disclaimer made you think <em>“Oh sh**, I still support iOS 10, what now?”</em>, no worries.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1594"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-1592">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-1593'
	>
	It’s also possible to create dynamic colors in code. You can initialize UIColor via <em>init(dynamicProvider:)</em> and return the corresponding colors depending on the current trait collection.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1596"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-code">
	<pre class="phiki language-swift github-light" data-language="swift" style="background-color: #fff;color: #24292e;"><code><span class="line"><span class="token" style="color: #d73a49;">let</span><span class="token"> myDynamicColor </span><span class="token" style="color: #d73a49;">=</span><span class="token"> </span><span class="token">UIColor</span><span class="token"> </span><span class="token">{</span><span class="token"> </span><span class="token">(</span><span class="token">traitCollection:</span><span class="token"> UITraitCollection</span><span class="token">)</span><span class="token"> </span><span class="token" style="color: #d73a49;">-&gt;</span><span class="token"> UIColor </span><span class="token" style="color: #d73a49;">in</span><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token" style="color: #d73a49;">switch</span><span class="token"> traitCollection.userInterfaceStyle </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token" style="color: #d73a49;">case</span><span class="token"> .</span><span class="token">unspecified</span><span class="token">, .</span><span class="token">light</span><span class="token" style="color: #d73a49;">:</span><span class="token"> </span><span class="token" style="color: #d73a49;">return</span><span class="token"> </span><span class="token">UIColor(</span><span class="token">red:</span><span class="token"> </span><span class="token" style="color: #005cc5;">220</span><span class="token">, </span><span class="token">green:</span><span class="token"> </span><span class="token" style="color: #005cc5;">220</span><span class="token">, </span><span class="token">blue:</span><span class="token"> </span><span class="token" style="color: #005cc5;">220</span><span class="token">, </span><span class="token">alpha:</span><span class="token"> </span><span class="token" style="color: #005cc5;">1.0</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token" style="color: #d73a49;">case</span><span class="token"> .</span><span class="token">dark</span><span class="token" style="color: #d73a49;">:</span><span class="token"> </span><span class="token" style="color: #d73a49;">return</span><span class="token"> </span><span class="token">UIColor(</span><span class="token">red:</span><span class="token"> </span><span class="token" style="color: #005cc5;">0</span><span class="token">, </span><span class="token">green:</span><span class="token"> </span><span class="token" style="color: #005cc5;">0</span><span class="token">, </span><span class="token">blue:</span><span class="token"> </span><span class="token" style="color: #005cc5;">0</span><span class="token">, </span><span class="token">alpha:</span><span class="token"> </span><span class="token" style="color: #005cc5;">1.0</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token">}</span><span class="token">                           
</span></span><span class="line"><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span></code></pre></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1599"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-1597">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-1598'
	>
	One thing to note here is that if you’re working with CALayers, they do not play nicely with dynamic colors since they are not a part of UIKit.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1602"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-1600">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-1601'
	>
	However, there is a neat way to get precisely the colors we need. Apple has also provided us with a function we can use to resolve colors for the current trait collection aptly named <em>resolvedColor(with:)</em>, as you can see below.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1604"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-code">
	<pre class="phiki language-swift github-light" data-language="swift" style="background-color: #fff;color: #24292e;"><code><span class="line"><span class="token" style="color: #d73a49;">let</span><span class="token"> resolvedColor </span><span class="token" style="color: #d73a49;">=</span><span class="token"> UIColor.</span><span class="token">label</span><span class="token">.</span><span class="token">resolvedColor(</span><span class="token">with:</span><span class="token"> traitCollection</span><span class="token">)</span><span class="token"> 
</span></span><span class="line"><span class="token">layer.</span><span class="token">borderColor</span><span class="token"> </span><span class="token" style="color: #d73a49;">=</span><span class="token"> resolvedColor.</span><span class="token">cgColor</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span></code></pre></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1607"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-1605">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-1606'
	>
	One more thing to consider and keep in mind regarding CALayer: since it’s not a part of UIKit, it also will not respond to any appearance changes. This is something you need to take care of manually, by updating its style through a callback or an observable (if you’re feeling reactive).</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1610"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-1608">
	<h2	class='typography typography--size-52-default js-typography block-heading__heading'
	data-id='es-1609'
	>
	3. Dynamic images</h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1613"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-1611">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-1612'
	>
	In iOS 13, images, just like color sets, can also be dynamic. There are multiple ways to achieve this, so let’s take a look at the different options at our disposal.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1616"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-1614">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-1615'
	>
	Note that not all images will need to be dark-mode compliant. For example, if you allow user-imported images or color profiles, those will need to remain as they are regardless of the currently set appearance, so there’s no need to adjust them on the fly.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1619"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-1617">
	<h3	class='typography typography--size-36-text js-typography block-heading__heading'
	data-id='es-1618'
	>
	SF Symbols</h3></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1622"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-1620">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-1621'
	>
	SF Symbols are a huge collection of over 1,500 consistent, highly configurable symbols you can use in your app that Apple has introduced during this year’s WWDC. They are <strong>fully integrated in the iOS 13 SDK and will automatically be available on every device that is running it</strong>, which means you don’t need to increase your app size by adding additional images and icons.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1625"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-1623">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-1624'
	>
	Another thing that really makes them shine is the automatic adaption to light/dark modes that comes out-of-the-box. In the image below, you can see just how versatile they really are, allowing you to adapt them to whichever style, weight or scale you may need.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1628"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-media">
	<div	class="media block-media__media media__border--none media__align--center-center"
	data-id="es-1626"
	 data-media-type='image'>

	<figure class="image block-media__image-figure image--size-stretch" data-id="es-1627">
	<picture class="image__picture block-media__image-picture">
								
			<source
				srcset=https://infinum.com/uploads/2019/09/how-to-prepare-your-app-for-dark-mode-in-iOS-13-7-1400x529.webp				media='(max-width: 699px)'
				type=image/webp								height="529"
												width="1400"
				 />
												<img
					src="https://infinum.com/uploads/2019/09/how-to-prepare-your-app-for-dark-mode-in-iOS-13-7.webp"
					class="image__img block-media__image-img"
					alt=""
										height="569"
															width="1505"
										loading="lazy"
					 />
					</picture>

			<figcaption class="image__figcaption block-media__image-figcaption">
			SF Symbols adapting to font		</figcaption>
	</figure></div></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1631"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-1629">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-1630'
	>
	You can use SF Symbols in two ways in your apps, through storyboards/xibs or by creating them in code.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1634"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-media">
	<div	class="media block-media__media media__border--none media__align--center-center"
	data-id="es-1632"
	 data-media-type='image'>

	<figure class="image block-media__image-figure image--size-stretch" data-id="es-1633">
	<picture class="image__picture block-media__image-picture">
								
			<source
				srcset=https://infinum.com/uploads/2019/09/how-to-prepare-your-app-for-dark-mode-in-iOS-13-8-1400x822.webp				media='(max-width: 699px)'
				type=image/webp								height="822"
												width="1400"
				 />
												<img
					src="https://infinum.com/uploads/2019/09/how-to-prepare-your-app-for-dark-mode-in-iOS-13-8.webp"
					class="image__img block-media__image-img"
					alt=""
										height="939"
															width="1600"
										loading="lazy"
					 />
					</picture>

			<figcaption class="image__figcaption block-media__image-figcaption">
			Using SF Symbols in storyboard		</figcaption>
	</figure></div></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1637"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-1635">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-1636'
	>
	To use SF Symbols through the interface builder, all you need to do is add an image view, type the symbol name and you’re done. Next to the image name you’ll be able to se the “System” text telling you that you are using an SF Symbol; images you import through the Assets will not have that text.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1640"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-1638">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-1639'
	>
	If you prefer setting up your images through code, you can also use symbols there by using the new UIImage initializer which takes a system name, like so:</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1642"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-code">
	<pre class="phiki language-swift github-light" data-language="swift" style="background-color: #fff;color: #24292e;"><code><span class="line"><span class="token" style="color: #d73a49;">let</span><span class="token"> image </span><span class="token" style="color: #d73a49;">=</span><span class="token"> </span><span class="token">UIImage(</span><span class="token">systemName:</span><span class="token"> </span><span class="token" style="color: #032f62;">&quot;</span><span class="token" style="color: #032f62;">cloud</span><span class="token" style="color: #032f62;">&quot;</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span></code></pre></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1645"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-1643">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-1644'
	>
	Since there are a lot of symbols available here and scrolling through them in Xcode can quickly become tiring, Apple has created an official <a href="https://developer.apple.com/design/downloads/SF-Symbols.dmg">SF Symbols app</a> that can be used for easier reference or a quick look at all the available symbols.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1648"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-1646">
	<h3	class='typography typography--size-36-text js-typography block-heading__heading'
	data-id='es-1647'
	>
	Custom images</h3></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1651"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-1649">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-1650'
	>
	For your custom images, you can define different image assets for both light and dark modes, and it can be done directly from the asset catalog, just like with custom colors. Just set their appearance in the right pane, drop a new image for each appearance and you’re done.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1654"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-media">
	<div	class="media block-media__media media__border--none media__align--center-center"
	data-id="es-1652"
	 data-media-type='image'>

	<figure class="image block-media__image-figure image--size-stretch" data-id="es-1653">
	<picture class="image__picture block-media__image-picture">
												<img
					src="https://infinum.com/uploads/2019/09/how-to-prepare-your-app-for-dark-mode-in-iOS-13-9.webp"
					class="image__img block-media__image-img"
					alt=""
										height="600"
															width="900"
										loading="lazy"
					 />
					</picture>

			<figcaption class="image__figcaption block-media__image-figcaption">
			Custom dynamic images in Asset catalog		</figcaption>
	</figure></div></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1657"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-1655">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-1656'
	>
	If, for some reason, you want to resolve the image and determine which one will be used, you can do that easily by resolving images by using the current trait collection:</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1659"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-code">
	<pre class="phiki language-swift github-light" data-language="swift" style="background-color: #fff;color: #24292e;"><code><span class="line"><span class="token" style="color: #d73a49;">let</span><span class="token"> image </span><span class="token" style="color: #d73a49;">=</span><span class="token"> </span><span class="token">UIImage(</span><span class="token">named:</span><span class="token"> </span><span class="token" style="color: #032f62;">&quot;</span><span class="token" style="color: #032f62;">image</span><span class="token" style="color: #032f62;">&quot;</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token" style="color: #d73a49;">let</span><span class="token"> asset </span><span class="token" style="color: #d73a49;">=</span><span class="token"> image</span><span class="token" style="color: #d73a49;">?</span><span class="token">.</span><span class="token">imageAsset</span><span class="token">
</span></span><span class="line"><span class="token" style="color: #d73a49;">let</span><span class="token"> resolvedImage </span><span class="token" style="color: #d73a49;">=</span><span class="token"> asset</span><span class="token" style="color: #d73a49;">?</span><span class="token">.</span><span class="token" style="color: #005cc5;">image</span><span class="token">(</span><span class="token">with:</span><span class="token"> traitCollection</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span></code></pre></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1662"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-1660">
	<h2	class='typography typography--size-52-default js-typography block-heading__heading'
	data-id='es-1661'
	>
	4. Attributed text</h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1665"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-1663">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-1664'
	>
	If you’ve ever used attributed text in your apps, you probably know that unless you specify the <em>foregroundColor</em> property, it will be automatically set to <em>.black</em>.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1668"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-1666">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-1667'
	>
	That was probably fine before if you weren’t using a black background, but with iOS 13, it will not work as expected when using the dark appearance–black text on a black background is a big no-no.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1671"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-1669">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-1670'
	>
	That’s where things like semantic colors come into play, as you can see below.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1673"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-code">
	<pre class="phiki language-swift github-light" data-language="swift" style="background-color: #fff;color: #24292e;"><code><span class="line"><span class="token" style="color: #d73a49;">let</span><span class="token"> attributedText </span><span class="token" style="color: #d73a49;">=</span><span class="token"> </span><span class="token" style="color: #032f62;">&quot;</span><span class="token" style="color: #032f62;">Hello dark mode</span><span class="token" style="color: #032f62;">&quot;</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token">let attributes:</span><span class="token"> </span><span class="token">[</span><span class="token">NSAttributedString.</span><span class="token" style="color: #005cc5;">Key</span><span class="token">:</span><span class="token"> </span><span class="token" style="color: #005cc5;">AnyObject</span><span class="token">]</span><span class="token"> </span><span class="token" style="color: #d73a49;">=</span><span class="token"> [
</span></span><span class="line"><span class="token">    .</span><span class="token">font</span><span class="token" style="color: #d73a49;">:</span><span class="token"> UIFont.</span><span class="token">preferredFont(</span><span class="token">forTextStyle:</span><span class="token"> .</span><span class="token">body</span><span class="token">)</span><span class="token">,
</span></span><span class="line"><span class="token">    .</span><span class="token">foregroundColor</span><span class="token" style="color: #d73a49;">:</span><span class="token"> .</span><span class="token">label</span><span class="token">
</span></span><span class="line"><span class="token">]
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token">attributedText.</span><span class="token">draw(</span><span class="token">at:</span><span class="token"> .</span><span class="token">zero</span><span class="token">, </span><span class="token">withAttributes:</span><span class="token"> attributes</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span></code></pre></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1676"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-1674">
	<h2	class='typography typography--size-52-default js-typography block-heading__heading'
	data-id='es-1675'
	>
	5. Responding to appearance changes</h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1679"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-1677">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-1678'
	>
	Whenever users change their appearance styles, several methods get called. You can leverage this by putting any additional UI logic which depends on the current appearance into these methods:</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1682"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="lists" data-id="es-1680">
	<ul	class='typography typography--size-16-text-roman js-typography lists__typography'
	data-id='es-1681'
	>
	<li>UIViewController – <em>viewWillLayoutSubviews()</em>,</li><li>UIPresentationController – <em>containerViewWillLayoutSubviews()</em>,</li><li>UIView – <em>layoutSubviews()</em> and <em>tintColorDidChange()</em>.</li></ul></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1685"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-1683">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-1684'
	>
	In addition, since all those objects conform to the <em>UITraitEnviromentprotocol</em>, <em>traitCollectionDidChange()</em> will also get called.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1688"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-1686">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-1687'
	>
	To simplify–if you’ve been initializing your colors/images in the <em>init</em> and <em>viewDidLoadmethods</em>, move that logic into the <em>layoutSubviews()</em> and <em>viewDidLayoutSubiews()</em> methods and you should be good to go. Any additional logic you have regarding the appearance can go into the <em>traitCollectionDidChange()</em> method, which will also get called when the appearance updates.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1691"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-1689">
	<h2	class='typography typography--size-52-default js-typography block-heading__heading'
	data-id='es-1690'
	>
	But… What if I don’t want to support it?</h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1694"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-1692">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-1693'
	>
	Having read all of the above, this question may have popped into your head, and it’s a perfectly valid dilemma.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1697"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-1695">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-1696'
	>
	There are several reasons why you wouldn’t want to add dark mode support: perhaps there’s no time to implement it properly or your brand guidelines are centered around light themes, to name only a few. Luckily for you, it’s really easy to disable dark mode and forget all about it.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1700"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-1698">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-1699'
	>
	There are three main ways to do this:</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1703"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="lists" data-id="es-1701">
	<ul	class='typography typography--size-16-text-roman js-typography lists__typography'
	data-id='es-1702'
	>
	<li>set <em>UIUserInterfaceStyle</em> to <em>Light</em> in your info.plist,</li><li>override the appearance in the <em>UIScreen</em>,</li><li>keep shipping your app with older Xcode versions.</li></ul></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1706"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-1704">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-1705'
	>
	For partial support, just override interface styles on screens where you don’t want to support dark mode by using the code shown in the first heading, <strong>1. Understanding the trait collection</strong>.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1709"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-1707">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-1708'
	>
	However, keep in mind that <strong>Apple really wants you to fully support dark mode</strong>, and their quote from WWDC should really drive that point home.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1714"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="blockquote block-blockquote__blockquote" data-id="es-1710">
	
	<div class="blockquote__content">
		<i
	class="icon blockquote__icon icon--size-16 icon--scale-100"
	 aria-hidden='true' data-name='blockquote-24' data-id='es-1711'>
	<svg fill='none' height='24' viewBox='0 0 24 24' width='24' xmlns='http://www.w3.org/2000/svg'><path clip-rule='evenodd' d='m12 24c6.6274 0 12-5.3726 12-12 0-2.79685-.9568-5.37021-2.561-7.41062-.581.22951-1.0832.60583-1.5069 1.12898-.5132.60844-.7698 1.41969-.7698 2.43375v.07605h2.5789v5.59004h-5.6197v-5.01962c0-1.11547.154-2.06616.4619-2.85205.3336-.81125.757-1.48307 1.2702-2.01545.528-.52161 1.1175-.92155 1.7687-1.1998-2.0728-1.70651-4.7279-2.73128-7.6223-2.73128-6.62742 0-12 5.37258-12 12 0 6.6274 5.37258 12 12 12zm-3.53811-18.05347c-.30793.78589-.46189 1.73658-.46189 2.85205v5.01962h5.6197v-5.59004h-2.5789v-.07605c0-1.01406.2566-1.82531.7698-2.43375.5389-.63379 1.1804-1.05209 1.9245-1.2549v-2.28164c-.7441.07605-1.4626.25351-2.1555.53238-.6928.27887-1.3086.68449-1.84752 1.21688-.51321.53238-.9366 1.2042-1.27019 2.01545z' fill='currentColor' fill-rule='evenodd'/></svg></i><p	class='typography typography--size-36-text js-typography blockquote__quote'
	data-id='es-1712'
	>
	“You really don’t want to be that one light appearance that’s stuck in dark appearance.”.</p>
		<div class="blockquote__caption-wrap">
					</div>
	</div>
</div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1717"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-1715">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-1716'
	>
	In other words, not switching to dark mode will make you the black sheep… If that makes any sense.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1720"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-1718">
	<h2	class='typography typography--size-52-default js-typography block-heading__heading'
	data-id='es-1719'
	>
	The dark mode sees the light of day</h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1723"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-1721">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-1722'
	>
	We’ve been eagerly anticipating dark mode on iOS ever since Apple released it on the Mac last year–and it’s finally here.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1726"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-1724">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-1725'
	>
	It appears to be a much-needed trigger which will encourage more iOS developers to look into app theming. By following the steps I’ve detailed in this post, you’ll be on course for perfecting dark mode in no time.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1729"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-1727">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-1728'
	>
	Go ahead, <a href="https://www.youtube.com/watch?v=O4irXQhgMqg">paint it black</a>. Happy theming!</p></div>	</div>
</div>
</div>		</div>
	</div><p>The post <a href="https://infinum.com/blog/how-to-prepare-your-app-for-dark-mode-in-ios-13/">How to Prepare Your App for Dark Mode in iOS 13</a> appeared first on <a href="https://infinum.com">Infinum</a>.</p>
]]>
				</content:encoded>
			</item>
					<item>
				<image>
					<url>7928https://infinum.com/uploads/2019/07/10-minute-tips-to-make-your-iOS-app-more-interactive-0.webp</url>
				</image>
				<title>10-Minute Tips to Make Your iOS App More Interactive</title>
				<link>https://infinum.com/blog/10-minute-tips-to-make-your-ios-app-more-interactive/</link>
				<pubDate>Tue, 09 Jul 2019 14:05:00 +0000</pubDate>
				<dc:creator>Goran Brlas</dc:creator>
				<guid isPermaLink="false">https://infinum.com/the-capsized-eight/10-minute-tips-to-make-your-ios-app-more-interactive/</guid>
				<description>
					<![CDATA[<p>Most people prefer visual interfaces to command line terminals. Learn how to increase app engagement and make your app stand out!</p>
<p>The post <a href="https://infinum.com/blog/10-minute-tips-to-make-your-ios-app-more-interactive/">10-Minute Tips to Make Your iOS App More Interactive</a> appeared first on <a href="https://infinum.com">Infinum</a>.</p>
]]>
				</description>
				<content:encoded>
					<![CDATA[<div
	class="wrapper"
	data-id="es-1827"
	 data-animation-target='inner-items'>
		
			<div class="wrapper__inner">
			<div class="block-blog-content js-block-blog-content">
	
<div class="block-blog-content-sidebar" data-id="es-1732">
	</div>

<div class="block-blog-content-main">
	
<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1735"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-1733">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-1734'
	>
	What do crows like? Shiny things. Us humans are not that different, which is why most people prefer using visual interfaces instead of command line terminals.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1738"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-1736">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-1737'
	>
	We love good looking, fluid, modern, responsive, and touch-sensitive applications which provide feedback. We geek out over good looking animations and apps that come alive as we use them. In short, <strong>we love our apps shiny</strong>.&nbsp;</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1741"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-1739">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-1740'
	>
	As developers, too often we focus on functionalities and just getting things done. If a user story or client requirement is completed and it works, we will pat ourselves on the back and call it a day. But what if we spent just a <strong>few more minutes</strong> to make things – you’ve guessed it – shinier?</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1744"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-1742">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-1743'
	>
	This blog post will provide you with <strong>4 quick and easy ways to make your apps stand out</strong> in the sea of similar ones, and all it’s going to take is a few minutes of your time.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1747"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-1745">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-1746'
	>
	Waiting for the coffee to brew or the microwave to finish heating up your food? Spend those few minutes adding these into your apps, and make it easier for users to pick your app as their favourite.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1750"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-1748">
	<h2	class='typography typography--size-52-default js-typography block-heading__heading'
	data-id='es-1749'
	>
	Round them&nbsp;up</h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1753"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-1751">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-1752'
	>
	Rectangles; they are everywhere. Let’s take two common UI elements to demonstrate this – the trusty <strong>button</strong> and the all-knowing, albeit non-native, <strong>progress bar.</strong> When customizing their look, we would probably come up with something like this:</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1756"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-media">
	<div	class="media block-media__media media__border--none media__align--center-center"
	data-id="es-1754"
	 data-media-type='image'>

	<figure class="image block-media__image-figure image--size-stretch" data-id="es-1755">
	<picture class="image__picture block-media__image-picture">
												<img
					src="https://infinum.com/uploads/2019/06/10-minute-tips-to-make-your-iOS-app-more-interactive-1.webp"
					class="image__img block-media__image-img"
					alt=""
										height="208"
															width="514"
										loading="lazy"
					 />
					</picture>

	</figure></div></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1759"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-1757">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-1758'
	>
	Sure, they get the job done as best as they can; the button can be clicked and the progress bar shows the current progress (duh). However, are they any different from all other generic UI elements we see throughout the apps we are using? Not really. Let’s change this!</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1762"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-1760">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-1761'
	>
	With just a few lines of code, we can easily make them stand out more, and make the UI itself more pleasing to the eye.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1764"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-code">
	<pre class="phiki language-swift github-light" data-language="swift" style="background-color: #fff;color: #24292e;"><code><span class="line"><span class="token" style="color: #d73a49;">public</span><span class="token"> </span><span class="token" style="color: #d73a49;">extension</span><span class="token"> </span><span class="token" style="color: #6f42c1;">UIView</span><span class="token"> </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token" style="color: #6a737d;">///</span><span class="token" style="color: #6a737d;"> Corner radius of view; also inspectable from Storyboard.</span><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token" style="color: #d73a49;">@IBInspectable</span><span class="token"> </span><span class="token">var cornerRadius:</span><span class="token"> CGFloat </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">        </span><span class="token" style="color: #d73a49;">get</span><span class="token"> </span><span class="token">{</span><span class="token"> </span><span class="token" style="color: #d73a49;">return</span><span class="token"> layer.</span><span class="token">cornerRadius</span><span class="token"> </span><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token">        </span><span class="token" style="color: #d73a49;">set</span><span class="token"> </span><span class="token">(</span><span class="token">cornerRadius</span><span class="token">)</span><span class="token"> </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">            layer.</span><span class="token">masksToBounds</span><span class="token"> </span><span class="token" style="color: #d73a49;">=</span><span class="token"> </span><span class="token" style="color: #005cc5;">true</span><span class="token">
</span></span><span class="line"><span class="token">            layer.</span><span class="token">cornerRadius</span><span class="token"> </span><span class="token" style="color: #d73a49;">=</span><span class="token"> cornerRadius
</span></span><span class="line"><span class="token">        </span><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span></code></pre></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1767"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-1765">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-1766'
	>
	Since UIButton is also a type of UIView, no additional code is necessary to make our button rounded as well. All we have to do is set the proper corner radius in the storyboard. After applying this small change, our <strong>rounded UI</strong> looks much nicer and, dare I say, <em>shinier</em>.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1770"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-media">
	<div	class="media block-media__media media__border--none media__align--center-center"
	data-id="es-1768"
	 data-media-type='image'>

	<figure class="image block-media__image-figure image--size-stretch" data-id="es-1769">
	<picture class="image__picture block-media__image-picture">
												<img
					src="https://infinum.com/uploads/2019/06/10-minute-tips-to-make-your-iOS-app-more-interactive-2.webp"
					class="image__img block-media__image-img"
					alt=""
										height="204"
															width="510"
										loading="lazy"
					 />
					</picture>

	</figure></div></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1773"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-1771">
	<h2	class='typography typography--size-52-default js-typography block-heading__heading'
	data-id='es-1772'
	>
	Feedback is important</h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1776"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-1774">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-1775'
	>
	Apple started taking device vibrations more seriously when they removed the home button from the iPhone 7 and 7 Plus. The various haptic signals needed for all the actions in this new buttonless device required Apple to build a 2nd generation of the Taptic Engine, as well as several frameworks in a bundle called <strong>Haptic Feedback</strong> to easily use this new technology. These frameworks are available from iOS 10, which in 2019 means most of your target audience’s devices support it.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1779"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-1777">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-1778'
	>
	There are three main types of feedback generators that we can use:</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1782"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="lists" data-id="es-1780">
	<ul	class='typography typography--size-16-text-roman js-typography lists__typography'
	data-id='es-1781'
	>
	<li><strong>UISelectionFeedbackGenerator</strong> indicates that the selection is actively changing. This feedback type is intended for communicating movement through a series of discrete values. Apple uses it throughout the system (e.g. toggle, picker wheel etc.) and if you provide a custom way for users to pick or select something, you should probably be using it as well.</li><li><strong>UINotificationFeedbackGenerator</strong> should notify the user that a task or action, such as making a payment or saving to a database, have completed, along with the completion state which should be obvious without looking at the screen. It has three variations:&nbsp;<code>.success</code>,&nbsp;<code>.warning</code>, and&nbsp;<code>.error</code>, which should be used accordingly.</li><li><strong>UIImpactFeedbackGenerator</strong> provides a physical means of complementing the visual experience. For example, the user might feel a thud when a view slides into place or two objects collide. Same as <em>UINotificationFeedbackGenerator</em>, this one also has three variations:&nbsp;<code>.light</code>,&nbsp;<code>.medium</code>, and&nbsp;<code>.heavy</code>.</li></ul></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1785"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-1783">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-1784'
	>
	Haptic signals are a great way to complement an app’s interface and create a stunning user experience overall. In addition, iOS 13 expands on this with the ability to create your own feedback patterns, which could result in interesting ways of interacting with our phones.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1788"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-1786">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-1787'
	>
	One thing to keep in mind is that you shouldn’t go overboard and make the device vibrate at all times. As uncle Ben said in the first Spider-man movie, <em>”With great power comes great responsibility”</em>, so use haptic feedback wisely and with purpose.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1791"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-1789">
	<h2	class='typography typography--size-52-default js-typography block-heading__heading'
	data-id='es-1790'
	>
	Ups and&nbsp;downs</h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1794"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-1792">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-1793'
	>
	Following along with the theme of notifying users of their actions, let’s switch from haptic to <strong>visual feedback</strong>. We’ve all used buttons inside our applications – when we press them, some action occurs. If we use Apple’s default buttons, they change the colour a bit, which notifies us something’s happened. Although subtle, the effect serves its purpose rather great. But why stop at that – why not make it look even better?&nbsp;</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1797"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-1795">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-1796'
	>
	What we can do here is implement button scaling when it’s highlighted, which (subjectively) looks a lot better. The code for that is pretty straightforward:</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1799"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-code">
	<pre class="phiki language-swift github-light" data-language="swift" style="background-color: #fff;color: #24292e;"><code><span class="line"><span class="token">class AnimatedButton</span><span class="token">:</span><span class="token"> </span><span class="token" style="color: #6f42c1;">RoundButton </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token" style="color: #d73a49;">override</span><span class="token"> </span><span class="token">var isHighlighted:</span><span class="token"> </span><span class="token" style="color: #005cc5;">Bool</span><span class="token"> </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">        </span><span class="token" style="color: #d73a49;">didSet</span><span class="token"> </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">            </span><span class="token">let transform:</span><span class="token"> CGAffineTransform </span><span class="token" style="color: #d73a49;">=</span><span class="token"> isHighlighted </span><span class="token" style="color: #d73a49;">?</span><span class="token"> .</span><span class="token" style="color: #d73a49;">init</span><span class="token">(</span><span class="token">scaleX:</span><span class="token"> </span><span class="token" style="color: #005cc5;">0.95</span><span class="token">, </span><span class="token">y:</span><span class="token"> </span><span class="token" style="color: #005cc5;">0.95</span><span class="token">)</span><span class="token"> </span><span class="token" style="color: #d73a49;">:</span><span class="token"> .</span><span class="token" style="color: #005cc5;">identity</span><span class="token">
</span></span><span class="line"><span class="token">            </span><span class="token">animate(</span><span class="token">transform</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">        </span><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token" style="color: #d73a49;">private</span><span class="token"> </span><span class="token" style="color: #d73a49;">extension</span><span class="token"> </span><span class="token" style="color: #6f42c1;">AnimatedButton</span><span class="token"> </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token" style="color: #d73a49;">private</span><span class="token"> </span><span class="token">func animate</span><span class="token">(</span><span class="token">_ transform</span><span class="token">: </span><span class="token">CGAffineTransform</span><span class="token">)</span><span class="token"> </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">        UIView.</span><span class="token">animate(</span><span class="token">
</span></span><span class="line"><span class="token">            </span><span class="token">withDuration:</span><span class="token"> </span><span class="token" style="color: #005cc5;">0.4</span><span class="token">,
</span></span><span class="line"><span class="token">            </span><span class="token">delay:</span><span class="token"> </span><span class="token" style="color: #005cc5;">0</span><span class="token">,
</span></span><span class="line"><span class="token">            </span><span class="token">usingSpringWithDamping:</span><span class="token"> </span><span class="token" style="color: #005cc5;">0.5</span><span class="token">,
</span></span><span class="line"><span class="token">            </span><span class="token">initialSpringVelocity:</span><span class="token"> </span><span class="token" style="color: #005cc5;">3</span><span class="token">,
</span></span><span class="line"><span class="token">            </span><span class="token">options:</span><span class="token"> [.</span><span class="token">curveEaseInOut</span><span class="token">],
</span></span><span class="line"><span class="token">            </span><span class="token">animations:</span><span class="token"> </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">                </span><span class="token" style="color: #005cc5;">self</span><span class="token">.</span><span class="token">transform</span><span class="token"> </span><span class="token" style="color: #d73a49;">=</span><span class="token"> transform
</span></span><span class="line"><span class="token">            </span><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">        </span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span></code></pre></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1802"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-1800">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-1801'
	>
	As you can notice, we have also used our <em>RoundButton</em> created before. They fit together perfectly, and this is what it looks like in action:</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1805"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-media">
	<div	class="media block-media__media media__border--none media__align--center-center"
	data-id="es-1803"
	 data-media-type='video'>

	<div class="video__wrapper" data-id="es-1804">
		<video
		class="video block-media__video js-video js-block-media-video video--cursor-takeover-use"
		 loop autoplay playsinline muted preload='metadata'>
		<source  src='https://infinum.com/uploads/2019/07/10-minute-tips-to-make-your-ios-app-more-interactive-3.mp4' type='video/mp4' />	</video>
	</div></div></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1808"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-1806">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-1807'
	>
	You can also do something similar for the tab bar items in the <em>UITabBarControllerDelegate’s tabBarController(_&nbsp;: didSelect:)</em> method. It looks really nice and provides a visual pop. For bonus points, add selection haptic feedback for a well-rounded user experience.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1811"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-media">
	<div	class="media block-media__media media__border--none media__align--center-center"
	data-id="es-1809"
	 data-media-type='video'>

	<div class="video__wrapper" data-id="es-1810">
		<video
		class="video block-media__video js-video js-block-media-video video--cursor-takeover-use"
		 loop autoplay playsinline muted preload='metadata'>
		<source  src='https://infinum.com/uploads/2019/07/10-minute-tips-to-make-your-ios-app-more-interactive-4.mp4' type='video/mp4' />	</video>
	</div></div></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1814"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-1812">
	<h2	class='typography typography--size-52-default js-typography block-heading__heading'
	data-id='es-1813'
	>
	Tab sliding</h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1817"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-1815">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-1816'
	>
	Last but not least, we will return to our tab bar controller for a moment. When we tap on the bar items, their respective view controllers come into focus. Good thing about Apple’s implementation of this is that their state is preserved when switching. However, the result is slightly basic-looking, which we don’t want. Why not switch it up a bit and improve the looks of this, too?&nbsp;</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1820"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-1818">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-1819'
	>
	All we need are a few lines of code to <strong>animate the transition of our view controllers</strong>:</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1822"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-code">
	<pre class="phiki language-swift github-light" data-language="swift" style="background-color: #fff;color: #24292e;"><code><span class="line"><span class="token" style="color: #d73a49;">extension</span><span class="token"> </span><span class="token" style="color: #6f42c1;">TabBarController</span><span class="token">:</span><span class="token"> </span><span class="token" style="color: #6f42c1;">UITabBarControllerDelegate </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token">func tabBarController</span><span class="token">(</span><span class="token">_ tabBarController</span><span class="token">: </span><span class="token">UITabBarController</span><span class="token">, </span><span class="token">shouldSelect viewController</span><span class="token">: </span><span class="token">UIViewController</span><span class="token">)</span><span class="token"> </span><span class="token" style="color: #d73a49;">-&gt;</span><span class="token"> </span><span class="token" style="color: #005cc5;">Bool</span><span class="token"> </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">        </span><span class="token" style="color: #d73a49;">guard</span><span class="token">
</span></span><span class="line"><span class="token">            </span><span class="token" style="color: #d73a49;">let</span><span class="token"> tabViewControllers </span><span class="token" style="color: #d73a49;">=</span><span class="token"> tabBarController.viewControllers,
</span></span><span class="line"><span class="token">            </span><span class="token" style="color: #d73a49;">let</span><span class="token"> targetIndex </span><span class="token" style="color: #d73a49;">=</span><span class="token"> tabViewControllers.</span><span class="token">firstIndex(</span><span class="token">of:</span><span class="token"> viewController</span><span class="token">)</span><span class="token">,
</span></span><span class="line"><span class="token">            </span><span class="token" style="color: #d73a49;">let</span><span class="token"> targetView </span><span class="token" style="color: #d73a49;">=</span><span class="token"> tabViewControllers</span><span class="token">[</span><span class="token">targetIndex</span><span class="token">]</span><span class="token">.</span><span class="token" style="color: #005cc5;">view</span><span class="token">,
</span></span><span class="line"><span class="token">            </span><span class="token" style="color: #d73a49;">let</span><span class="token"> currentViewController </span><span class="token" style="color: #d73a49;">=</span><span class="token"> selectedViewController,
</span></span><span class="line"><span class="token">            </span><span class="token" style="color: #d73a49;">let</span><span class="token"> currentIndex </span><span class="token" style="color: #d73a49;">=</span><span class="token"> tabViewControllers.</span><span class="token">firstIndex(</span><span class="token">of:</span><span class="token"> currentViewController</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">            </span><span class="token" style="color: #d73a49;">else</span><span class="token"> </span><span class="token">{</span><span class="token"> </span><span class="token" style="color: #d73a49;">return</span><span class="token"> </span><span class="token" style="color: #005cc5;">false</span><span class="token"> </span><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token">        </span><span class="token" style="color: #d73a49;">if</span><span class="token"> currentIndex </span><span class="token" style="color: #d73a49;">!=</span><span class="token"> targetIndex </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">            </span><span class="token">animateToView(</span><span class="token">targetView</span><span class="token">, </span><span class="token">at:</span><span class="token"> targetIndex</span><span class="token">, </span><span class="token">from:</span><span class="token"> currentViewController.</span><span class="token" style="color: #005cc5;">view</span><span class="token">, </span><span class="token">at:</span><span class="token"> currentIndex</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">        </span><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token">        </span><span class="token" style="color: #d73a49;">return</span><span class="token"> </span><span class="token" style="color: #005cc5;">true</span><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token" style="color: #d73a49;">private</span><span class="token"> </span><span class="token" style="color: #d73a49;">extension</span><span class="token"> </span><span class="token" style="color: #6f42c1;">TabBarController</span><span class="token"> </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token">func animateToView</span><span class="token">(</span><span class="token">_ toView</span><span class="token">: </span><span class="token">UIView</span><span class="token">, </span><span class="token">at toIndex</span><span class="token">: </span><span class="token" style="color: #005cc5;">Int</span><span class="token">, </span><span class="token">from fromView</span><span class="token">: </span><span class="token">UIView</span><span class="token">, </span><span class="token">at fromIndex</span><span class="token">: </span><span class="token" style="color: #005cc5;">Int</span><span class="token">)</span><span class="token"> </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">        </span><span class="token" style="color: #6a737d;">//</span><span class="token" style="color: #6a737d;"> Position toView off screen (to the left/right of fromView)</span><span class="token">
</span></span><span class="line"><span class="token">        </span><span class="token" style="color: #d73a49;">let</span><span class="token"> screenWidth </span><span class="token" style="color: #d73a49;">=</span><span class="token"> UIScreen.</span><span class="token">main</span><span class="token">.</span><span class="token">bounds</span><span class="token">.</span><span class="token" style="color: #005cc5;">size</span><span class="token">.</span><span class="token">width</span><span class="token">
</span></span><span class="line"><span class="token">        </span><span class="token" style="color: #d73a49;">let</span><span class="token"> offset </span><span class="token" style="color: #d73a49;">=</span><span class="token"> toIndex </span><span class="token" style="color: #d73a49;">&gt;</span><span class="token"> fromIndex </span><span class="token" style="color: #d73a49;">?</span><span class="token"> screenWidth </span><span class="token" style="color: #d73a49;">:</span><span class="token"> </span><span class="token" style="color: #d73a49;">-</span><span class="token">screenWidth
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token">        toView.</span><span class="token">frame</span><span class="token">.</span><span class="token">origin</span><span class="token"> </span><span class="token" style="color: #d73a49;">=</span><span class="token"> </span><span class="token">CGPoint(</span><span class="token">
</span></span><span class="line"><span class="token">            </span><span class="token">x:</span><span class="token"> toView.</span><span class="token">frame</span><span class="token">.</span><span class="token">origin</span><span class="token">.</span><span class="token">x</span><span class="token"> </span><span class="token" style="color: #d73a49;">+</span><span class="token"> offset</span><span class="token">,
</span></span><span class="line"><span class="token">            </span><span class="token">y:</span><span class="token"> toView.</span><span class="token">frame</span><span class="token">.</span><span class="token">origin</span><span class="token">.</span><span class="token">y</span><span class="token">
</span></span><span class="line"><span class="token">        </span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token">        fromView.</span><span class="token">superview</span><span class="token" style="color: #d73a49;">?</span><span class="token">.</span><span class="token">addSubview(</span><span class="token">toView</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token">        </span><span class="token" style="color: #6a737d;">//</span><span class="token" style="color: #6a737d;"> Disable interaction during animation</span><span class="token">
</span></span><span class="line"><span class="token">        view.</span><span class="token">isUserInteractionEnabled</span><span class="token"> </span><span class="token" style="color: #d73a49;">=</span><span class="token"> </span><span class="token" style="color: #005cc5;">false</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token">        UIView.</span><span class="token">animate(</span><span class="token">
</span></span><span class="line"><span class="token">            </span><span class="token">withDuration:</span><span class="token"> </span><span class="token" style="color: #005cc5;">0.5</span><span class="token">,
</span></span><span class="line"><span class="token">            </span><span class="token">delay:</span><span class="token"> </span><span class="token" style="color: #005cc5;">0.0</span><span class="token">,
</span></span><span class="line"><span class="token">            </span><span class="token">usingSpringWithDamping:</span><span class="token"> </span><span class="token" style="color: #005cc5;">0.75</span><span class="token">,
</span></span><span class="line"><span class="token">            </span><span class="token">initialSpringVelocity:</span><span class="token"> </span><span class="token" style="color: #005cc5;">0.5</span><span class="token">,
</span></span><span class="line"><span class="token">            </span><span class="token">options:</span><span class="token"> .</span><span class="token">curveEaseInOut</span><span class="token">,
</span></span><span class="line"><span class="token">            </span><span class="token">animations:</span><span class="token"> </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">                </span><span class="token" style="color: #6a737d;">//</span><span class="token" style="color: #6a737d;"> Slide the views by -offset</span><span class="token">
</span></span><span class="line"><span class="token">                fromView.</span><span class="token">center</span><span class="token"> </span><span class="token" style="color: #d73a49;">=</span><span class="token"> </span><span class="token">CGPoint(</span><span class="token">x:</span><span class="token"> fromView.</span><span class="token">center</span><span class="token">.</span><span class="token">x</span><span class="token"> </span><span class="token" style="color: #d73a49;">-</span><span class="token"> offset</span><span class="token">, </span><span class="token">y:</span><span class="token"> fromView.</span><span class="token">center</span><span class="token">.</span><span class="token">y</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">                toView.</span><span class="token">center</span><span class="token"> </span><span class="token" style="color: #d73a49;">=</span><span class="token"> </span><span class="token">CGPoint(</span><span class="token">x:</span><span class="token"> toView.</span><span class="token">center</span><span class="token">.</span><span class="token">x</span><span class="token"> </span><span class="token" style="color: #d73a49;">-</span><span class="token"> offset</span><span class="token">, </span><span class="token">y:</span><span class="token"> toView.</span><span class="token">center</span><span class="token">.</span><span class="token">y</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">            </span><span class="token">}</span><span class="token">,
</span></span><span class="line"><span class="token">            </span><span class="token">completion:</span><span class="token"> </span><span class="token">{</span><span class="token"> </span><span class="token" style="color: #005cc5;">_</span><span class="token"> </span><span class="token" style="color: #d73a49;">in</span><span class="token">
</span></span><span class="line"><span class="token">                </span><span class="token" style="color: #6a737d;">//</span><span class="token" style="color: #6a737d;"> Remove the old view from the tabbar view.</span><span class="token">
</span></span><span class="line"><span class="token">                fromView.</span><span class="token">removeFromSuperview(</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">                </span><span class="token" style="color: #005cc5;">self</span><span class="token">.</span><span class="token">selectedIndex</span><span class="token"> </span><span class="token" style="color: #d73a49;">=</span><span class="token"> toIndex
</span></span><span class="line"><span class="token">                </span><span class="token" style="color: #005cc5;">self</span><span class="token">.</span><span class="token" style="color: #005cc5;">view</span><span class="token">.</span><span class="token">isUserInteractionEnabled</span><span class="token"> </span><span class="token" style="color: #d73a49;">=</span><span class="token"> </span><span class="token" style="color: #005cc5;">true</span><span class="token">
</span></span><span class="line"><span class="token">            </span><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">        </span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span></code></pre></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1825"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-1823">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-1824'
	>
	After doing this, our tab switching should have a fresh new look, like in the example below:</p></div>	</div>
</div>
</div>		</div>
	</div>

<div
	class="wrapper"
	data-id="es-1830"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="wrapper__inner">
			<div class="block-media">
	<div	class="media block-media__media media__border--none media__align--center-center"
	data-id="es-1828"
	 data-media-type='video'>

	<div class="video__wrapper" data-id="es-1829">
		<video
		class="video block-media__video js-video js-block-media-video video--cursor-takeover-use"
		 loop autoplay playsinline muted preload='metadata'>
		<source  src='https://infinum.com/uploads/2019/07/10-minute-tips-to-make-your-ios-app-more-interactive-5.mp4' type='video/mp4' />	</video>
	</div></div></div>		</div>
	</div>

<div
	class="wrapper"
	data-id="es-1845"
	 data-animation-target='inner-items'>
		
			<div class="wrapper__inner">
			<div class="block-blog-content js-block-blog-content">
	
<div class="block-blog-content-sidebar" data-id="es-1831">
	</div>

<div class="block-blog-content-main">
	
<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1834"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-1832">
	<h2	class='typography typography--size-52-default js-typography block-heading__heading'
	data-id='es-1833'
	>
	Wrapping it up</h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1837"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-1835">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-1836'
	>
	If you’re underwhelmed when using applications with bland interfaces, you shouldn’t be satisfied with creating them either. Sudden UI changes or no feedback on inputs could result in users thinking they might have done something wrong or question whether anything is happening under the hood at all.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1840"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-1838">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-1839'
	>
	Listed above are just some of the ways you can increase app engagement and make it stand out. The best thing is they are so easy to execute and so helpful in capturing the attention of users!</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1843"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-1841">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-1842'
	>
	Got any tips &amp; tricks of your own? Feel free to leave them in the comments below, we’re always eager to learn new things.</p></div>	</div>
</div>
</div>		</div>
	</div><p>The post <a href="https://infinum.com/blog/10-minute-tips-to-make-your-ios-app-more-interactive/">10-Minute Tips to Make Your iOS App More Interactive</a> appeared first on <a href="https://infinum.com">Infinum</a>.</p>
]]>
				</content:encoded>
			</item>
					<item>
				<image>
					<url>7910https://infinum.com/uploads/2019/01/crash-course-in-augmented-reality-on-ios-with-arkit-0.webp</url>
				</image>
				<title>A Crash Course in Augmented Reality on iOS with ARKit</title>
				<link>https://infinum.com/blog/crash-course-in-augmented-reality-on-ios-with-arkit/</link>
				<pubDate>Mon, 28 Jan 2019 14:40:00 +0000</pubDate>
				<dc:creator>Goran Brlas</dc:creator>
				<guid isPermaLink="false">https://infinum.com/the-capsized-eight/crash-course-in-augmented-reality-on-ios-with-arkit/</guid>
				<description>
					<![CDATA[<p>Since the release of <a href="https://developer.apple.com/arkit/">ARKit</a> in 2017., and especially the 2.0 announcement during the WWDC 2018 conference, I&#8217;ve been interested in what it can provide.</p>
<p>The post <a href="https://infinum.com/blog/crash-course-in-augmented-reality-on-ios-with-arkit/">A Crash Course in Augmented Reality on iOS with ARKit</a> appeared first on <a href="https://infinum.com">Infinum</a>.</p>
]]>
				</description>
				<content:encoded>
					<![CDATA[<div
	class="wrapper"
	data-id="es-2033"
	 data-animation-target='inner-items'>
		
			<div class="wrapper__inner">
			<div class="block-blog-content js-block-blog-content">
	
<div class="block-blog-content-sidebar" data-id="es-1846">
	</div>

<div class="block-blog-content-main">
	
<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1849"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-1847">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-1848'
	>
	Since the release of <a href="https://developer.apple.com/arkit/">ARKit</a> in 2017., and especially the 2.0 announcement during the WWDC 2018 conference, I’ve been interested in what it can provide.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1852"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-1850">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-1851'
	>
	At first, I didn’t know what I was getting myself into. Coming from a computer science background with some minor experience in computer graphics and object rendering, I was expecting a lot of mathematical black magic. Turns out I was wrong.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1855"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-1853">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-1854'
	>
	Apple, always on the lookout to simplify things, built a framework that’s intuitive and easy to use but packed with powerful features at the same time. If you know your way around XCode and the basics of iOS development, you could be up and running in no time, even if you haven’t touched AR or 3D modeling before.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1858"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-1856">
	<h2	class='typography typography--size-52-default js-typography block-heading__heading'
	data-id='es-1857'
	>
	Demystifying Augmented Reality</h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1861"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-1859">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-1860'
	>
	So what is augmented reality? A short definition I found on <a href="https://whatis.techtarget.com">whatis</a> explains it quite nicely:</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1866"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="blockquote block-blockquote__blockquote" data-id="es-1862">
	
	<div class="blockquote__content">
		<i
	class="icon blockquote__icon icon--size-16 icon--scale-100"
	 aria-hidden='true' data-name='blockquote-24' data-id='es-1863'>
	<svg fill='none' height='24' viewBox='0 0 24 24' width='24' xmlns='http://www.w3.org/2000/svg'><path clip-rule='evenodd' d='m12 24c6.6274 0 12-5.3726 12-12 0-2.79685-.9568-5.37021-2.561-7.41062-.581.22951-1.0832.60583-1.5069 1.12898-.5132.60844-.7698 1.41969-.7698 2.43375v.07605h2.5789v5.59004h-5.6197v-5.01962c0-1.11547.154-2.06616.4619-2.85205.3336-.81125.757-1.48307 1.2702-2.01545.528-.52161 1.1175-.92155 1.7687-1.1998-2.0728-1.70651-4.7279-2.73128-7.6223-2.73128-6.62742 0-12 5.37258-12 12 0 6.6274 5.37258 12 12 12zm-3.53811-18.05347c-.30793.78589-.46189 1.73658-.46189 2.85205v5.01962h5.6197v-5.59004h-2.5789v-.07605c0-1.01406.2566-1.82531.7698-2.43375.5389-.63379 1.1804-1.05209 1.9245-1.2549v-2.28164c-.7441.07605-1.4626.25351-2.1555.53238-.6928.27887-1.3086.68449-1.84752 1.21688-.51321.53238-.9366 1.2042-1.27019 2.01545z' fill='currentColor' fill-rule='evenodd'/></svg></i><p	class='typography typography--size-36-text js-typography blockquote__quote'
	data-id='es-1864'
	>
	Augmented reality is the integration of digital information with the user’s physical environment in real-time.</p>
		<div class="blockquote__caption-wrap">
					</div>
	</div>
</div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1869"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-1867">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-1868'
	>
	How is it actually achieved? Before jumping into the code, there are three core pillars we need to understand:</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1872"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-media">
	<div	class="media block-media__media media__border--none media__align--center-center"
	data-id="es-1870"
	 data-media-type='image'>

	<figure class="image block-media__image-figure image--size-stretch" data-id="es-1871">
	<picture class="image__picture block-media__image-picture">
												<img
					src="https://infinum.com/uploads/2019/01/crash-course-in-augmented-reality-on-ios-with-arkit-1.webp"
					class="image__img block-media__image-img"
					alt=""
										height="384"
															width="1000"
										loading="lazy"
					 />
					</picture>

	</figure></div></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1876"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="bullet bullet--left bullet__type--number bullet__color--black block-bullet__bullet" data-id="es-1873">
	<p	class='typography typography--size-14-text js-typography bullet__dot'
	data-id='es-1874'
	>
	1</p>	<div class="bullet__content">
		<p	class='typography typography--size-16-text-roman js-typography bullet__paragraph'
	data-id='es-1875'
	>
	<strong>Tracking</strong> provides the ability to track the device&#8217;s relative position in the physical environment using camera images, as well as motion data from its sensors. This data is then processed and used to get a precise view of where the device is located and its orientation.</p>	</div>
</div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1880"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="bullet bullet--left bullet__type--number bullet__color--black block-bullet__bullet" data-id="es-1877">
	<p	class='typography typography--size-14-text js-typography bullet__dot'
	data-id='es-1878'
	>
	2</p>	<div class="bullet__content">
		<p	class='typography typography--size-16-text-roman js-typography bullet__paragraph'
	data-id='es-1879'
	>
	<strong>Scene understanding</strong> builds upon tracking. It&#8217;s the ability to determine and extract attributes or properties from the environment around the device, for example, plane detection (e.g., walls, tables, chairs), collision detection, etc.</p>	</div>
</div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1884"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="bullet bullet--left bullet__type--number bullet__color--black block-bullet__bullet" data-id="es-1881">
	<p	class='typography typography--size-14-text js-typography bullet__dot'
	data-id='es-1882'
	>
	3</p>	<div class="bullet__content">
		<p	class='typography typography--size-16-text-roman js-typography bullet__paragraph'
	data-id='es-1883'
	>
	<strong>Rendering</strong>, the last pillar of AR, is used to present digital information in the real world. For the purposes of this tutorial, I&#8217;ll be using SceneKit, but virtually any household (SpriteKit, Unity, UnReal, etc.) or custom rendering engine can be used.</p>	</div>
</div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1887"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-1885">
	<h2	class='typography typography--size-52-default js-typography block-heading__heading'
	data-id='es-1886'
	>
	ARKit in&nbsp;action</h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1890"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-1888">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-1889'
	>
	Now that we’ve covered the basics, let’s put ARKit into the picture. <strong>The framework does the heavy lifting regarding tracking and scene understanding</strong>. Its job is to combine motion tracking, camera scene capture, advanced scene processing, and display conveniences to simplify the task of building an AR experience.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1893"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-media">
	<div	class="media block-media__media media__border--none media__align--center-center"
	data-id="es-1891"
	 data-media-type='image'>

	<figure class="image block-media__image-figure image--size-stretch" data-id="es-1892">
	<picture class="image__picture block-media__image-picture">
												<img
					src="https://infinum.com/uploads/2019/01/crash-course-in-augmented-reality-on-ios-with-arkit-2.webp"
					class="image__img block-media__image-img"
					alt=""
										height="426"
															width="1000"
										loading="lazy"
					 />
					</picture>

			<figcaption class="image__figcaption block-media__image-figcaption">
			ARKit image tracking pipeline		</figcaption>
	</figure></div></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1896"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-1894">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-1895'
	>
	There are two ways to implement image detection through its configurations – you could use either<strong><em> ARWorldTrackingConfiguration</em></strong> or <strong><em>ARImageTrackingConfiguration</em></strong>. </p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1899"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-1897">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-1898'
	>
	World tracking works best in a stable, non-moving environment, but it struggles if the tracked image starts to move around. That’s why ARKit 2.0 introduced the image tracking configuration. It uses <strong>known images</strong> to add virtual content to the 3D world and continues to track the position of that content even when the image position changes, simultaneously providing a steady 60 frames per second.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1902"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-1900">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-1901'
	>
	I think we’ve covered enough theory to get started, so let’s dive into some code. We’re going to be building an AR app for tracking and identifying Pokémon in the wild.<br>Just like in the cartoons!</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1905"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-1903">
	<h2	class='typography typography--size-52-default js-typography block-heading__heading'
	data-id='es-1904'
	>
	Getting our hands&nbsp;dirty</h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1908"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-1906">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-1907'
	>
	To start things off, I suggest you use the Augmented Reality app template. XCode will create a view controller with a <em>ARSCNView</em> and a starting <em>ARWorldTrackingConfiguration</em>.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1911"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-media">
	<div	class="media block-media__media media__border--none media__align--center-center"
	data-id="es-1909"
	 data-media-type='image'>

	<figure class="image block-media__image-figure image--size-stretch" data-id="es-1910">
	<picture class="image__picture block-media__image-picture">
												<img
					src="https://infinum.com/uploads/2019/01/crash-course-in-augmented-reality-on-ios-with-arkit-3.webp"
					class="image__img block-media__image-img"
					alt=""
										height="511"
															width="716"
										loading="lazy"
					 />
					</picture>

	</figure></div></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1914"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-1912">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-1913'
	>
	From the visual standpoint, this should be enough for this tutorial so I’ll leave the storyboard file as it is.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1917"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-1915">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-1916'
	>
	We’ll be focusing on image tracking, so we can pretty much delete all the boilerplate code from the view controller and start only with the basic <em>viewDidLoad()</em> and <em>viewWillAppear()</em> methods.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1919"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-code">
	<pre class="phiki language-swift github-light" data-language="swift" style="background-color: #fff;color: #24292e;"><code><span class="line"><span class="token" style="color: #d73a49;">override</span><span class="token"> </span><span class="token">func viewDidLoad</span><span class="token">(</span><span class="token">)</span><span class="token"> </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token" style="color: #005cc5;">super</span><span class="token">.</span><span class="token">viewDidLoad(</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">    sceneView.</span><span class="token">delegate</span><span class="token"> </span><span class="token" style="color: #d73a49;">=</span><span class="token"> </span><span class="token" style="color: #005cc5;">self</span><span class="token">
</span></span><span class="line"><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token" style="color: #d73a49;">override</span><span class="token"> </span><span class="token">func viewWillAppear</span><span class="token">(</span><span class="token">_ animated</span><span class="token">: </span><span class="token" style="color: #005cc5;">Bool</span><span class="token">)</span><span class="token"> </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token" style="color: #005cc5;">super</span><span class="token">.</span><span class="token">viewWillAppear(</span><span class="token">animated</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">    sceneView.</span><span class="token">session</span><span class="token">.</span><span class="token">run(</span><span class="token">configuration</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span></code></pre></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1922"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-1920">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-1921'
	>
	In <em>viewDidLoad()</em> we set the <em>sceneView’s</em> delegate. <em>ARSCNViewDelegate</em> has a set of methods that we can implement to find out whenever an anchor/ node pair has been added, updated, or removed from the scene. We’ll get to this in a minute.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1925"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-1923">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-1924'
	>
	<em>viewWillAppear()</em> implementation is also rather short. Simply tell the sceneView to start AR processing for the session with the specified configuration and optional options (since we don’t need them here, they’re omitted).</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1928"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-1926">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-1927'
	>
	Our configuration is defined separately as a computed property for better readability. This is what it looks like:</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1930"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-code">
	<pre class="phiki language-swift github-light" data-language="swift" style="background-color: #fff;color: #24292e;"><code><span class="line"><span class="token" style="color: #d73a49;">private</span><span class="token"> </span><span class="token">let configuration:</span><span class="token"> ARImageTrackingConfiguration </span><span class="token" style="color: #d73a49;">=</span><span class="token"> </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token" style="color: #d73a49;">guard</span><span class="token"> </span><span class="token" style="color: #d73a49;">let</span><span class="token"> trackingImages </span><span class="token" style="color: #d73a49;">=</span><span class="token"> ARReferenceImage.</span><span class="token">referenceImages(</span><span class="token">
</span></span><span class="line"><span class="token">        </span><span class="token">inGroupNamed:</span><span class="token"> </span><span class="token" style="color: #032f62;">&quot;</span><span class="token" style="color: #032f62;">Pokemons</span><span class="token" style="color: #032f62;">&quot;</span><span class="token">, 
</span></span><span class="line"><span class="token">        </span><span class="token">bundle:</span><span class="token"> </span><span class="token" style="color: #005cc5;">nil</span><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token" style="color: #d73a49;">else</span><span class="token"> </span><span class="token">{</span><span class="token"> </span><span class="token" style="color: #005cc5;">fatalError</span><span class="token">(</span><span class="token" style="color: #032f62;">&quot;</span><span class="token" style="color: #032f62;">Couldn&amp;#8217;t load tracking images.</span><span class="token" style="color: #032f62;">&quot;</span><span class="token">)</span><span class="token"> </span><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token" style="color: #d73a49;">let</span><span class="token"> configuration </span><span class="token" style="color: #d73a49;">=</span><span class="token"> </span><span class="token">ARImageTrackingConfiguration(</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">    configuration.</span><span class="token">trackingImages</span><span class="token"> </span><span class="token" style="color: #d73a49;">=</span><span class="token"> trackingImages
</span></span><span class="line"><span class="token">    configuration.</span><span class="token">maximumNumberOfTrackedImages</span><span class="token"> </span><span class="token" style="color: #d73a49;">=</span><span class="token"> </span><span class="token" style="color: #005cc5;">2</span><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token" style="color: #d73a49;">return</span><span class="token"> configuration
</span></span><span class="line"><span class="token">}</span><span class="token">(</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span></code></pre></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1933"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-1931">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-1932'
	>
	The first thing we need to do regarding the configuration is to specify which images we want to track. These images can either be loaded from a file or added to the Asset Catalog and then loaded as a group. I’ve decided to do the latter.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1936"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-1934">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-1935'
	>
	After the images are loaded successfully, image tracking configuration is created and its <em>trackingImages</em> parameter is set to those loaded images. One more thing we need to specify is the <em>maximumNumberOfTrackedImages</em> property, which is used to specify how many images we wish to track simultaneously. If more than this number of images is visible, only the images already being tracked will continue to be tracked until either the tracking is lost, or the image is removed from the specified <em>trackingImages</em>. This number ranges from 1 (default) to 4.<br>My guess is, as hardware and software evolves, there’ll be an option to track even more images at the same time.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1939"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-1937">
	<h2	class='typography typography--size-52-default js-typography block-heading__heading'
	data-id='es-1938'
	>
	Let the tracking begin</h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1942"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-1940">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-1941'
	>
	As I’ve mentioned previously, <em>ARSCNViewDelegate</em> provides a lot of methods for mediating the automatic synchronization of SceneKit content with an AR session. We’ll be focusing on the <code>renderer:nodeForAnchor:</code> method implementation, so let’s look at how we can handle adding nodes to the existing AR scene.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1945"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-1943">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-1944'
	>
	Here is the overview of our node creation:</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1947"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-code">
	<pre class="phiki language-swift github-light" data-language="swift" style="background-color: #fff;color: #24292e;"><code><span class="line"><span class="token">func renderer</span><span class="token">(</span><span class="token">_ renderer</span><span class="token">: </span><span class="token">SCNSceneRenderer</span><span class="token">, </span><span class="token">nodeFor anchor</span><span class="token">: </span><span class="token">ARAnchor</span><span class="token">)</span><span class="token"> </span><span class="token" style="color: #d73a49;">-&gt;</span><span class="token"> </span><span class="token">SCNNode</span><span class="token" style="color: #d73a49;">?</span><span class="token"> </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token" style="color: #d73a49;">guard</span><span class="token"> </span><span class="token" style="color: #d73a49;">let</span><span class="token"> imageAnchor </span><span class="token" style="color: #d73a49;">=</span><span class="token"> anchor </span><span class="token" style="color: #d73a49;">as?</span><span class="token"> ARImageAnchor,
</span></span><span class="line"><span class="token">        </span><span class="token" style="color: #d73a49;">let</span><span class="token"> pokemonName </span><span class="token" style="color: #d73a49;">=</span><span class="token"> imageAnchor.referenceImage.name,
</span></span><span class="line"><span class="token">        </span><span class="token" style="color: #d73a49;">let</span><span class="token"> pokemonURL </span><span class="token" style="color: #d73a49;">=</span><span class="token"> </span><span class="token">URL(</span><span class="token">
</span></span><span class="line"><span class="token">            </span><span class="token">string:</span><span class="token"> </span><span class="token" style="color: #032f62;">&quot;</span><span class="token" style="color: #032f62;">https://pokemondb.net/pokedex/</span><span class="token" style="color: #032f62;">&quot;</span><span class="token"> </span><span class="token" style="color: #d73a49;">+</span><span class="token"> pokemonName.</span><span class="token" style="color: #005cc5;">lowercased</span><span class="token">(</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">        </span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">        </span><span class="token" style="color: #d73a49;">else</span><span class="token"> </span><span class="token">{</span><span class="token"> </span><span class="token" style="color: #d73a49;">return</span><span class="token"> </span><span class="token" style="color: #005cc5;">nil</span><span class="token"> </span><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token" style="color: #d73a49;">let</span><span class="token"> pokemon </span><span class="token" style="color: #d73a49;">=</span><span class="token"> </span><span class="token">Pokemon(</span><span class="token">title:</span><span class="token"> pokemonName</span><span class="token">, </span><span class="token">URL:</span><span class="token"> pokemonURL</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token" style="color: #d73a49;">let</span><span class="token"> node </span><span class="token" style="color: #d73a49;">=</span><span class="token"> </span><span class="token">SCNNode(</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token" style="color: #d73a49;">let</span><span class="token"> overlayPlane </span><span class="token" style="color: #d73a49;">=</span><span class="token"> </span><span class="token">SCNPlane(</span><span class="token">
</span></span><span class="line"><span class="token">        </span><span class="token">width:</span><span class="token"> imageAnchor.</span><span class="token">referenceImage</span><span class="token">.</span><span class="token">physicalSize</span><span class="token">.</span><span class="token">width</span><span class="token">,
</span></span><span class="line"><span class="token">        </span><span class="token">height:</span><span class="token"> imageAnchor.</span><span class="token">referenceImage</span><span class="token">.</span><span class="token">physicalSize</span><span class="token">.</span><span class="token">height</span><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token" style="color: #6a737d;">//</span><span class="token" style="color: #6a737d;"> Add the blue-tinted overlay node.</span><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token" style="color: #d73a49;">let</span><span class="token"> overlayPlaneNode </span><span class="token" style="color: #d73a49;">=</span><span class="token"> </span><span class="token">createOverlayPlaneNode(</span><span class="token">
</span></span><span class="line"><span class="token">        </span><span class="token">for:</span><span class="token"> overlayPlane</span><span class="token">, 
</span></span><span class="line"><span class="token">        </span><span class="token">pokemon:</span><span class="token"> pokemon</span><span class="token">, 
</span></span><span class="line"><span class="token">        </span><span class="token">imageAnchor:</span><span class="token"> imageAnchor
</span></span><span class="line"><span class="token">    </span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token" style="color: #6a737d;">//</span><span class="token" style="color: #6a737d;"> Add the text node displaying what image is currently tracked.</span><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token" style="color: #d73a49;">let</span><span class="token"> textNode </span><span class="token" style="color: #d73a49;">=</span><span class="token"> </span><span class="token">createTextNode(</span><span class="token">for:</span><span class="token"> pokemon.</span><span class="token">title</span><span class="token">.</span><span class="token">capitalized</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">    textNode.</span><span class="token">pivotOnTopCenter(</span><span class="token">)</span><span class="token"> </span><span class="token" style="color: #6a737d;">//</span><span class="token" style="color: #6a737d;"> Move the point from which calculations are done.</span><span class="token">
</span></span><span class="line"><span class="token">    textNode.</span><span class="token">position</span><span class="token">.</span><span class="token">y</span><span class="token"> </span><span class="token" style="color: #d73a49;">-=</span><span class="token"> </span><span class="token" style="color: #005cc5;">Float</span><span class="token">(</span><span class="token">overlayPlane.</span><span class="token">height</span><span class="token"> </span><span class="token" style="color: #d73a49;">/</span><span class="token"> </span><span class="token" style="color: #005cc5;">2</span><span class="token">)</span><span class="token"> </span><span class="token" style="color: #d73a49;">+</span><span class="token"> </span><span class="token" style="color: #005cc5;">0.005</span><span class="token">
</span></span><span class="line"><span class="token">    overlayPlaneNode.</span><span class="token">addChildNode(</span><span class="token">textNode</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token" style="color: #6a737d;">//</span><span class="token" style="color: #6a737d;"> Add the webView node displaying the Pokemon details.</span><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token" style="color: #d73a49;">let</span><span class="token"> webViewNode </span><span class="token" style="color: #d73a49;">=</span><span class="token"> </span><span class="token">createWebViewNode(</span><span class="token">overlayPlane:</span><span class="token"> overlayPlane</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">    overlayPlaneNode.</span><span class="token">addChildNode(</span><span class="token">webViewNode</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token">    node.</span><span class="token">addChildNode(</span><span class="token">overlayPlaneNode</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token" style="color: #d73a49;">return</span><span class="token"> node
</span></span><span class="line"><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span></code></pre></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1950"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-1948">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-1949'
	>
	Let’s unpack what happens here, section-by-section. Before we get to the interesting stuff, we need to check three things:</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1954"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="bullet bullet--left bullet__type--number bullet__color--black block-bullet__bullet" data-id="es-1951">
	<p	class='typography typography--size-14-text js-typography bullet__dot'
	data-id='es-1952'
	>
	1</p>	<div class="bullet__content">
		<p	class='typography typography--size-16-text-roman js-typography bullet__paragraph'
	data-id='es-1953'
	>
	the received anchor object can actually be cast to an <em>ARImageAnchor</em> object;</p>	</div>
</div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1958"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="bullet bullet--left bullet__type--number bullet__color--black block-bullet__bullet" data-id="es-1955">
	<p	class='typography typography--size-14-text js-typography bullet__dot'
	data-id='es-1956'
	>
	2</p>	<div class="bullet__content">
		<p	class='typography typography--size-16-text-roman js-typography bullet__paragraph'
	data-id='es-1957'
	>
	that image anchor object must have a name (specified in the Asset catalog) since that&#8217;s how we differentiate detected objects;</p>	</div>
</div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1962"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="bullet bullet--left bullet__type--number bullet__color--black block-bullet__bullet" data-id="es-1959">
	<p	class='typography typography--size-14-text js-typography bullet__dot'
	data-id='es-1960'
	>
	3</p>	<div class="bullet__content">
		<p	class='typography typography--size-16-text-roman js-typography bullet__paragraph'
	data-id='es-1961'
	>
	an URL for finding the Pokémon on the Pokédex web page (I&#8217;m using the <a href="https://pokemondb.net/pokedex" target="_blank" rel="noreferrer noopener">PokémonDB</a> as the baseURL here) can be successfully created.</p>	</div>
</div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1965"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-1963">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-1964'
	>
	After passing all these checks, we can now start with the fun stuff. Firstly, we create our Pokémon object and then an empty <em>SCNNode</em> object which represents all the AR data we will show for that tracked Pokémon. This node will be a container node, which means its sole purpose is to hold a hierarchy of other nodes.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1968"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-1966">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-1967'
	>
	The next step is adding the overlay node:</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1970"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-code">
	<pre class="phiki language-swift github-light" data-language="swift" style="background-color: #fff;color: #24292e;"><code><span class="line"><span class="token">func createOverlayPlaneNode</span><span class="token">(</span><span class="token">for plane</span><span class="token">: </span><span class="token">SCNPlane</span><span class="token">, </span><span class="token">pokemon</span><span class="token">: </span><span class="token">Pokemon</span><span class="token">, </span><span class="token">imageAnchor</span><span class="token">: </span><span class="token">ARImageAnchor</span><span class="token">)</span><span class="token"> </span><span class="token" style="color: #d73a49;">-&gt;</span><span class="token"> </span><span class="token">SCNNode </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">    plane.</span><span class="token">firstMaterial</span><span class="token" style="color: #d73a49;">?</span><span class="token">.</span><span class="token">diffuse</span><span class="token">.</span><span class="token">contents</span><span class="token"> </span><span class="token" style="color: #d73a49;">=</span><span class="token"> UIColor.</span><span class="token">blue</span><span class="token">.</span><span class="token">withAlphaComponent(</span><span class="token" style="color: #005cc5;">0.5</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token" style="color: #d73a49;">let</span><span class="token"> planeNode </span><span class="token" style="color: #d73a49;">=</span><span class="token"> </span><span class="token">SCNNode(</span><span class="token">geometry:</span><span class="token"> plane</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token" style="color: #6a737d;">//</span><span class="token" style="color: #6a737d;"> Rotates the plane by -90 degrees</span><span class="token">
</span></span><span class="line"><span class="token">    planeNode.</span><span class="token">eulerAngles</span><span class="token">.</span><span class="token">x</span><span class="token"> </span><span class="token" style="color: #d73a49;">=</span><span class="token"> </span><span class="token" style="color: #d73a49;">-</span><span class="token">.</span><span class="token" style="color: #005cc5;">pi</span><span class="token"> </span><span class="token" style="color: #d73a49;">/</span><span class="token"> </span><span class="token" style="color: #005cc5;">2</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token" style="color: #d73a49;">return</span><span class="token"> planeNode
</span></span><span class="line"><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span></code></pre></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1973"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-1971">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-1972'
	>
	As its name suggests, this overlay node is laid over the tracked image. We specify its geometry to be a plane, with its width and height being the same as the image’s. After specifying the size, we can set its <em>firstMaterial?.diffuse.contents</em> property a wide array of objects we wish to use – current ARKit implementation allows us to use a color, an image, layer, scene, path, texture, video player etc..</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1976"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-1974">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-1975'
	>
	In this implementation, we will add a blue-tinted overlay showing where the tracked image is located. Another interesting option would be to set an AVPlayer as the plane material, which would then play a video connected to the specific Pokémon. Who wouldn’t like if their Charizard started spitting fire when detected? Since we’re covering the basics here, I’ll leave that out for now.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1979"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-1977">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-1978'
	>
	Another useful thing to add is the text node that would tell us which Pokémon is being tracked at the time since there could be more of them.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1981"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-code">
	<pre class="phiki language-swift github-light" data-language="swift" style="background-color: #fff;color: #24292e;"><code><span class="line"><span class="token">func textNode</span><span class="token">(</span><span class="token">for text</span><span class="token">: </span><span class="token" style="color: #005cc5;">String</span><span class="token">)</span><span class="token"> </span><span class="token" style="color: #d73a49;">-&gt;</span><span class="token"> </span><span class="token">SCNNode </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">      </span><span class="token" style="color: #d73a49;">let</span><span class="token"> sceneText </span><span class="token" style="color: #d73a49;">=</span><span class="token"> </span><span class="token">SCNText(</span><span class="token">string:</span><span class="token"> text</span><span class="token">, </span><span class="token">extrusionDepth:</span><span class="token"> </span><span class="token" style="color: #005cc5;">0.0</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">      sceneText.</span><span class="token">font</span><span class="token"> </span><span class="token" style="color: #d73a49;">=</span><span class="token"> UIFont.</span><span class="token">boldSystemFont(</span><span class="token">ofSize:</span><span class="token"> </span><span class="token" style="color: #005cc5;">10</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">      sceneText.</span><span class="token">flatness</span><span class="token"> </span><span class="token" style="color: #d73a49;">=</span><span class="token"> </span><span class="token" style="color: #005cc5;">0.1</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token">      </span><span class="token" style="color: #d73a49;">let</span><span class="token"> textNode </span><span class="token" style="color: #d73a49;">=</span><span class="token"> </span><span class="token">SCNNode(</span><span class="token">geometry:</span><span class="token"> sceneText</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">      textNode.</span><span class="token">scale</span><span class="token"> </span><span class="token" style="color: #d73a49;">=</span><span class="token"> </span><span class="token">SCNVector3(</span><span class="token">x:</span><span class="token"> </span><span class="token" style="color: #005cc5;">0.002</span><span class="token">, </span><span class="token">y:</span><span class="token"> </span><span class="token" style="color: #005cc5;">0.002</span><span class="token">, </span><span class="token">z:</span><span class="token"> </span><span class="token" style="color: #005cc5;">0.002</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token">      </span><span class="token" style="color: #d73a49;">return</span><span class="token"> textNode
</span></span><span class="line"><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span></code></pre></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1984"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-1982">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-1983'
	>
	The procedure is similar to adding the overlay node. First we need to create a geometry – this time it’s a text geometry using our Pokémon’s name. We set the proper font, flatness (accuracy or smoothness of the text geometry) and the text scaling – since SceneKit deals in meters by default, we need to scale it waaay down.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1987"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-1985">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-1986'
	>
	If you’ve implemented everything correctly along the way, this is what should happen when you detect your first image:</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1990"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-media">
	<div	class="media block-media__media media__border--none media__align--center-center"
	data-id="es-1988"
	 data-media-type='image'>

	<figure class="image block-media__image-figure image--size-stretch" data-id="es-1989">
	<picture class="image__picture block-media__image-picture">
												<img
					src="https://infinum.com/uploads/2019/01/crash-course-in-augmented-reality-on-ios-with-arkit-4.gif"
					class="image__img block-media__image-img"
					alt=""
										height="277"
															width="600"
										loading="lazy"
					 />
					</picture>

			<figcaption class="image__figcaption block-media__image-figcaption">
			Tracked image with overlay and text.		</figcaption>
	</figure></div></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1993"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-1991">
	<h2	class='typography typography--size-52-default js-typography block-heading__heading'
	data-id='es-1992'
	>
	Who is that&nbsp;Pokémon?</h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1996"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-1994">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-1995'
	>
	The final piece of our Pokémon puzzle we’re missing is actually something which would show us the information about the detected pokemon using <a href="https://pokemondb.net/pokedex">PokémonDB</a>, right here inside our AR experience. We can do that by using our newly acquired knowledge about plane and node creation, with making some slight modifications:</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-1999"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="lists" data-id="es-1997">
	<ul	class='typography typography--size-16-text-roman js-typography lists__typography'
	data-id='es-1998'
	>
	<li>instead of using an <em>UIColor</em> as the plane material for this new node, this time we are going to use a <em>UIWebView</em> (at the time of writing this article, WKWebView for some reason still isn’t supported inside <em>ARSessions</em> and we get just a grey, empty plane if we try to use it – Apple, some consistency would be appreciated);</li><li>change the <em>webView</em> node’s position parameters to be either left or right of the detected image, to improve visibility;</li><li>you could also modify the plane’s width and height parameters to provide better readability of the page.</li></ul></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-2002"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-2000">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-2001'
	>
	After playing around with it a little, your final result should look something like this:</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-2005"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-media">
	<div	class="media block-media__media media__border--none media__align--center-center"
	data-id="es-2003"
	 data-media-type='image'>

	<figure class="image block-media__image-figure image--size-stretch" data-id="es-2004">
	<picture class="image__picture block-media__image-picture">
												<img
					src="https://infinum.com/uploads/2019/01/crash-course-in-augmented-reality-on-ios-with-arkit-5.gif"
					class="image__img block-media__image-img"
					alt=""
										height="277"
															width="600"
										loading="lazy"
					 />
					</picture>

	</figure></div></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-2008"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-2006">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-2007'
	>
	And voilà, you’ve just created your first AR experience. It wasn’t that hard, was it? This sneak peek into AR is just scratching the surface of what’s possible, and as time goes on, more and more options are going to be available to us developers.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-2011"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-2009">
	<h2	class='typography typography--size-52-default js-typography block-heading__heading'
	data-id='es-2010'
	>
	The future is augmented</h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-2014"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-2012">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-2013'
	>
	To wrap things up, I’d like to share my own opinion about the future of AR. As such, take it with a grain of salt.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-2019"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="blockquote block-blockquote__blockquote" data-id="es-2015">
	
	<div class="blockquote__content">
		<i
	class="icon blockquote__icon icon--size-16 icon--scale-100"
	 aria-hidden='true' data-name='blockquote-24' data-id='es-2016'>
	<svg fill='none' height='24' viewBox='0 0 24 24' width='24' xmlns='http://www.w3.org/2000/svg'><path clip-rule='evenodd' d='m12 24c6.6274 0 12-5.3726 12-12 0-2.79685-.9568-5.37021-2.561-7.41062-.581.22951-1.0832.60583-1.5069 1.12898-.5132.60844-.7698 1.41969-.7698 2.43375v.07605h2.5789v5.59004h-5.6197v-5.01962c0-1.11547.154-2.06616.4619-2.85205.3336-.81125.757-1.48307 1.2702-2.01545.528-.52161 1.1175-.92155 1.7687-1.1998-2.0728-1.70651-4.7279-2.73128-7.6223-2.73128-6.62742 0-12 5.37258-12 12 0 6.6274 5.37258 12 12 12zm-3.53811-18.05347c-.30793.78589-.46189 1.73658-.46189 2.85205v5.01962h5.6197v-5.59004h-2.5789v-.07605c0-1.01406.2566-1.82531.7698-2.43375.5389-.63379 1.1804-1.05209 1.9245-1.2549v-2.28164c-.7441.07605-1.4626.25351-2.1555.53238-.6928.27887-1.3086.68449-1.84752 1.21688-.51321.53238-.9366 1.2042-1.27019 2.01545z' fill='currentColor' fill-rule='evenodd'/></svg></i><p	class='typography typography--size-36-text js-typography blockquote__quote'
	data-id='es-2017'
	>
	“Is AR actually going to be the future of mobile applications?”</p>
		<div class="blockquote__caption-wrap">
					</div>
	</div>
</div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-2022"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-2020">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-2021'
	>
	This question has started to pop up lately, and even though I don’t have a magic ball to tell the future, looking from the number of devices that currently support ARKit, it really doesn’t seem too far-fetched. Everyone with an iPhone running iOS 12 can enjoy these experiences, and younger generations are probably going to be (if they aren’t already) crazy about them.&nbsp;</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-2025"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-2023">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-2024'
	>
	However, the whole concept of AR on mobile phones has one major issue – the practicality of use. It’s too impractical to walk around with your phone pointed at different things all the time, experiencing the real world while interacting with its augmentations through a screen. In my opinion, the way we interact with our phones is not really going to change that much, but instead, something else will rise up to augmented reality’s call – AR glasses.&nbsp;</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-2028"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-2026">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-2027'
	>
	Google tried it a few years ago, but it was just ahead of its time for multiple reasons. Nevertheless, with the way mobile AR is advancing, it’s just a matter of time before another major tech player announces their own AR glasses. Judging by the <a href="https://www.macrumors.com/2019/01/28/apple-augmented-reality-ces/">information coming from this year’s CES</a>, Apple seems to be holding their cards close to their chest and are waiting for the perfect moment to jump into the AR game.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-2031"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-2029">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-2030'
	>
	What will happen next? We don’t know that yet, but we’ll probably look back at today and think of it as a learning experience for things to come.</p></div>	</div>
</div>
</div>		</div>
	</div><p>The post <a href="https://infinum.com/blog/crash-course-in-augmented-reality-on-ios-with-arkit/">A Crash Course in Augmented Reality on iOS with ARKit</a> appeared first on <a href="https://infinum.com">Infinum</a>.</p>
]]>
				</content:encoded>
			</item>
		
	</channel>
</rss>