<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Lankinen</title>
    <description>The latest articles on DEV Community by Lankinen (@lankinen).</description>
    <link>https://dev.to/lankinen</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F272848%2F659a5a3d-df4b-46e7-891d-0c3dcc9d0e99.png</url>
      <title>DEV Community: Lankinen</title>
      <link>https://dev.to/lankinen</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/lankinen"/>
    <language>en</language>
    <item>
      <title>Testing Startup Idea in 6 Days</title>
      <dc:creator>Lankinen</dc:creator>
      <pubDate>Wed, 26 Aug 2020 08:22:43 +0000</pubDate>
      <link>https://dev.to/lankinen/testing-startup-idea-in-6-days-3992</link>
      <guid>https://dev.to/lankinen/testing-startup-idea-in-6-days-3992</guid>
      <description>&lt;p&gt;This article is about how I tested a hypothesis I had by building a website in 3 days. It's not my first time building something to test business hypothesis but this time I wanted to do it faster and document the processes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Hypothesis
&lt;/h2&gt;

&lt;p&gt;The hypothesis is that people enjoy commenting 💩 and reading 😖 comments about news the same way they do with YouTube videos. There are some news sites offering comment option but I don't like all of them. For example Hacker News is great website but the "news" (sometimes just Wikipedia article) rarely interest me.&lt;/p&gt;




&lt;h2&gt;
  
  
  How to test the hypothesis?
&lt;/h2&gt;

&lt;p&gt;The first step is to think how to test this hypothesis 👉AS EASILY AS POSSIBLE👈. The goal is to not build first version of the final product but test the hypothesis. If you can do it by interviewing people, then start with that.&lt;/p&gt;

&lt;p&gt;I can't do a newsletter because commenting would be a problem. I could go some kind of forum and try to get people talk there. Or maybe Reddit. The thing is that it's always difficult to get first 100 people to even look the idea. On Reddit it would be a huge problem to get enough people to even look the subreddit. I couldn't say that people don't like the idea but it might be just that not enough people saw it.&lt;/p&gt;

&lt;p&gt;There is a trick 🧙‍♂️. Site called Product Hunt. It's a website where users can post products (own or someone else). Other users can up vote 👍 them which increase their placement in the daily feed.&lt;/p&gt;

&lt;p&gt;Product Hunt is a great way to get a lot of people to look the idea. You can't publish a form or subreddit on Product Hunt but it needs to be a product. That's why I need to build something I can publish on Product Hunt.&lt;/p&gt;

&lt;p&gt;I decided to do a simple website 💻. There is no point of listing all possible news as the comments would spread. That is why I need to show only top x news of the day. I decided that 10 news a day is good.&lt;/p&gt;

&lt;p&gt;One problem with 10 news a day is that I can't please everyone. I need to start with some small group of people. Because my goal is to launch this on Product Hunt, I should build it for the Product Hunt users. They are mostly startup and technical people (like me 🙂). I still want to list at least 3 news about some big topics and not just some niche tech news.&lt;/p&gt;




&lt;p&gt;The step number two when building something is to decide what the MVP looks like. Most of the people should create exact list of things they want to be in the MVP because otherwise they start adding more and more features. This happens so easily and in many forms that it's hard to notice it until it's too late. I have done that mistake in the past a few times 🤦 and feel like I have learned to sense when to build something or not. I still do high level list of features for MVP.&lt;/p&gt;

&lt;p&gt;MVP:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Show 10 news that change every day (I'm deciding them)&lt;/li&gt;
&lt;li&gt;Users can comment news and reply other people's comments&lt;/li&gt;
&lt;li&gt;Users can like and dislike comments (to show the best comments and hide spam or trash comments)&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;Okay so now I have a good plan. The idea is to create Product Hunt launch and see how people respond. If everyone churns the same day, I just assume that the hypothesis wasn't right. 🤞&lt;/p&gt;

&lt;p&gt;In Lean Analytics book the authors said how you should have exact definition of success because otherwise you might end up the worst situation possible, which is that you get stuck to idea that works but never becomes big. At this point I don't believe it make sense to do that kind of goal because MVPs are not for everyone (some expect good looking and ready products) and you learn probably something big. If it seems like people like the idea and you do the next version, it's time to define the goal.&lt;/p&gt;

&lt;p&gt;The opposite is to look when to quit. Especially when doing something bigger, I have found it the best to do Quitting Contract (from The Dip book). There you define the situation where you quit. Too often people end up "living dead" zone where they try a bunch of stuff without understanding that the core hypothesis doesn't work. And some people in the other hand quit too early because they face the first problem. With smaller projects like this, it's easier to do more rational decisions as I haven't invested that much time.&lt;/p&gt;




&lt;h2&gt;
  
  
  Building
&lt;/h2&gt;

&lt;p&gt;The final website is here: &lt;a href="https://comment-news.web.app/"&gt;https://comment-news.web.app/&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  15th
&lt;/h3&gt;

&lt;p&gt;I spent ~2 hours coding. I decided to use ReactJS because I'm familiar with it which allows me to build stuff faster and there aren't any limitations at this point.&lt;/p&gt;

&lt;p&gt;I always do mockups using notepad and pen instead of tools like Figma. The reason is that I can do these in a few minutes when, at least for me, it would took much longer to do it on Figma.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--oTHnl9dn--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/bgv5qmc4ummg3ujx76ra.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--oTHnl9dn--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/bgv5qmc4ummg3ujx76ra.jpeg" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--YioJeFEm--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/6rhc0468brugwcss0mji.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--YioJeFEm--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/6rhc0468brugwcss0mji.jpeg" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--8Pn5d8pE--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/y6zwqvm72oqfwutygomh.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--8Pn5d8pE--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/y6zwqvm72oqfwutygomh.jpeg" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I'm bad at estimating but I believe I can do this during the next week. Because there is no external deadline, I don't feel like I need to do any deadlines for myself either.&lt;/p&gt;

&lt;p&gt;At this point I don't do any kind of TODO list of all the tasks. I think it's just faster to have high level view and then plan more accurately in daily or task basis. I make TODO every evening for the next day.&lt;/p&gt;

&lt;h3&gt;
  
  
  16th
&lt;/h3&gt;

&lt;p&gt;1.30 pm&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--pslOCT9A--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/bhdftk3j4mo1u7nxmj0f.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--pslOCT9A--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/bhdftk3j4mo1u7nxmj0f.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;5.00 pm&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--D3kqiEzP--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/imo36dwncu4hw4vi9ic3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--D3kqiEzP--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/imo36dwncu4hw4vi9ic3.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;🌅 end of the day&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--AN10Guhb--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/mju7qwpqc4am3lbbtkvr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--AN10Guhb--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/mju7qwpqc4am3lbbtkvr.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I got the website pretty far. I still need to add a lot of functionalities to the buttons and setup database. Right now I'm using hard coded data.&lt;/p&gt;

&lt;h3&gt;
  
  
  17th
&lt;/h3&gt;

&lt;p&gt;11am - After making reply work, the code starts to get complex so I will spend some time cleaning 🧹 it. This is something I do once in a while. I don't really plan ahead but just build stuff. This approach always causes hard to read code. It's pretty easy to then just take an hour or so and clean it. I have found it much faster than trying to plan everything ahead and write clean code right away.&lt;/p&gt;

&lt;p&gt;2.30 pm - The code is polished and now it's much easier to work on other stuff. I made replying work properly.&lt;/p&gt;

&lt;p&gt;3.30 pm - Sorting is ready. I don't think having ability to sort by date is something people will use a lot so I could leave it out but I added it anyways because it kind of came automatically after doing vote sorting that's anyways needed.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"It was easy to add" is often the reason why MVPs have a lot of features and it's not a good thing. MVP should focus only the core feature and everything else should be left out even if it's easy to add and doesn't seem to make the code much complex.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Locally everything is ready. The next I will setup database. I decided to use Firebase because it's again something I'm familiar with and it's not causing any limitations at this point.&lt;/p&gt;

&lt;p&gt;When I was coding the website I had some hard coded data. I used it only through one file. Now it's easy to just change this file to use database.&lt;/p&gt;

&lt;p&gt;6.30 pm - I got the database working.&lt;/p&gt;

&lt;p&gt;8.00 pm - Fixed some small things and everything seems to be working fine. I still need to improve the UI but the next thing I'm going to do is a tool I can use to submit the news everyday.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--tdVjKs0h--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/uy6tyug2mx29q822zlt4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--tdVjKs0h--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/uy6tyug2mx29q822zlt4.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--xco3OtVA--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/ofm09hsd4rzjou6ggts0.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--xco3OtVA--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/ofm09hsd4rzjou6ggts0.jpeg" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I don't really care what it is going to look like because I'm the only one using it. I need some UI and possibly also ability to use it on my phone so it's probably the best to just create another ReactJS website. I actually put it to the same website but under some secret 🤫 path and behind a password.&lt;/p&gt;

&lt;h3&gt;
  
  
  18th
&lt;/h3&gt;

&lt;p&gt;9.00 am - I'm working on dev tool that I can use to add news to the feed. I'm not going to make it secure because it requires too much work. Basically anyone can add news to the feed but it's not so easy that people without technical skills could do it.&lt;/p&gt;

&lt;p&gt;10.30 am - Dev tool is ready. The next job is to improve UI of the website. I try to keep it simple because I'm not good at designing websites.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--9Ll3Mo7z--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/285eoe2qsybv87v0tjad.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--9Ll3Mo7z--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/285eoe2qsybv87v0tjad.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--iFyWShOG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/1qim4xc7zxdt1jjv33pe.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--iFyWShOG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/1qim4xc7zxdt1jjv33pe.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I like to put bright colors 🌈 to different elements at this point to easily see all paddings and the size of them. Some people go 🥜 when they see this, thinking that I'm going to make it look like this.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--OKLLVrt9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/rxulr592jiiny96flute.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--OKLLVrt9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/rxulr592jiiny96flute.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--1OTxH-BY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/qsvhyluw555qaszwt1ld.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--1OTxH-BY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/qsvhyluw555qaszwt1ld.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Emojis 🗿 always make everything look better.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ZANwT_-_--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/his2w5r3uwoqhawbc1n1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ZANwT_-_--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/his2w5r3uwoqhawbc1n1.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;1.30 pm - Small break 🌮&lt;/p&gt;

&lt;p&gt;2.00 pm - Back to code 🧑‍💻 (or more like this 👉 💻🖥🖥)&lt;/p&gt;

&lt;p&gt;I'm not sure if the website looks like this on my iPhone because the pixels aren't exactly right even though Chrome says it should look like this.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--waynnkj6--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/6a8dg8mo3did2d5fi16h.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--waynnkj6--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/6a8dg8mo3did2d5fi16h.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;With "right" numbers it should look like this which is much better.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--uaIHes3V--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/ffdbfgr4xe8y6xnjk5gv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--uaIHes3V--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/ffdbfgr4xe8y6xnjk5gv.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I try to deploy it at this point so I can easily test it on my real phone. I'm going to again use Firebase for this because they have great hosting solution that's super easy to setup for ReactJS projects.&lt;/p&gt;

&lt;p&gt;Okay it looks like the first image which is the worse 😟&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s---gHx0ohm--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/d35x2d6yezjhaw2rci5e.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s---gHx0ohm--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/d35x2d6yezjhaw2rci5e.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Got it! 🎉&lt;/p&gt;

&lt;p&gt;It's 2.30 pm and the final UI related thing is the feed. This is what it looks like right now.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--U-tcSBhs--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/fbpjot9ddwsa05sldm6x.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--U-tcSBhs--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/fbpjot9ddwsa05sldm6x.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I don't want to touch it much. I like this kind of colorful design. I want to change the color of text, I need to decide how multiple items will look, and I will add a button to the right side in case people don't understand that the text is link.&lt;/p&gt;

&lt;p&gt;This might make someone with better color sense to 🤮 but it looks cool, imo, so it's fine.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;I don't think you should take everything in the product too seriously and try to make it look like some big corporation did it. Do things that make you happy and the users will notice it and like it more than trying to pretend a big company.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--26BI-SPU--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/duq2i59y9pen4oc95ght.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--26BI-SPU--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/duq2i59y9pen4oc95ght.gif" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;3.15 pm - Icon done. I just took news paper emoji 📰 and put it top of the blue color I used on the website. The name is at least for now "Comment News". I bet most of the people don't pay attention to these things and that is why I don't either.&lt;/p&gt;

&lt;p&gt;The next I add the most important thing, analytics.&lt;/p&gt;

&lt;p&gt;4.00 pm - I decided to use Google Analytics because again I have used it in the past and it's not limiting anything at this point. I track page loads to see how many people visits but also button clicks to see how active they are. Basically I just want to see how many people came to the website, how many of them return later, and do they vote, comment, or do any other action.&lt;/p&gt;

&lt;p&gt;5.00 pm - I'm interested to not just see if people want to comment news and read other people's comments but also see if they like the format of getting 10 news a day. It saves a ton of time and often 10 is enough to stay updated of everything. That is why I added an input box where users can put their email to get the feed sent to their inbox everyday. I'm not going to implement that feature right away but I collect emails to database to see the demand but also have them later if needed.&lt;/p&gt;

&lt;p&gt;I'm going to take a break to eat something and then I will figure out what to do next.&lt;/p&gt;

&lt;p&gt;5.45 pm - Okay, so I thought that it's really important to have users because the whole point of the website is the comments. Because I need to start from zero, I need to pretend like there are users. I thought about doing some kind of automation where I scrape tweets from Twitter 🐦🔫 and submit them as comments (assuming that I find a thread where people talk about that news) but then I realize that it's probably too much.&lt;/p&gt;

&lt;p&gt;The whole point of this experiment is to launch it on Product Hunt and then just see how they respond to it. I need to add a lot of comments at least the first day so that when the Product Hunt users come to the website they think that it's used a lot. Then hopefully those users start to comment the news, the next day. But to make sure there is always comments, I could also make fake comments for the second day. After that I might do some fake comments but the goal is that users start to comment or the website doesn't work and I shut it down. So there are only 1-3 days when I seriously need to write comments and it's faster to do them manually than trying to create some scraping tool.&lt;/p&gt;

&lt;p&gt;I thought about buying a domain but I don't want to spend $1 for .xyz because I'm not sure if it's any better than the subdomain Firebase is offering and $9 for .com is too much for my wallet 💰 (I'm cheap).&lt;/p&gt;

&lt;p&gt;The only thing left is to prepare Product Hunt launch. The same time I will initialize database for tomorrow. I will do the final review of every feature to make sure there aren't any major 🐛.&lt;/p&gt;

&lt;p&gt;8.00 pm - I haven't though much about picking top 10 news but when I started doing it, I realized how hard it actually is. I first opened a bunch of different news sites and tried to find if there are some overlapping topics. There kind of were but then in some news I wasn't sure if they were about the same topic. I right away realize that it requires too much time. Then I went to Google News. They list pretty well the most interesting topics from different categories and the best is that they collect "all" the sources talking about that topic.&lt;/p&gt;

&lt;p&gt;I started manually picking topics and trying to copy paste all the articles to notepad but after 30 minutes and 3 topics I realize how much time it would take 🤨. I don't need to do it that many day but it's still too much work for me. I needed to create a scraper.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;When building automation for MVP, it's important to think how much it takes to build it and how much time it saves. It's often hard to estimate but I would say that only automate stuff that saves you double the time it takes to build. Just because often software building estimations seem to double.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The scraper takes URL of the topic and then it scrapes 5-10 sources (I don't want too many) and information about them. In the future, I could easily automate it in a way that it also picks the topics removing all work from me but I rather do it manually first to make sure the topics are interesting&lt;/p&gt;

&lt;p&gt;The scraper is almost ready. I will continue tomorrow. I believe that I'm available to launch the website on Product Hunt the day after tomorrow.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;I want to highlight that this is what always happens. I was ready to take the screenshots and launch the website tomorrow but then I realize something I didn't notice before which causes one extra day. This is not the same as building more and more features which might look very similar. Be careful if one day turns into two and two days turn into three. Then you are probably adding features, not fixing the mistakes you didn't think in the first place.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  19th
&lt;/h3&gt;

&lt;p&gt;10 am - Scraper is ready. I can give title, summary, and URL. Then it extracts all the other data automatically and saves it to the database.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;I first built the developer tool using ReactJS. Then I started to add news and I realize that it wasn't actually the best  solution. The original work was waste of time but I don't regret it. I don't think I could have predicted that it's too hard to use without  first really using it. It's just important to have some time for this kind of mistakes because it's inevitable to have them. "Move fast and break things"&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;11 am - I ate and did some small fixes to the website. Those started to get too small 🦠, the kind of things you don't want to waste time doing when building MVP.&lt;/p&gt;

&lt;p&gt;1 pm - I did some more fixes mostly to scraper to reduce probability 🎲 of mistakes. I cleaned the database and added some news to prepare screenshots for Product Hunt.&lt;/p&gt;

&lt;p&gt;I was taking screenshots for Product Hunt but then I notice this 😱&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--mzxvLHQ_--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/lvjmjcugp54yjg2kdz2u.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--mzxvLHQ_--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/lvjmjcugp54yjg2kdz2u.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The source icons look bad. Really bad. It's pretty small part of the whole website but I want to fix it as I have the whole day (these are the words people use when they start building more and more stuff to MVP 🙂).&lt;/p&gt;

&lt;p&gt;4 pm - I'm back after a few hour break 🎾. I just notice that mobile feed is also looking bad so I need to improve it.&lt;/p&gt;

&lt;p&gt;First I start with the source problem. I tried to look if there is some easy to way to get more high resolution photos. I couldn't find any solution to that. The other problem with icons is that some are rectangular which doesn't fit into the square space I have. Because of these problems I decided to not use the icons but show text that says the source name.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--M_MrRN_a--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/mdryxx4saahyd0amkhy9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--M_MrRN_a--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/mdryxx4saahyd0amkhy9.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Maybe good icons would have looked better but it's fine like this.&lt;/p&gt;

&lt;p&gt;So this is the mobile problem&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--hWHU-0VL--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/y9o0n6us7xteyezwe543.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--hWHU-0VL--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/y9o0n6us7xteyezwe543.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Looks better&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--O99x52MR--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/8vdanwm3e3tnctfse286.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--O99x52MR--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/8vdanwm3e3tnctfse286.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The website is ready! 👏&lt;/p&gt;

&lt;p&gt;&lt;a href="https://comment-news.web.app/"&gt;https://comment-news.web.app/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;7 pm - I wrote description, comment, and tag line for Product Hunt. I took some screenshots too.&lt;/p&gt;

&lt;p&gt;I checked analytics to make sure it's working as it might be the most important part. I actually realize that I had setup it incorrectly that made it to track nothing. I'm glad, I looked it once more because I was available to fix it. 😌&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;It's good practice to have some path of actions you follow every time and in the end, repeating it as many times as it takes to do it once without any problems.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;8 pm - The database is now cleaned and I started to fill it with some news for tomorrow. The idea is that the feed changes everyday 12 am PST which is here 🌍 10 am. This gives me time at morning to prepare the feed before users see it. The idea is to schedule Product Hunt launch tomorrow morning to happen a few minutes after 12 am PST when the new day changes also on Product Hunt ⬜🐻🟥.&lt;/p&gt;

&lt;p&gt;I'm a little bit freak out 😰 at this point. I notice some small UI things but I'm not going to touch anything that small at this point because it might cause more work and then I might not be available to publish it tomorrow. It's really common that people start to do stuff in the last minute and make mistakes or just make the whole product more complex causing more problems which postpones the launch.&lt;/p&gt;

&lt;h3&gt;
  
  
  20th
&lt;/h3&gt;

&lt;p&gt;9.00 am - I scheduled Product Hunt launch for 10.30 am (12 am PST).&lt;/p&gt;

&lt;p&gt;"YouTube like comments for 10 trending news of the day" is the tag line I'm going to use. Originally I thought something without the YouTube thing but then I started to think that do people get the idea if I just say that they can comment news. At least I right away like the idea when I compare it to YouTube comments that I enjoy reading. It might be confusing but I rather put it there and take the risk of being confusing than leave it boring.&lt;/p&gt;

&lt;p&gt;10.30 am - Adding news, fake comments, and fake votes took longer than I expected but I'm still on time. Choosing 10 news was a little bit difficult. I wish I have promise to do only 5 but it's too late to change anything.&lt;/p&gt;

&lt;p&gt;I also realize that right now analytics is not tracking what news people read but are they reading news at all 😐. I of course want to be available to track the news reading to see what kind of news they like the most but it's too late to do it for the launch at this point. I try to do it in a few hours.&lt;/p&gt;

&lt;p&gt;Right now I'm just going to comment, reply, and vote to make it look like there is traffic on the website. I'm also going to promote the Product Hunt launch in a few places. I'm not sure how important it is but I launched something recently and it got only 3 upvotes so I don't want that it happens again. I believe that the feed is designed in a way that good products can get noticed even without extra promotion.&lt;/p&gt;

&lt;p&gt;11 am - I ate and came back. Doesn't look good. Just one up vote on Product Hunt and it's from me. I will add a few comments to all of the news and try to promote the posting after that.&lt;/p&gt;

&lt;p&gt;Tweeted, send messages to friends, and announced it on a few Slack channels. I also posted it to Hacker News.&lt;/p&gt;

&lt;p&gt;1 pm - 3 upvotes. Two are from me and one is from friend. Doesn't look great but then in the other hand it's mid night in PST. I do some other stuff as there is nothing I feel important in this project.&lt;/p&gt;

&lt;p&gt;4 pm - 4 upvotes. One from stranger. 4 users have visited based on Google Analytics.&lt;/p&gt;

&lt;h3&gt;
  
  
  21st
&lt;/h3&gt;

&lt;p&gt;9.30 am - There are still 4 upvotes and at this point it doesn't any more matter as there is a new feed. I got 7 visits to the website. I notice that the email sign up wasn't working which is a little bit annoying.&lt;/p&gt;

&lt;p&gt;I added 10 news for today's feed. I start to think that I need to automate this process as I'm not interested of doing it more than maybe one more day.  This way I also remove all the manual work so I can just let the website live its own life and move to something else. I don't really think the website will explode 💥 on its own but I keep it running 🏃 for this article and just in case I want to show it to someone.&lt;/p&gt;

&lt;h3&gt;
  
  
  22nd
&lt;/h3&gt;

&lt;p&gt;One user visited during yesterday and it was me 😶. I automated news scraping script in a way that I don't need to do anything 🤖.&lt;/p&gt;

&lt;h3&gt;
  
  
  23rd
&lt;/h3&gt;

&lt;p&gt;Yesterday I had 3 visitors. One was me, one from Slovenia 🇸🇮, and one from United States🇺🇸. American left the page right away while Slovenian spent 8 seconds 🙏.&lt;/p&gt;

&lt;h3&gt;
  
  
  26th
&lt;/h3&gt;

&lt;p&gt;There haven't been any visitors since 22nd.&lt;/p&gt;

&lt;p&gt;I didn't focus this much since the last update. I even try to avoid thinking about this 🙈 because the way it ended annoys me. I didn't get as many users to look the idea on Product Hunt as I originally expected and I don't have any solution to get more people to look at it. I could spend a week or more trying to get people try it but I don't really want because the idea is not something I really believe but did just for testing purpose.&lt;/p&gt;




&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;I overestimated the amount of people who would look the idea on Product Hunt. There is no feature that would allow me to see how many people saw the listing. Based on the amount of people who visited the website, I couldn't do much conclusions because the amount is not statistically significant.&lt;/p&gt;

&lt;p&gt;I assumed that Product Hunt is working in a way that good products get noticed without extra promotion. Now I'm guessing that the sorting algorithm is too much bias towards the upvotes instead of giving all the products proper amount of user views before deciding if it's bad or good.&lt;/p&gt;

&lt;p&gt;It might be also that my listing wasn't good enough or maybe in theory the idea doesn't sound very good.&lt;/p&gt;

&lt;p&gt;Did this really proved that people don't like reading YouTube like comments about news? The data that I collected shows me that people didn't like this idea. Is it that they don't like reading comments about news? Maybe, I can't say it for sure. The variable I didn't remove with this MVP was that people couldn't use their current source of news but I required them to use 10 news I chose.&lt;/p&gt;

&lt;p&gt;Now I start to realize that maybe the comments on YouTube aren't as important as I thought. If the video is not good, no one will read the comments. The same might have happen here. I expected that the comments could be the main feature but it is actually extra feature that makes the product better.&lt;/p&gt;

&lt;p&gt;Based on all this I would say that there is possibility that this hypothesis was incorrect. I couldn't see any proof that people would like this idea. That is why I conclude this by saying that this hypothesis was incorrect.&lt;/p&gt;




&lt;p&gt;Someone might say that it's really hard to make any predictions from the data I got, and I agree. But I'm not trying to come up a vaccine that needs to be tested perfectly. Startup hypothesis should be tested with the right balance of efficiency and accuracy. I believe that I learned something about the things I wanted from this quick, 6 day, experience. I might have missed something important that might have give the opposite conclusion but I don't see it the worth of effort to continue.&lt;/p&gt;

&lt;p&gt;One important thing that I learned from Lean Startup is that you should never do mistakes and then just say "at least we learned something". It might be the most common excuse to fail. There should always be a question you try to answer not that you come up questions after you have failed.&lt;/p&gt;

&lt;p&gt;There are two things that might have helped to do more accurate predictions: user interviews and getting more people. User interviews are kind of interviews where you talk with people who possibly might use the product. You don't ask directly what they think about it but things like what news sources they use, why they use them, are there comments, do they talk about the news with their friends, etc.&lt;/p&gt;




&lt;p&gt;I hope you learned something new by reading this lengthy article. If you realized something I probably missed, please let me know so I can learn. The goal of writing this wasn't just to teach people but learn and then also allow me to later review it as I have learned more. I also notice that it helps me to analyze my decisions better and avoid common mistakes like building MVP too far. I'm going to continue documenting in the future projects as it seems to be worth of the time.&lt;/p&gt;

&lt;p&gt;Follow me on Twitter 🥺&lt;br&gt;
&lt;a href="https://twitter.com/reallankinen"&gt;@RealLankinen&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Originally published: &lt;a href="https://www.notion.so/lankinen/Testing-Startup-Idea-in-6-Days-bbdddcc18e6e46478ab55786d162f83b"&gt;https://www.notion.so/lankinen/Testing-Startup-Idea-in-6-Days-bbdddcc18e6e46478ab55786d162f83b&lt;/a&gt;&lt;/p&gt;

</description>
      <category>react</category>
      <category>startup</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>CS193p Notes - Lecture 14: UIKit Integration</title>
      <dc:creator>Lankinen</dc:creator>
      <pubDate>Sun, 26 Jul 2020 16:42:21 +0000</pubDate>
      <link>https://dev.to/lankinen/cs193p-notes-lecture-14-uikit-integration-1p7m</link>
      <guid>https://dev.to/lankinen/cs193p-notes-lecture-14-uikit-integration-1p7m</guid>
      <description>&lt;ul&gt;
&lt;li&gt;UIKit is the old way of developing iOS apps&lt;/li&gt;
&lt;li&gt;SwfitUI (which we have learned in this course) replaced it and is doing most of the things&lt;/li&gt;
&lt;li&gt;There are still some things that might be better in UIKit or there might be some old code so it's important to understand how to use it in SwiftUI&lt;/li&gt;
&lt;/ul&gt;




&lt;ul&gt;
&lt;li&gt;Instead of having MVVM there is MVC

&lt;ul&gt;
&lt;li&gt;In MVC views are grouped together and controlled by a &lt;code&gt;Controller&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;UIKit is object-oriented (not functional)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Qw-o8qlB--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/qi674ebo5dklw7ptnvxu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Qw-o8qlB--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/qi674ebo5dklw7ptnvxu.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--wsYvSO3G--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/suvaqyxjqv3bqqajfrvf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--wsYvSO3G--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/suvaqyxjqv3bqqajfrvf.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;UIKit uses a concept "delegation"

&lt;ul&gt;
&lt;li&gt;Objects (controllers and views) often delegate some of their functionality to other objects&lt;/li&gt;
&lt;li&gt;They do this by having a var called &lt;code&gt;delegate&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;delegate&lt;/code&gt; var is constrained via a protocol with all the delegatable functionality&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Enroute demo UIView (&lt;a href="https://youtu.be/GRX5Dha_Clw?t=745"&gt;12:25&lt;/a&gt;)
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;We create &lt;code&gt;MapView&lt;/code&gt; to normal Swift file (not SwiftUI) because there isn't &lt;code&gt;var body&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This will draw a map and add pins to the points mentioned in &lt;code&gt;annotations&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

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

&lt;span class="kd"&gt;struct&lt;/span&gt; &lt;span class="kt"&gt;MapView&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;UIViewRepresentable&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;annotations&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;MKAnnotation&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

  &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;makeUIView&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;context&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;MKMapView&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;mkMapView&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;MKMapView&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;mkMapView&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;delegate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;coordinator&lt;/span&gt;
    &lt;span class="n"&gt;mkMapView&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addAnnotations&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;annotations&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;mkMapView&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;updateUIView&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="nv"&gt;uiView&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;MKMapView&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;context&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;makeCoordinator&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Coordinator&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kt"&gt;Coordinator&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="kt"&gt;Coordinator&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;NSObject&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;MKMapViewDelegate&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;mapView&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="nv"&gt;mapView&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;MKMapView&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;viewFor&lt;/span&gt; &lt;span class="nv"&gt;annotation&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;MKAnnotation&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;MKAnnotationView&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;view&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;mapView&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dequeueReusableAnnotationView&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;withIdentifier&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"MapViewAnnotation"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;??&lt;/span&gt;
        &lt;span class="kt"&gt;MKPinAnnotationView&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;annotation&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;annotation&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;reuseIdentifier&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"MapViewAnnotation"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="n"&gt;view&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;canShowCallout&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;view&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h3&gt;
  
  
  EmojiArt demo UIViewController (&lt;a href="https://youtu.be/GRX5Dha_Clw?t=2353"&gt;39:13&lt;/a&gt;)
&lt;/h3&gt;



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

&lt;span class="kd"&gt;typealias&lt;/span&gt; &lt;span class="kt"&gt;PickedImageHandler&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;UIImage&lt;/span&gt;&lt;span class="p"&gt;?)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Void&lt;/span&gt;

&lt;span class="kd"&gt;struct&lt;/span&gt; &lt;span class="kt"&gt;ImagePicker&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;UIViewControllerRepresentable&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// could be handled using binding but wanted to show&lt;/span&gt;
  &lt;span class="c1"&gt;// that there are different ways&lt;/span&gt;
  &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;handlePickedImage&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;PickedImageHandler&lt;/span&gt;

  &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;makeUIViewController&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;context&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;UIImagePickerController&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;picker&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;UIImagePickerController&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;picker&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sourceType&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;photoLibrary&lt;/span&gt;
    &lt;span class="n"&gt;picker&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;delegate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;coordinator&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;picker&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;updateUIViewController&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="nv"&gt;uiViewController&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;UIImagePickerController&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;context&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;makeCoordinator&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Coordinator&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;Coordinator&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;handlePickedImage&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;handlePickedImage&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="kt"&gt;Coordinator&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;NSObject&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;UIImagePickerControllerDelegate&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;UINavigationControllerDelegate&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;handlePickedImage&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;PickedImageHandler&lt;/span&gt;

    &lt;span class="nf"&gt;init&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;handlePickedImage&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kd"&gt;@escaping&lt;/span&gt; &lt;span class="kt"&gt;PickedImageHandler&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;handlePickedImage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;handlePickedImage&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;imagePickerController&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="nv"&gt;picker&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;UIImagePickerController&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;didFinishPickingMediaWithInfo&lt;/span&gt; &lt;span class="nv"&gt;info&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;UIImagePickerController&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;InfoKey&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Any&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nf"&gt;handlePickedImage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;info&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;originalImage&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;as?&lt;/span&gt; &lt;span class="kt"&gt;UIImage&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="kt"&gt;ImagePickerControllerDidCancel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="nv"&gt;picker&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;UIImagePickerController&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nf"&gt;handlePickedImage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; 
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;&lt;a href="https://twitter.com/reallankinen"&gt;@RealLankinen&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://dev.to/lankinen/cs193p-notes-lecture-1-course-logistics-and-introduction-to-swiftui-44ap"&gt;Notes 1&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/lankinen/cs193p-notes-lecture-2-mvvm-and-the-swift-type-system-406f"&gt;Notes 2&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/lankinen/cs193p-notes-lecture-3-reactive-ui-protocols-layout-5g8a"&gt;Notes 3&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/lankinen/cs193p-notes-lecture-4-grid-enum-optionals-4noj"&gt;Notes 4&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/lankinen/cs193p-notes-lecture-5-viewbuilder-shape-viewmodifier-fgh"&gt;Notes 5&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/lankinen/cs193p-notes-lecture-6-animation-1a8f"&gt;Notes 6&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/lankinen/cs193p-notes-lecture-7-multithreading-emojiart-2ak3"&gt;Notes 7&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/lankinen/cs193p-notes-lecture-8-gestures-json-1f3m"&gt;Notes 8&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/lankinen/cs193p-notes-lecture-9-data-flow-26e"&gt;Notes 9&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/lankinen/cs193p-notes-lecture-10-navigation-textfield-3ei9"&gt;Notes 10&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/lankinen/cs193p-notes-lecture-11-picker-2hgh"&gt;Notes 11&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/lankinen/cs193p-notes-lecture-12-core-data-eci"&gt;Notes 12&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/lankinen/cs193p-notes-lecture-13-persistence-2jeh"&gt;Notes 13&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/lankinen/cs193p-notes-lecture-14-uikit-integration-1p7m"&gt;&lt;strong&gt;Notes 14&lt;/strong&gt;&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://www.notion.so/lankinen/CS193p-2020-iOS-development-course-from-Stanford-81c094238e9d471bbf059ea8d83b3e15"&gt;Originally published here&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ios</category>
      <category>swift</category>
    </item>
    <item>
      <title>CS193p Notes - Lecture 13: Persistence</title>
      <dc:creator>Lankinen</dc:creator>
      <pubDate>Sun, 26 Jul 2020 16:40:57 +0000</pubDate>
      <link>https://dev.to/lankinen/cs193p-notes-lecture-13-persistence-2jeh</link>
      <guid>https://dev.to/lankinen/cs193p-notes-lecture-13-persistence-2jeh</guid>
      <description>&lt;ul&gt;
&lt;li&gt;UserDefaults

&lt;ul&gt;
&lt;li&gt;Simple. limited. small.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;Codable/JSON

&lt;ul&gt;
&lt;li&gt;Clean way to turn almost any data structure into an interoperable/storable format&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;UIDocument

&lt;ul&gt;
&lt;li&gt;This is really the way to do things when you have a true document like EmojiArt has&lt;/li&gt;
&lt;li&gt;UIKit compatibility code is required (no SwiftUI interface to it yet [THIS IS SwiftUI COURSE])&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;Core Data

&lt;ul&gt;
&lt;li&gt;Powerful. Object-oriented. Elegant SwiftUI integration.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;Cloud Kit

&lt;ul&gt;
&lt;li&gt;Storing data into a database in the cloud&lt;/li&gt;
&lt;li&gt;Has UserDefaults-like thing&lt;/li&gt;
&lt;li&gt;Plays nicely with Core Data&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Cloud Kit&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Record Type&lt;/strong&gt; = like a class or struct&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Fields&lt;/strong&gt; = like vars in a class or struct&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Record&lt;/strong&gt; = an "instance" of a &lt;strong&gt;Record Type&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reference&lt;/strong&gt; = a "pointer" to another &lt;strong&gt;Record&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Database&lt;/strong&gt; = a place where &lt;strong&gt;Records&lt;/strong&gt; are stored&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Zone&lt;/strong&gt; = a sub-area of a &lt;strong&gt;Database&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Container&lt;/strong&gt; = collection of &lt;strong&gt;Databases&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Query&lt;/strong&gt; = a &lt;strong&gt;Database&lt;/strong&gt; search&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Subscription&lt;/strong&gt; = a "standing &lt;strong&gt;Query&lt;/strong&gt;" which sends push notifications when changes occur&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;iCloud needs to be turned on from Project Settings under &lt;code&gt;Capabilities&lt;/code&gt; tab. Choose &lt;code&gt;CloudKit&lt;/code&gt; from Services. Click CloudKit Dashboard.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;db&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;CKContainer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;shared&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;privateCloudDatabase&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;tweet&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;CKRecord&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Tweet"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;tweet&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"text"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"140 characters of pure joy"&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;tweeter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;CKRecord&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"TwitterUser"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;tweet&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"tweeter"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;CKReference&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;record&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;tweeter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;action&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;deleteSelf&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;save&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tweet&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;savedRecord&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;CKRecord&lt;/span&gt;&lt;span class="p"&gt;?,&lt;/span&gt; &lt;span class="nv"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;NSError&lt;/span&gt;&lt;span class="p"&gt;?)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Void&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;error&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="kc"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// hooray!&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;error&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;errorCode&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="kt"&gt;CKErrorCode&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;NotAuthenticated&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;rawValue&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// tell user he or she has to be logged in to iCloud for this to work&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// report other errors (there are 29 different CKErrorCodes!)&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;File System

&lt;ul&gt;
&lt;li&gt;Unix file system&lt;/li&gt;
&lt;li&gt;an app can read and write only it's own "sandbox"&lt;/li&gt;
&lt;li&gt;Sandbox is useful because

&lt;ul&gt;
&lt;li&gt;No one else can damage app&lt;/li&gt;
&lt;li&gt;other apps can't view your app's data&lt;/li&gt;
&lt;li&gt;by deleting the sandbox, it's simple to get rid of all the data&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;Sandbox contains

&lt;ul&gt;
&lt;li&gt;Application directory - Your executable, .jpgs, etc.; not writable&lt;/li&gt;
&lt;li&gt;Documents directory - Permanent storage created by and always visible to the user&lt;/li&gt;
&lt;li&gt;Application Support directory - Permanent storage not seen directly by the user&lt;/li&gt;
&lt;li&gt;Caches directory - Store temporary files here (this is not backed up)&lt;/li&gt;
&lt;li&gt;Other directories (see documentation) ...
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;predicate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;NSPredicate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;format&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"text contains %@"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;searchString&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;query&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;CKQuery&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;recordType&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"Tweet"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;predicate&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;predicate&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;perform&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;records&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;CKRecord&lt;/span&gt;&lt;span class="p"&gt;]?,&lt;/span&gt; &lt;span class="nv"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;NSError&lt;/span&gt;&lt;span class="p"&gt;?)&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;error&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="kc"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// records will be an array of matching CKRecords&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;error&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;errorCode&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="kt"&gt;CKErrorCode&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;NotAuthenticated&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;rawValue&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// tell user he or she has to be logged in to iCloud for this to work!&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// report other errors (there are 29 different CKErrorCodes!)&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;&lt;a href="https://twitter.com/reallankinen"&gt;@RealLankinen&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://dev.to/lankinen/cs193p-notes-lecture-1-course-logistics-and-introduction-to-swiftui-44ap"&gt;Notes 1&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/lankinen/cs193p-notes-lecture-2-mvvm-and-the-swift-type-system-406f"&gt;Notes 2&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/lankinen/cs193p-notes-lecture-3-reactive-ui-protocols-layout-5g8a"&gt;Notes 3&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/lankinen/cs193p-notes-lecture-4-grid-enum-optionals-4noj"&gt;Notes 4&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/lankinen/cs193p-notes-lecture-5-viewbuilder-shape-viewmodifier-fgh"&gt;Notes 5&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/lankinen/cs193p-notes-lecture-6-animation-1a8f"&gt;Notes 6&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/lankinen/cs193p-notes-lecture-7-multithreading-emojiart-2ak3"&gt;Notes 7&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/lankinen/cs193p-notes-lecture-8-gestures-json-1f3m"&gt;Notes 8&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/lankinen/cs193p-notes-lecture-9-data-flow-26e"&gt;Notes 9&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/lankinen/cs193p-notes-lecture-10-navigation-textfield-3ei9"&gt;Notes 10&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/lankinen/cs193p-notes-lecture-11-picker-2hgh"&gt;Notes 11&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/lankinen/cs193p-notes-lecture-12-core-data-eci"&gt;Notes 12&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/lankinen/cs193p-notes-lecture-13-persistence-2jeh"&gt;&lt;strong&gt;Notes 13&lt;/strong&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/lankinen/cs193p-notes-lecture-14-uikit-integration-1p7m"&gt;Notes 14&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://www.notion.so/lankinen/CS193p-2020-iOS-development-course-from-Stanford-81c094238e9d471bbf059ea8d83b3e15"&gt;Originally published here&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ios</category>
      <category>swift</category>
    </item>
    <item>
      <title>CS193p Notes - Lecture 12: Core Data</title>
      <dc:creator>Lankinen</dc:creator>
      <pubDate>Sun, 26 Jul 2020 16:40:31 +0000</pubDate>
      <link>https://dev.to/lankinen/cs193p-notes-lecture-12-core-data-eci</link>
      <guid>https://dev.to/lankinen/cs193p-notes-lecture-12-core-data-eci</guid>
      <description>&lt;ul&gt;
&lt;li&gt;Core data

&lt;ul&gt;
&lt;li&gt;Object-oriented database&lt;/li&gt;
&lt;li&gt;Core Data uses SQL to store the data but interacting with it happens using Swift and object-oriented programming&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;The objects we create in the database are &lt;code&gt;ObservableObject&lt;/code&gt;s&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;@FetchRequest&lt;/code&gt; fetches the objects and represents a "standing query"&lt;/li&gt;
&lt;li&gt;To get Core Data to a project it's required to check the box when creating a new project

&lt;ul&gt;
&lt;li&gt;If you already have a project where you want to add Core Data, create a new project and copy paste everything there&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--0nAdKI8G--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/oiywr6gnpt6b32zcwjee.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--0nAdKI8G--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/oiywr6gnpt6b32zcwjee.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;AppName.xcdatamodeId&lt;/p&gt;

&lt;p&gt;&lt;code&gt;SceneDelgate.swift&lt;/code&gt; creates &lt;code&gt;context&lt;/code&gt; that is then passed to all views using &lt;code&gt;.environment&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;@Environment&lt;/span&gt;&lt;span class="p"&gt;(\&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;managedObjectContext&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;context&lt;/span&gt;
&lt;span class="o"&gt;...&lt;/span&gt;
&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sheet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;isPresented&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="n"&gt;showFilter&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kt"&gt;FilterFlights&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;flightSearch&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="n"&gt;flightSearch&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;isPresented&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="n"&gt;showFilter&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;environment&lt;/span&gt;&lt;span class="p"&gt;(\&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;managedObjectContext&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;





&lt;div class="highlight"&gt;&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;@Environment&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;./&lt;/span&gt;&lt;span class="n"&gt;managedObjectContext&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;context&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;flight&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;Flight&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;context&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;flight&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;aircraft&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"B737"&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;ksjc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;Airport&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;context&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;ksjc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;icao&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"KSJC"&lt;/span&gt;
&lt;span class="n"&gt;flight&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;origin&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ksjc&lt;/span&gt; &lt;span class="c1"&gt;// add flight to ksjc.flightsFrom&lt;/span&gt;
&lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;save&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="c1"&gt;// disk might be full but in general don't fail&lt;/span&gt;

&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;request&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;NSFetchRequest&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;Flight&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;entityName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"Flight"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;predicate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;NSPredicate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;format&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"arrival &amp;lt; %@ and origin = %@"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;ksjc&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sortDescriptors&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;NSSortDescriptor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;key&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"indent"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;ascending&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;flights&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// KSJC flights sorted by ident&lt;/span&gt;
&lt;span class="c1"&gt;// flights is nil if fetch failed, [] if no such flights, otherwise [Flight]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;&lt;a href="https://twitter.com/reallankinen"&gt;@RealLankinen&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://dev.to/lankinen/cs193p-notes-lecture-1-course-logistics-and-introduction-to-swiftui-44ap"&gt;Notes 1&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/lankinen/cs193p-notes-lecture-2-mvvm-and-the-swift-type-system-406f"&gt;Notes 2&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/lankinen/cs193p-notes-lecture-3-reactive-ui-protocols-layout-5g8a"&gt;Notes 3&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/lankinen/cs193p-notes-lecture-4-grid-enum-optionals-4noj"&gt;Notes 4&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/lankinen/cs193p-notes-lecture-5-viewbuilder-shape-viewmodifier-fgh"&gt;Notes 5&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/lankinen/cs193p-notes-lecture-6-animation-1a8f"&gt;Notes 6&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/lankinen/cs193p-notes-lecture-7-multithreading-emojiart-2ak3"&gt;Notes 7&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/lankinen/cs193p-notes-lecture-8-gestures-json-1f3m"&gt;Notes 8&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/lankinen/cs193p-notes-lecture-9-data-flow-26e"&gt;Notes 9&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/lankinen/cs193p-notes-lecture-10-navigation-textfield-3ei9"&gt;Notes 10&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/lankinen/cs193p-notes-lecture-11-picker-2hgh"&gt;Notes 11&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/lankinen/cs193p-notes-lecture-12-core-data-eci"&gt;&lt;strong&gt;Notes 12&lt;/strong&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/lankinen/cs193p-notes-lecture-13-persistence-2jeh"&gt;Notes 13&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/lankinen/cs193p-notes-lecture-14-uikit-integration-1p7m"&gt;Notes 14&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://www.notion.so/lankinen/CS193p-2020-iOS-development-course-from-Stanford-81c094238e9d471bbf059ea8d83b3e15"&gt;Originally published here&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ios</category>
      <category>swift</category>
    </item>
    <item>
      <title>CS193p Notes - Lecture 11: Picker</title>
      <dc:creator>Lankinen</dc:creator>
      <pubDate>Sun, 26 Jul 2020 16:39:44 +0000</pubDate>
      <link>https://dev.to/lankinen/cs193p-notes-lecture-11-picker-2hgh</link>
      <guid>https://dev.to/lankinen/cs193p-notes-lecture-11-picker-2hgh</guid>
      <description>&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;var description: String { ... }&lt;/code&gt; can be used to define what the variable is going to show when printed. Struct needs to also function like &lt;code&gt;CustomStringConvertible&lt;/code&gt; to this work&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://youtu.be/fCfC6m7XUew?t=1456"&gt;24:16&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;struct&lt;/span&gt; &lt;span class="kt"&gt;FilterFlights&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;View&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;@Binding&lt;/span&gt; &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;flightSearch&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;FlightSearch&lt;/span&gt;
  &lt;span class="kd"&gt;@Binding&lt;/span&gt; &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;isPresented&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Bool&lt;/span&gt;

  &lt;span class="c1"&gt;// applies filters only when leaving the sheet&lt;/span&gt;
  &lt;span class="kd"&gt;@State&lt;/span&gt; &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;draft&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;FlightSearch&lt;/span&gt;

  &lt;span class="nf"&gt;init&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;flightSearch&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Binding&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;FlightSearch&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;isPresented&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Binding&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;Bool&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;_flightSearch&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;flightSearch&lt;/span&gt;
    &lt;span class="n"&gt;_isPresented&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;isPresented&lt;/span&gt;
    &lt;span class="n"&gt;_draft&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;State&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;wrappedValue&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;flightSearch&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;wrappedValue&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;Picker(...)&lt;/code&gt; takes 3 parameters: label, selection (binding to the thing where selected value is saved), and the views (you provide a bunch of views to choose from

&lt;ul&gt;
&lt;li&gt;Add &lt;code&gt;.tag(...)&lt;/code&gt; to the view that's clicked because this line will then update second argument to be what value is inside tag&lt;/li&gt;
&lt;li&gt;Looks much better when &lt;code&gt;Picker&lt;/code&gt; is put inside &lt;code&gt;Form&lt;/code&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;Form&lt;/code&gt; needs to be inside &lt;code&gt;NavigationView&lt;/code&gt; to make it clickable&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://twitter.com/reallankinen"&gt;@RealLankinen&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://dev.to/lankinen/cs193p-notes-lecture-1-course-logistics-and-introduction-to-swiftui-44ap"&gt;Notes 1&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/lankinen/cs193p-notes-lecture-2-mvvm-and-the-swift-type-system-406f"&gt;Notes 2&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/lankinen/cs193p-notes-lecture-3-reactive-ui-protocols-layout-5g8a"&gt;Notes 3&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/lankinen/cs193p-notes-lecture-4-grid-enum-optionals-4noj"&gt;Notes 4&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/lankinen/cs193p-notes-lecture-5-viewbuilder-shape-viewmodifier-fgh"&gt;Notes 5&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/lankinen/cs193p-notes-lecture-6-animation-1a8f"&gt;Notes 6&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/lankinen/cs193p-notes-lecture-7-multithreading-emojiart-2ak3"&gt;Notes 7&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/lankinen/cs193p-notes-lecture-8-gestures-json-1f3m"&gt;Notes 8&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/lankinen/cs193p-notes-lecture-9-data-flow-26e"&gt;Notes 9&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/lankinen/cs193p-notes-lecture-10-navigation-textfield-3ei9"&gt;Notes 10&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/lankinen/cs193p-notes-lecture-11-picker-2hgh"&gt;&lt;strong&gt;Notes 11&lt;/strong&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/lankinen/cs193p-notes-lecture-12-core-data-eci"&gt;Notes 12&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/lankinen/cs193p-notes-lecture-13-persistence-2jeh"&gt;Notes 13&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/lankinen/cs193p-notes-lecture-14-uikit-integration-1p7m"&gt;Notes 14&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://www.notion.so/lankinen/CS193p-2020-iOS-development-course-from-Stanford-81c094238e9d471bbf059ea8d83b3e15"&gt;Originally published here&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ios</category>
      <category>swift</category>
    </item>
    <item>
      <title>CS193p Notes - Lecture 10: Navigation + TextField</title>
      <dc:creator>Lankinen</dc:creator>
      <pubDate>Sun, 26 Jul 2020 16:39:20 +0000</pubDate>
      <link>https://dev.to/lankinen/cs193p-notes-lecture-10-navigation-textfield-3ei9</link>
      <guid>https://dev.to/lankinen/cs193p-notes-lecture-10-navigation-textfield-3ei9</guid>
      <description>&lt;ul&gt;
&lt;li&gt;&lt;code&gt;popover(...)&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;ViewModel is passed to subviews using &lt;code&gt;@EnvironmentObject&lt;/code&gt;

&lt;ul&gt;
&lt;li&gt;Add var with &lt;code&gt;@EnvironmentObject&lt;/code&gt; property wrapper to the sub view and give &lt;code&gt;@ObservedObject&lt;/code&gt; ViewModel to it by adding &lt;code&gt;.environmentObject(self.viewModel)&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Navigate to another view by clicking an item&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kt"&gt;NavigationView&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kt"&gt;List&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;ForEach&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;store&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;documents&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;document&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; 
      &lt;span class="kt"&gt;NavigationLink&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;destination&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;EmojiArtDocumentView&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;document&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;document&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kt"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;store&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;name&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;for&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;document&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Delete items from list&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kt"&gt;List&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kt"&gt;ForEach&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="o"&gt;...&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;onDelete&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;indexSet&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt;
    &lt;span class="n"&gt;indexSet&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;map&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;store&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;documents&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;$0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;forEach&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;document&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt;
      &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;store&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;removeDocument&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;document&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;navigationBarItems&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nv"&gt;trailing&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;EditButton&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;&lt;a href="https://twitter.com/reallankinen"&gt;@RealLankinen&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://dev.to/lankinen/cs193p-notes-lecture-1-course-logistics-and-introduction-to-swiftui-44ap"&gt;Notes 1&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/lankinen/cs193p-notes-lecture-2-mvvm-and-the-swift-type-system-406f"&gt;Notes 2&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/lankinen/cs193p-notes-lecture-3-reactive-ui-protocols-layout-5g8a"&gt;Notes 3&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/lankinen/cs193p-notes-lecture-4-grid-enum-optionals-4noj"&gt;Notes 4&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/lankinen/cs193p-notes-lecture-5-viewbuilder-shape-viewmodifier-fgh"&gt;Notes 5&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/lankinen/cs193p-notes-lecture-6-animation-1a8f"&gt;Notes 6&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/lankinen/cs193p-notes-lecture-7-multithreading-emojiart-2ak3"&gt;Notes 7&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/lankinen/cs193p-notes-lecture-8-gestures-json-1f3m"&gt;Notes 8&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/lankinen/cs193p-notes-lecture-9-data-flow-26e"&gt;Notes 9&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/lankinen/cs193p-notes-lecture-10-navigation-textfield-3ei9"&gt;&lt;strong&gt;Notes 10&lt;/strong&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/lankinen/cs193p-notes-lecture-11-picker-2hgh"&gt;Notes 11&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/lankinen/cs193p-notes-lecture-12-core-data-eci"&gt;Notes 12&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/lankinen/cs193p-notes-lecture-13-persistence-2jeh"&gt;Notes 13&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/lankinen/cs193p-notes-lecture-14-uikit-integration-1p7m"&gt;Notes 14&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://www.notion.so/lankinen/CS193p-2020-iOS-development-course-from-Stanford-81c094238e9d471bbf059ea8d83b3e15"&gt;Originally published here&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ios</category>
      <category>swift</category>
    </item>
    <item>
      <title>CS193p Notes - Lecture 9: Data Flow</title>
      <dc:creator>Lankinen</dc:creator>
      <pubDate>Sun, 26 Jul 2020 16:38:54 +0000</pubDate>
      <link>https://dev.to/lankinen/cs193p-notes-lecture-9-data-flow-26e</link>
      <guid>https://dev.to/lankinen/cs193p-notes-lecture-9-data-flow-26e</guid>
      <description>&lt;p&gt;Property Wrappers&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Property wrappers are things like &lt;code&gt;@Publish&lt;/code&gt; that are put before &lt;code&gt;var&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;A property wrapper actually creates a struct
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;@Published&lt;/span&gt; &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;emojiArt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;EmojiArt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;EmojiArt&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="kd"&gt;struct&lt;/span&gt; &lt;span class="kt"&gt;Published&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;wrappedValue&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;EmojiArt&lt;/span&gt;
  &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;projectedValue&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Publisher&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;EmojiArt&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;Never&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; 
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;_emojiArt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Published&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;Published&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;wrappedValue&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;EmojiArt&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;emojiArt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;EmojiArt&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;get&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;_emojiArt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;wrappedValue&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;set&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;_emojiArt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;wrappedValue&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;newValue&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;Publisher&amp;lt;EmojiArt, Never&amp;gt;&lt;/code&gt; is a type that property wrapper decides

&lt;ul&gt;
&lt;li&gt;The point of wrappers is that it's possible to do something when the value is get/set&lt;/li&gt;
&lt;li&gt;For example when &lt;code&gt;Published&lt;/code&gt; wrapperValue is changed, it's calling &lt;code&gt;objectWillChange.send()&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;$&lt;/code&gt; is binding&lt;/li&gt;
&lt;li&gt;Binding is used a lot and it's very important because it's all about having a single source of the truth
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;struct&lt;/span&gt; &lt;span class="kt"&gt;MyView&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;View&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;@State&lt;/span&gt; &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;myString&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Hello"&lt;/span&gt;
  &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;View&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;OtherView&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;sharedText&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="n"&gt;myString&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="kd"&gt;struct&lt;/span&gt; &lt;span class="kt"&gt;OtherView&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;View&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;@Binding&lt;/span&gt; &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;sharedText&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt;
  &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;View&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sharedText&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;@EnvironmentObject&lt;/code&gt; is similar to &lt;code&gt;.fill()&lt;/code&gt; because when it's use in viewModel it's actually added to all of the views under neath the main View where it's called.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Publishers (&lt;a href="https://youtu.be/0i152oA3T3s?t=1097"&gt;18:17&lt;/a&gt;)
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;Publisher&amp;lt;Output, Failure&amp;gt;&lt;/code&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;Output&lt;/code&gt; is the type of thing this &lt;code&gt;Publisher&lt;/code&gt; publishes&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Failure&lt;/code&gt; is the type of thing it communicates if it fails while trying to publish&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Demo
&lt;/h3&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;import&lt;/span&gt; &lt;span class="kt"&gt;Combine&lt;/span&gt;
&lt;span class="o"&gt;...&lt;/span&gt;
  &lt;span class="kd"&gt;@Published&lt;/span&gt; &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;emojiArt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;EmojiArt&lt;/span&gt;
  &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;autosaveCancellable&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;AnyCancellable&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt;
&lt;span class="o"&gt;...&lt;/span&gt;
  &lt;span class="nf"&gt;init&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="o"&gt;...&lt;/span&gt;
    &lt;span class="n"&gt;autosaveCancellable&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="n"&gt;emojiArt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sink&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;emojiArt&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt;
      &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\(&lt;/span&gt;&lt;span class="n"&gt;emojiArt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;utf8&lt;/span&gt; &lt;span class="p"&gt;??&lt;/span&gt; &lt;span class="s"&gt;"nill"&lt;/span&gt;&lt;span class="se"&gt;)&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="kt"&gt;UserDefaults&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;standard&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;emojiArt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;forKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;EmojiArtDocument&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;untitled&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;When sink is stored to a variable, it's going to work as long as this ViewModel exists

&lt;ul&gt;
&lt;li&gt;This way it's auto saving all the changes as long as ViewModel is used&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://twitter.com/reallankinen"&gt;@RealLankinen&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://dev.to/lankinen/cs193p-notes-lecture-1-course-logistics-and-introduction-to-swiftui-44ap"&gt;Notes 1&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/lankinen/cs193p-notes-lecture-2-mvvm-and-the-swift-type-system-406f"&gt;Notes 2&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/lankinen/cs193p-notes-lecture-3-reactive-ui-protocols-layout-5g8a"&gt;Notes 3&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/lankinen/cs193p-notes-lecture-4-grid-enum-optionals-4noj"&gt;Notes 4&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/lankinen/cs193p-notes-lecture-5-viewbuilder-shape-viewmodifier-fgh"&gt;Notes 5&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/lankinen/cs193p-notes-lecture-6-animation-1a8f"&gt;Notes 6&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/lankinen/cs193p-notes-lecture-7-multithreading-emojiart-2ak3"&gt;Notes 7&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/lankinen/cs193p-notes-lecture-8-gestures-json-1f3m"&gt;Notes 8&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/lankinen/cs193p-notes-lecture-9-data-flow-26e"&gt;&lt;strong&gt;Notes 9&lt;/strong&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/lankinen/cs193p-notes-lecture-10-navigation-textfield-3ei9"&gt;Notes 10&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/lankinen/cs193p-notes-lecture-11-picker-2hgh"&gt;Notes 11&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/lankinen/cs193p-notes-lecture-12-core-data-eci"&gt;Notes 12&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/lankinen/cs193p-notes-lecture-13-persistence-2jeh"&gt;Notes 13&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/lankinen/cs193p-notes-lecture-14-uikit-integration-1p7m"&gt;Notes 14&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://www.notion.so/lankinen/CS193p-2020-iOS-development-course-from-Stanford-81c094238e9d471bbf059ea8d83b3e15"&gt;Originally published here&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ios</category>
      <category>swift</category>
    </item>
    <item>
      <title>CS193p Notes - Lecture 8: Gestures JSON</title>
      <dc:creator>Lankinen</dc:creator>
      <pubDate>Sun, 26 Jul 2020 16:38:28 +0000</pubDate>
      <link>https://dev.to/lankinen/cs193p-notes-lecture-8-gestures-json-1f3m</link>
      <guid>https://dev.to/lankinen/cs193p-notes-lecture-8-gestures-json-1f3m</guid>
      <description>&lt;h3&gt;
  
  
  UserDefaults
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Numerous ways to make data persists in iOS:

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;FileManager&lt;/code&gt; filesystem&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;CoreData&lt;/code&gt; SQL database&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;CloudKit&lt;/code&gt; database in the cloud&lt;/li&gt;
&lt;li&gt;3rd party options&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;UserDefaults&lt;/code&gt; simplest to use but only for lightweight data. Like dictionary.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;UserDefaults&lt;/code&gt; is most often used by making one instance and using it everywhere

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;let defaults = UserDefaults.standard&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;defaults.set(object, forKey: "SomeKey")&lt;/code&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;let i: Int = defaults.integer(forKey: "MyInteger")&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;let b: Data? = defaults.data(forKey: "MyData")&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;let a = array(forKey: "MyArray")&lt;/code&gt; this returns &lt;code&gt;Array&amp;lt;Any&amp;gt;&lt;/code&gt;

&lt;ul&gt;
&lt;li&gt;To use &lt;code&gt;Any&lt;/code&gt; type it's possible to change the type with &lt;code&gt;as&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Gestures (&lt;a href="https://youtu.be/mz-rNLWJ0bk?t=517"&gt;8:37&lt;/a&gt;)
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;myView.gesture(theGesture)&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;gesture is implemented in func or computer var
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;theGesture&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kd"&gt;some&lt;/span&gt; &lt;span class="kt"&gt;Gesture&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kt"&gt;TapGesture&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;count&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;onEnded&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;non-discrete gestures&lt;/p&gt;

&lt;p&gt;To see end result&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;theGesture&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kd"&gt;some&lt;/span&gt; &lt;span class="kt"&gt;Gesture&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kt"&gt;DragGesture&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;onEnded&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="o"&gt;...&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;To see the value of gesture&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;@GestureState&lt;/span&gt; &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;myGestureState&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;MyGestureStateType&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;starting&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Returns &lt;code&gt;&amp;lt;starting value&amp;gt;&lt;/code&gt; always when the gesture ends.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;theGesture&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kd"&gt;some&lt;/span&gt; &lt;span class="kt"&gt;Gesture&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kt"&gt;DragGesture&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;updating&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="n"&gt;myGestureState&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;myGestureState&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;transaction&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt;
      &lt;span class="n"&gt;myGestureState&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="cm"&gt;/* usually something related to value */&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;onEnded&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="cm"&gt;/* do something */&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;&lt;code&gt;myGestureState&lt;/code&gt; can be modified only inside &lt;code&gt;.updating&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;theGesture&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kd"&gt;some&lt;/span&gt; &lt;span class="kt"&gt;Gesture&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kt"&gt;DragGesture&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;onChanged&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt;
      &lt;span class="cm"&gt;/* do something with value (which is the state of the fingers) */&lt;/span&gt;
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;onEnded&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="cm"&gt;/* do something */&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;.updating&lt;/code&gt; is better in most of the cases because you care only the relative change&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Demo (&lt;a href="https://youtu.be/mz-rNLWJ0bk?t=1341"&gt;22:21&lt;/a&gt;)
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;UserDefaults.standard.set(emojiArt.json, forKey: "EmojiArtDocument.Untitled")&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Codable&lt;/code&gt; property means that struct can be encoded and decoded
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;json&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Data&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="kt"&gt;JSONEncoder&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;encode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nf"&gt;init&lt;/span&gt;&lt;span class="p"&gt;?(&lt;/span&gt;&lt;span class="nv"&gt;json&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Data&lt;/span&gt;&lt;span class="p"&gt;?)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;newEmojiArt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="kt"&gt;JSONDecoder&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;decode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;EmojiArt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;from&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;self&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;newEmojiArt&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;nil&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Double tap makes zooms in a way that you can see the full image&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="o"&gt;...&lt;/span&gt;
&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;gesture&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;doubleTapToZoom&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;in&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;geometry&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

&lt;span class="o"&gt;...&lt;/span&gt;

&lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;doubleTapToZoom&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="nv"&gt;size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;CGSize&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kd"&gt;some&lt;/span&gt; &lt;span class="kt"&gt;Gesture&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kt"&gt;TapGesture&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;count&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;onEnded&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="n"&gt;withAnimation&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;zoomToFit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;document&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;backgroundImage&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;in&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;zoomToFit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="nv"&gt;image&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;UIImage&lt;/span&gt;&lt;span class="p"&gt;?,&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="nv"&gt;size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;CGSize&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;image&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;image&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;image&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;width&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;image&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;height&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;hZoom&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;width&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;image&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;width&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;vZoom&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;height&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;image&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;height&lt;/span&gt;
    &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;zoomScale&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;min&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;hZoom&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;vZoom&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;&lt;a href="https://twitter.com/reallankinen"&gt;@RealLankinen&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://dev.to/lankinen/cs193p-notes-lecture-1-course-logistics-and-introduction-to-swiftui-44ap"&gt;Notes 1&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/lankinen/cs193p-notes-lecture-2-mvvm-and-the-swift-type-system-406f"&gt;Notes 2&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/lankinen/cs193p-notes-lecture-3-reactive-ui-protocols-layout-5g8a"&gt;Notes 3&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/lankinen/cs193p-notes-lecture-4-grid-enum-optionals-4noj"&gt;Notes 4&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/lankinen/cs193p-notes-lecture-5-viewbuilder-shape-viewmodifier-fgh"&gt;Notes 5&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/lankinen/cs193p-notes-lecture-6-animation-1a8f"&gt;Notes 6&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/lankinen/cs193p-notes-lecture-7-multithreading-emojiart-2ak3"&gt;Notes 7&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/lankinen/cs193p-notes-lecture-8-gestures-json-1f3m"&gt;&lt;strong&gt;Notes 8&lt;/strong&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/lankinen/cs193p-notes-lecture-9-data-flow-26e"&gt;Notes 9&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/lankinen/cs193p-notes-lecture-10-navigation-textfield-3ei9"&gt;Notes 10&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/lankinen/cs193p-notes-lecture-11-picker-2hgh"&gt;Notes 11&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/lankinen/cs193p-notes-lecture-12-core-data-eci"&gt;Notes 12&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/lankinen/cs193p-notes-lecture-13-persistence-2jeh"&gt;Notes 13&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/lankinen/cs193p-notes-lecture-14-uikit-integration-1p7m"&gt;Notes 14&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://www.notion.so/lankinen/CS193p-2020-iOS-development-course-from-Stanford-81c094238e9d471bbf059ea8d83b3e15"&gt;Originally published here&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ios</category>
      <category>swift</category>
    </item>
    <item>
      <title>CS193p Notes - Lecture 7: Multithreading EmojiArt</title>
      <dc:creator>Lankinen</dc:creator>
      <pubDate>Sun, 26 Jul 2020 16:38:09 +0000</pubDate>
      <link>https://dev.to/lankinen/cs193p-notes-lecture-7-multithreading-emojiart-2ak3</link>
      <guid>https://dev.to/lankinen/cs193p-notes-lecture-7-multithreading-emojiart-2ak3</guid>
      <description>&lt;h3&gt;
  
  
  Colors and Images
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;UIColor allows manipulating colors&lt;/li&gt;
&lt;li&gt;Image is a View that takes name (String) of the image in Assets.xcassets folder

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;Image(uiImage: self.document.backgoundImage)&lt;/code&gt; and &lt;code&gt;backgroundImage: UIImage?&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;It's also possible to get system images

&lt;ul&gt;
&lt;li&gt;See the different system images by downloading an app from here &lt;a href="https://developer.apple.com/design/"&gt;https://developer.apple.com/design/&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Multithreaded Programming (&lt;a href="https://youtu.be/tmx-OwkBWxA?t=375"&gt;6:15&lt;/a&gt;)
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;UI code is using main queue&lt;/li&gt;
&lt;li&gt;Grand Central Dispatch (GCD) is where queue stuff is called

&lt;ul&gt;
&lt;li&gt;Two fundamental tasks:

&lt;ol&gt;
&lt;li&gt;getting access to a queue&lt;/li&gt;
&lt;li&gt;plopping a block of code on a queue&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;DispatchQueue.main&lt;/code&gt; is the queue where all UI code must be posted&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;DispatchQueue.global(qos: QoS)&lt;/code&gt; a non-UI queue with a certain quality of service

&lt;ul&gt;
&lt;li&gt;qos is one of the following

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;.userInterface&lt;/code&gt; do this fast because UI depends on it&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;.userInitiated&lt;/code&gt; the user just asked to do this, so do it now&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;.utility&lt;/code&gt; needs to happen but user didn't asked for it&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;.background&lt;/code&gt; maintenance tasks (cleanups, etc.)
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;queue&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;DispatchQueue&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;main&lt;/span&gt; &lt;span class="n"&gt;or&lt;/span&gt; &lt;span class="kt"&gt;Dispatch&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;global&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;gos&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;queue&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;async&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;Dispatch.global(gos: )&lt;/code&gt; not used very much because there are higher level APIs for specific use cases(e.g. &lt;code&gt;URLSession&lt;/code&gt;)&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  EmojiArt Demo (&lt;a href="https://youtu.be/tmx-OwkBWxA?t=1238"&gt;20:38&lt;/a&gt;)
&lt;/h3&gt;

&lt;p&gt;View&lt;br&gt;
&lt;/p&gt;

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

&lt;span class="kd"&gt;struct&lt;/span&gt; &lt;span class="kt"&gt;EmojiArtDocumentView&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;View&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;@ObservedObject&lt;/span&gt; &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;document&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;EmojiArtDocument&lt;/span&gt;

  &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kd"&gt;some&lt;/span&gt; &lt;span class="kt"&gt;View&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;ModelView&lt;br&gt;
&lt;/p&gt;

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

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="kt"&gt;EmojiArtDocument&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;ObservableObject&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;When looping through strings, it doesn't make sense to make all strings in the app identifiable but just those. There is parameter &lt;code&gt;id&lt;/code&gt; in &lt;code&gt;ForEach&lt;/code&gt; that can be set to &lt;code&gt;\.self&lt;/code&gt; to use string's own value as identifier.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;struct&lt;/span&gt; &lt;span class="kt"&gt;EmojiArt&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;backgroundURL&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;URL&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt;
  &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;emojis&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;Emoji&lt;/span&gt;&lt;span class="p"&gt;]()&lt;/span&gt;

  &lt;span class="kd"&gt;struct&lt;/span&gt; &lt;span class="kt"&gt;Emoji&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Identifiable&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt;
    &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;x&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Int&lt;/span&gt;
    &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;y&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Int&lt;/span&gt;
    &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Int&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Int&lt;/span&gt;

    &lt;span class="kd"&gt;fileprivate&lt;/span&gt; &lt;span class="nf"&gt;init&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;x&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;y&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt;
      &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;
      &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;
      &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;size&lt;/span&gt;
      &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;uniqueEmojiId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;

  &lt;span class="k"&gt;mutating&lt;/span&gt; &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;addEmoji&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="nv"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;x&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;y&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;uniqueEmojiId&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
    &lt;span class="n"&gt;emojis&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Emoij&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;x&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;y&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;uniqueEmojiId&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; 
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;privatefile&lt;/code&gt; makes init only accessible from that file and that way other files can't create emojis

&lt;ul&gt;
&lt;li&gt;In this case we wanted to do this because there is unique way to create id for each emoji and we don't want any other file to create emojis with it's own id system&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;Model should be private in ViewModel because it's job is to offer intent(s) which View will use to access Model&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://twitter.com/reallankinen"&gt;@RealLankinen&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://dev.to/lankinen/cs193p-notes-lecture-1-course-logistics-and-introduction-to-swiftui-44ap"&gt;Notes 1&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/lankinen/cs193p-notes-lecture-2-mvvm-and-the-swift-type-system-406f"&gt;Notes 2&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/lankinen/cs193p-notes-lecture-3-reactive-ui-protocols-layout-5g8a"&gt;Notes 3&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/lankinen/cs193p-notes-lecture-4-grid-enum-optionals-4noj"&gt;Notes 4&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/lankinen/cs193p-notes-lecture-5-viewbuilder-shape-viewmodifier-fgh"&gt;Notes 5&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/lankinen/cs193p-notes-lecture-6-animation-1a8f"&gt;Notes 6&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/lankinen/cs193p-notes-lecture-7-multithreading-emojiart-2ak3"&gt;&lt;strong&gt;Notes 7&lt;/strong&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/lankinen/cs193p-notes-lecture-8-gestures-json-1f3m"&gt;Notes 8&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/lankinen/cs193p-notes-lecture-9-data-flow-26e"&gt;Notes 9&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/lankinen/cs193p-notes-lecture-10-navigation-textfield-3ei9"&gt;Notes 10&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/lankinen/cs193p-notes-lecture-11-picker-2hgh"&gt;Notes 11&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/lankinen/cs193p-notes-lecture-12-core-data-eci"&gt;Notes 12&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/lankinen/cs193p-notes-lecture-13-persistence-2jeh"&gt;Notes 13&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/lankinen/cs193p-notes-lecture-14-uikit-integration-1p7m"&gt;Notes 14&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://www.notion.so/lankinen/CS193p-2020-iOS-development-course-from-Stanford-81c094238e9d471bbf059ea8d83b3e15"&gt;Originally published here&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ios</category>
      <category>swift</category>
    </item>
    <item>
      <title>CS193p Notes - Lecture 6: Animation</title>
      <dc:creator>Lankinen</dc:creator>
      <pubDate>Sun, 26 Jul 2020 16:37:25 +0000</pubDate>
      <link>https://dev.to/lankinen/cs193p-notes-lecture-6-animation-1a8f</link>
      <guid>https://dev.to/lankinen/cs193p-notes-lecture-6-animation-1a8f</guid>
      <description>&lt;h3&gt;
  
  
  Property Observers
&lt;/h3&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;isFaceUp&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Bool&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;willSet&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;newValue&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nf"&gt;startUsingBonusTime&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nf"&gt;stopUsingBonusTime&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Syntax reminds computer var but it's not the same thing&lt;/li&gt;
&lt;li&gt;Most of the cases &lt;code&gt;newValue&lt;/code&gt; contains the value it's going to get but in &lt;code&gt;didSet&lt;/code&gt; the value is in &lt;code&gt;oldValue&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  @State (&lt;a href="https://youtu.be/3krC2c56ceQ?t=107"&gt;1:47&lt;/a&gt;)
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Views are read only&lt;/li&gt;
&lt;li&gt;Sometimes we want to keep some state and that happens by adding &lt;code&gt;@state&lt;/code&gt; front of var

&lt;ul&gt;
&lt;li&gt;Case might be that we want to allow user to edit some image first and then the intention is called with all the state changes and it's stored to the model.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;Changing a variable with &lt;code&gt;@state&lt;/code&gt; redraws the view&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Animation (&lt;a href="https://youtu.be/3krC2c56ceQ?t=494"&gt;8:14&lt;/a&gt;)
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Animation happens after the thing happened but in user's point of view it looks like happening the same time

&lt;ul&gt;
&lt;li&gt;The idea is that the value is changed once from A to B and animation is played instead of changing the values from A to B and drawing the animation after every change&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;The point of animation is to draw attention to thing that change&lt;/li&gt;
&lt;li&gt;Changes to views in containers that are already on screen

&lt;ul&gt;
&lt;li&gt;The appearance and disappearance of Views&lt;/li&gt;
&lt;li&gt;Changes to the arguments to Animatable view modifiers of Views&lt;/li&gt;
&lt;li&gt;Changes to the arguments to the creation of Shapes&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;

&lt;p&gt;Two ways to animate&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Implicitly &lt;code&gt;.animation(Animation)&lt;/code&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;"Automatic animation"
&lt;/li&gt;
&lt;/ul&gt;

&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kt"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Ghost"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;opacity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;scary&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;rotationEffect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Angle&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;degrees&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;upsideDown&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="mi"&gt;180&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
  &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;animation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Animation&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;easeInOut&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;



&lt;ul&gt;
&lt;li&gt;You can control

&lt;ul&gt;
&lt;li&gt;duration&lt;/li&gt;
&lt;li&gt;delay&lt;/li&gt;
&lt;li&gt;repeat&lt;/li&gt;
&lt;li&gt;curve

&lt;ul&gt;
&lt;li&gt;rate at which the animation plays out

&lt;ul&gt;
&lt;li&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;When added to a container, all the items inside it get's own animation instead of animating the whole container as one&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;

&lt;p&gt;Explicitly &lt;code&gt;withAnimation(Animation) { }&lt;/code&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Primary way of doing animation&lt;/li&gt;
&lt;li&gt;This allows to do the same animation for a bunch of views&lt;/li&gt;
&lt;li&gt;Explicit animations do not override an implicit animation&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;

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

&lt;ul&gt;
&lt;li&gt;Specify how to animate the arrival/departure of Views
&lt;/li&gt;
&lt;/ul&gt;

&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kt"&gt;ZStack&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;isFaceUp&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;RoundedRectangle&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;
    &lt;span class="kt"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Ghost"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;transition&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;scale&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;RoundedRectangle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;cornerRadius&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;transition&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;identity&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;



&lt;ul&gt;
&lt;li&gt;If &lt;code&gt;isFaceUp&lt;/code&gt; changed (while ZStack is on screen and an explicit animation is in progress) ...

&lt;ul&gt;
&lt;li&gt;... to false, the back would appear instantly, Text would shrink to nothing, front RR fade out.&lt;/li&gt;
&lt;li&gt;... to true, the back would disappear instantly, Text grow in from nothing, front RR fade in.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Places like if-else or for loop where the data changes are good for animations to highlight users the change.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Difference between Button and Text with OnTouch gesture is that different operating systems (WatchOS, iOS) know how to show it the best for the user&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://twitter.com/reallankinen"&gt;@RealLankinen&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://dev.to/lankinen/cs193p-notes-lecture-1-course-logistics-and-introduction-to-swiftui-44ap"&gt;Notes 1&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/lankinen/cs193p-notes-lecture-2-mvvm-and-the-swift-type-system-406f"&gt;Notes 2&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/lankinen/cs193p-notes-lecture-3-reactive-ui-protocols-layout-5g8a"&gt;Notes 3&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/lankinen/cs193p-notes-lecture-4-grid-enum-optionals-4noj"&gt;Notes 4&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/lankinen/cs193p-notes-lecture-5-viewbuilder-shape-viewmodifier-fgh"&gt;Notes 5&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/lankinen/cs193p-notes-lecture-6-animation-1a8f"&gt;&lt;strong&gt;Notes 6&lt;/strong&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/lankinen/cs193p-notes-lecture-7-multithreading-emojiart-2ak3"&gt;Notes 7&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/lankinen/cs193p-notes-lecture-8-gestures-json-1f3m"&gt;Notes 8&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/lankinen/cs193p-notes-lecture-9-data-flow-26e"&gt;Notes 9&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/lankinen/cs193p-notes-lecture-10-navigation-textfield-3ei9"&gt;Notes 10&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/lankinen/cs193p-notes-lecture-11-picker-2hgh"&gt;Notes 11&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/lankinen/cs193p-notes-lecture-12-core-data-eci"&gt;Notes 12&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/lankinen/cs193p-notes-lecture-13-persistence-2jeh"&gt;Notes 13&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/lankinen/cs193p-notes-lecture-14-uikit-integration-1p7m"&gt;Notes 14&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://www.notion.so/lankinen/CS193p-2020-iOS-development-course-from-Stanford-81c094238e9d471bbf059ea8d83b3e15"&gt;Originally published here&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ios</category>
      <category>swift</category>
    </item>
    <item>
      <title>CS193p Notes - Lecture 5: ViewBuilder + Shape + ViewModifier</title>
      <dc:creator>Lankinen</dc:creator>
      <pubDate>Sun, 26 Jul 2020 16:36:42 +0000</pubDate>
      <link>https://dev.to/lankinen/cs193p-notes-lecture-5-viewbuilder-shape-viewmodifier-fgh</link>
      <guid>https://dev.to/lankinen/cs193p-notes-lecture-5-viewbuilder-shape-viewmodifier-fgh</guid>
      <description>&lt;h3&gt;
  
  
  Access control
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;private&lt;/code&gt; doesn't allow anyone outside the struct/class access it&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;private(set)&lt;/code&gt; means that setting is private but reading is not meaning that anyone can read it&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  ViewBuilder (&lt;a href="https://youtu.be/oDKDGCRdSHc?t=725"&gt;12:05)&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;@ViewBuilder&lt;/code&gt; can be added to any function that returns a view. If there is a list of views it combines them into one.&lt;/p&gt;

&lt;p&gt;"The contents of a &lt;code&gt;@ViewBuilder&lt;/code&gt; is a list of Views. No need to type &lt;code&gt;return&lt;/code&gt;. Cannot use &lt;code&gt;var&lt;/code&gt;s.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;@ViewBuilder&lt;/span&gt;
&lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;front&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;of&lt;/span&gt; &lt;span class="nv"&gt;card&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Card&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kd"&gt;some&lt;/span&gt; &lt;span class="kt"&gt;View&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kt"&gt;RoundedRectangle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;cornerRadius&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="kt"&gt;RoundedRectangle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;cornerRadius&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stroke&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="kt"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;card&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;content&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h3&gt;
  
  
  Shape (&lt;a href="https://youtu.be/oDKDGCRdSHc?t=1222"&gt;20:22&lt;/a&gt;)
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;CG&lt;/code&gt; = Core Graphics&lt;br&gt;
&lt;/p&gt;

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

&lt;span class="kd"&gt;struct&lt;/span&gt; &lt;span class="kt"&gt;Pie&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Shape&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;startAngle&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Angle&lt;/span&gt;
  &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;endAngle&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Angle&lt;/span&gt;
  &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;clockwise&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Bool&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;

  &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="nv"&gt;rect&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;CGRect&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Path&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;center&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;CGPoint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;x&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;react&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;midX&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;y&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;react&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;midY&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;radius&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;min&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;rect&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;width&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;rect&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;height&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;start&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;CGPoint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="nv"&gt;x&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;center&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;radius&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nf"&gt;cos&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;CGFloat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;startAngle&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;radians&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
      &lt;span class="nv"&gt;y&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;center&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;radius&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nf"&gt;sin&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;CGFloat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;startAngle&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;radians&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;p&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;Path&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;move&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;to&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;center&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;to&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addArc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="nv"&gt;center&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;center&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nv"&gt;radius&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;radius&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nv"&gt;startAngle&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;startAngle&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nv"&gt;endAngle&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;endAngle&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nv"&gt;clockwise&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;clockwise&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;to&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;center&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;0 degrees is to right&lt;/li&gt;
&lt;li&gt;0x0 is in left top corner and increases by going down and right&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  ViewModifier (&lt;a href="https://youtu.be/oDKDGCRdSHc?t=2514"&gt;41:54&lt;/a&gt;)
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;There are two things that can be animated: shapes and views.&lt;/li&gt;
&lt;li&gt;Animating views happens in ViewModifier&lt;/li&gt;
&lt;li&gt;Modifier can for example make any view to look like a card, cardify
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kt"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Ghost"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;modifier&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Cardify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;isFaceUp&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

&lt;span class="kd"&gt;struct&lt;/span&gt; &lt;span class="kt"&gt;Cardify&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;ViewModifier&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;isFaceUp&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Bool&lt;/span&gt;
  &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;body&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Content&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kd"&gt;some&lt;/span&gt; &lt;span class="kt"&gt;View&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;ZStack&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;isFaceUp&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kt"&gt;RoundedRectangle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;cornerRadius&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fill&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Color&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;white&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="kt"&gt;RoundedRectangle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;cornerRadius&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stroke&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="n"&gt;content&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kt"&gt;RoundedRectangle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;cornerRadius&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;





&lt;div class="highlight"&gt;&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kt"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Ghost"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;cardify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;isFaceUp&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="kd"&gt;extension&lt;/span&gt; &lt;span class="kt"&gt;View&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;cardify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;isFaceUp&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Bool&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kd"&gt;some&lt;/span&gt; &lt;span class="kt"&gt;View&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;modifier&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Cardify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;isFaceUp&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;isFaceUp&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;&lt;a href="https://twitter.com/reallankinen"&gt;@RealLankinen&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://dev.to/lankinen/cs193p-notes-lecture-1-course-logistics-and-introduction-to-swiftui-44ap"&gt;Notes 1&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/lankinen/cs193p-notes-lecture-2-mvvm-and-the-swift-type-system-406f"&gt;Notes 2&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/lankinen/cs193p-notes-lecture-3-reactive-ui-protocols-layout-5g8a"&gt;Notes 3&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/lankinen/cs193p-notes-lecture-4-grid-enum-optionals-4noj"&gt;Notes 4&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/lankinen/cs193p-notes-lecture-5-viewbuilder-shape-viewmodifier-fgh"&gt;&lt;strong&gt;Notes 5&lt;/strong&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/lankinen/cs193p-notes-lecture-6-animation-1a8f"&gt;Notes 6&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/lankinen/cs193p-notes-lecture-7-multithreading-emojiart-2ak3"&gt;Notes 7&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/lankinen/cs193p-notes-lecture-8-gestures-json-1f3m"&gt;Notes 8&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/lankinen/cs193p-notes-lecture-9-data-flow-26e"&gt;Notes 9&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/lankinen/cs193p-notes-lecture-10-navigation-textfield-3ei9"&gt;Notes 10&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/lankinen/cs193p-notes-lecture-11-picker-2hgh"&gt;Notes 11&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/lankinen/cs193p-notes-lecture-12-core-data-eci"&gt;Notes 12&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/lankinen/cs193p-notes-lecture-13-persistence-2jeh"&gt;Notes 13&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/lankinen/cs193p-notes-lecture-14-uikit-integration-1p7m"&gt;Notes 14&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://www.notion.so/lankinen/CS193p-2020-iOS-development-course-from-Stanford-81c094238e9d471bbf059ea8d83b3e15"&gt;Originally published here&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ios</category>
      <category>swift</category>
    </item>
    <item>
      <title>CS193p Notes - Lecture 4: Grid + enum + Optionals</title>
      <dc:creator>Lankinen</dc:creator>
      <pubDate>Sun, 26 Jul 2020 16:36:11 +0000</pubDate>
      <link>https://dev.to/lankinen/cs193p-notes-lecture-4-grid-enum-optionals-4noj</link>
      <guid>https://dev.to/lankinen/cs193p-notes-lecture-4-grid-enum-optionals-4noj</guid>
      <description>&lt;h3&gt;
  
  
  Grid
&lt;/h3&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="nf"&gt;init&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="nv"&gt;items&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;Item&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="nv"&gt;viewForItem&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kd"&gt;@escaping&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Item&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;ItemView&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;items&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;items&lt;/span&gt;
    &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;viewForItem&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;viewForItem&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;@escaping&lt;/code&gt; is required because function is not used inside init but used somewhere else.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;extension&lt;/span&gt; &lt;span class="kt"&gt;Array&lt;/span&gt; &lt;span class="k"&gt;where&lt;/span&gt; &lt;span class="kt"&gt;Element&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Identifiable&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;firstIndex&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;matching&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Element&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Int&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;index&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;..&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;count&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;matching&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;index&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Adds new function to all Arrays where elements are identifiable&lt;/li&gt;
&lt;li&gt;Name of the file &lt;code&gt;Array+Identifiable&lt;/code&gt; tells that it's identifiable extension to Array&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  Enum
&lt;/h3&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;enum&lt;/span&gt; &lt;span class="kt"&gt;FastFoodMenuItem&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="nf"&gt;hamburger&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;numberOfPatties&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="nf"&gt;fries&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;FryOrderSize&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="nf"&gt;drink&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;ounces&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="n"&gt;cookie&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;enum&lt;/span&gt; &lt;span class="kt"&gt;FryOrderSize&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="n"&gt;large&lt;/span&gt;
  &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="n"&gt;small&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;menuItem&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;FastFoodMenuItem&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;FastFoodMenuItem&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;hamburger&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;patties&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Enums can contain extra data that's just for specific item like fries can be small or large.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Optional
&lt;/h3&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;enum&lt;/span&gt; &lt;span class="kt"&gt;Optional&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="k"&gt;none&lt;/span&gt;
  &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="nf"&gt;some&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;T&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;An optional is an enum.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;hello&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt;              &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;hello&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Optional&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="k"&gt;none&lt;/span&gt;
&lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;hello&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"hello"&lt;/span&gt;    &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;hello&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Optional&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;some&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"hello"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;hello&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;nil&lt;/span&gt;        &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;hello&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Optional&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="k"&gt;none&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;It's possible to get the value from optional two ways&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="n"&gt;hello&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt; &lt;span class="c1"&gt;// this crashes the program in case the value is none&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;safehello&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;hello&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;safehello&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// do something else&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Default&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="n"&gt;hello&lt;/span&gt; &lt;span class="p"&gt;??&lt;/span&gt; &lt;span class="s"&gt;"This is default value"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;comma in &lt;code&gt;if&lt;/code&gt; statement is like sequential &lt;code&gt;&amp;amp;&amp;amp;&lt;/code&gt; operator meaning that the value that is assigned in first condition can be used in the second condition.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;indexOfTheOneAndOnlyFaceUpCard&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;get&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;faceUpCardIndices&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;]()&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;index&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;cards&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;indices&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;cards&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;isFaceUp&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;faceUpCardIndices&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;faceUpCardIndices&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;count&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;faceUpCardIndices&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;first&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;nill&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;set&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;index&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;cards&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;indices&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;index&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;newValue&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;cards&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;isFaceUp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;cards&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;isFaceUp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;When setting new value it turns all the other cards face down&lt;/li&gt;
&lt;li&gt;when getting value it is going to check if there is two face up cards&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://twitter.com/reallankinen"&gt;@RealLankinen&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://dev.to/lankinen/cs193p-notes-lecture-1-course-logistics-and-introduction-to-swiftui-44ap"&gt;Notes 1&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/lankinen/cs193p-notes-lecture-2-mvvm-and-the-swift-type-system-406f"&gt;Notes 2&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/lankinen/cs193p-notes-lecture-3-reactive-ui-protocols-layout-5g8a"&gt;Notes 3&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/lankinen/cs193p-notes-lecture-4-grid-enum-optionals-4noj"&gt;&lt;strong&gt;Notes 4&lt;/strong&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/lankinen/cs193p-notes-lecture-5-viewbuilder-shape-viewmodifier-fgh"&gt;Notes 5&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/lankinen/cs193p-notes-lecture-6-animation-1a8f"&gt;Notes 6&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/lankinen/cs193p-notes-lecture-7-multithreading-emojiart-2ak3"&gt;Notes 7&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/lankinen/cs193p-notes-lecture-8-gestures-json-1f3m"&gt;Notes 8&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/lankinen/cs193p-notes-lecture-9-data-flow-26e"&gt;Notes 9&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/lankinen/cs193p-notes-lecture-10-navigation-textfield-3ei9"&gt;Notes 10&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/lankinen/cs193p-notes-lecture-11-picker-2hgh"&gt;Notes 11&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/lankinen/cs193p-notes-lecture-12-core-data-eci"&gt;Notes 12&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/lankinen/cs193p-notes-lecture-13-persistence-2jeh"&gt;Notes 13&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/lankinen/cs193p-notes-lecture-14-uikit-integration-1p7m"&gt;Notes 14&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://www.notion.so/lankinen/CS193p-2020-iOS-development-course-from-Stanford-81c094238e9d471bbf059ea8d83b3e15"&gt;Originally published here&lt;/a&gt;&lt;/p&gt;

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