<?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: Monty Harper</title>
    <description>The latest articles on DEV Community by Monty Harper (@montyharper).</description>
    <link>https://dev.to/montyharper</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%2F1084170%2Fe088d72c-e15d-4014-b0c3-0703ae8cb49a.jpeg</url>
      <title>DEV Community: Monty Harper</title>
      <link>https://dev.to/montyharper</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/montyharper"/>
    <language>en</language>
    <item>
      <title>Notes on Notes</title>
      <dc:creator>Monty Harper</dc:creator>
      <pubDate>Mon, 29 Jul 2024 20:23:17 +0000</pubDate>
      <link>https://dev.to/montyharper/notes-on-notes-1hh5</link>
      <guid>https://dev.to/montyharper/notes-on-notes-1hh5</guid>
      <description>&lt;p&gt;July 29, 2024 at 8:29 AM&lt;/p&gt;

&lt;p&gt;Do you take notes while you’re working on a personal coding project? I do, and I find it very useful for moving the project along and for consolidating my learning as I go.&lt;/p&gt;

&lt;h2&gt;
  
  
  iWeek App
&lt;/h2&gt;

&lt;p&gt;I recently “finished” coding a project I call &lt;em&gt;iWeek&lt;/em&gt;, meaning I completed a MVP version that works! &lt;em&gt;iWeek&lt;/em&gt; is a to-do list app tailored for my own work situation. The app is designed to help schedule and track time spent on various projects throughout the week so nothing gets overlooked.&lt;/p&gt;

&lt;p&gt;I spent about six months working on the app off and on, and I learned a ton in the process. My notes will help me leverage that experience into actual lessons learned, so my next app should go a lot quicker.&lt;/p&gt;

&lt;p&gt;In all I wrote about 12,000 words worth of &lt;em&gt;iWeek&lt;/em&gt; notes. That’s a third the length of a short novel! Over the past couple of days I’ve read through and tagged many interesting items. What this means for you is…&lt;/p&gt;

&lt;p&gt;I identified about ten topics I could write about surrounding the making of &lt;em&gt;iWeek&lt;/em&gt;, in addition to the two I’ve already posted (&lt;a href="https://dev.to/montyharper/making-a-new-item-in-swiftdata-go-directly-to-edit-view-or-how-to-get-things-exactly-backwards-kbl"&gt;How to Get Things Exactly Backwards&lt;/a&gt;, and &lt;a href="https://dev.to/montyharper/clear-vision-not-so-clear-or-the-user-is-me-27dd"&gt;Clear Vision Not So Clear&lt;/a&gt;). So I’m launching a series of short articles about things I learned writing &lt;em&gt;iWeek&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;I’m starting off a bit meta in this article, with notes about taking notes…&lt;/p&gt;

&lt;h2&gt;
  
  
  My Platform
&lt;/h2&gt;

&lt;p&gt;I keep notes on all my iOS projects in &lt;a href="https://www.literatureandlatte.com/scrivener/overview" rel="noopener noreferrer"&gt;Scrivener&lt;/a&gt;, a desktop app designed to help authors keep their ideas and writing well organized. I’ve used Scrivener to write a few novels (I write fantasy and sci fi for middle-grade readers) and I love it so much, I now use it for everything. &lt;/p&gt;

&lt;p&gt;My “iOS Development” Scrivener file includes a folder for &lt;a href="https://www.hackingwithswift.com/100/swiftui" rel="noopener noreferrer"&gt;100Days of SwiftUI&lt;/a&gt; with a page on each lesson, notes on each project I did for my Udacity nanodegree, notes on my resume and job search efforts, notes and drafts for every article I’ve posted here on Dev, and notes on each of my original iOS app projects.&lt;/p&gt;

&lt;p&gt;Of course, Scrivener isn’t the only piece of writing software good for this purpose, but I do recommend keeping your notes in one place, apart from your code. Some of my earlier code includes comments that really belong in a notes file. Code comments should be brief and relevant to a given line of code. The information I log in my notes file goes well beyond that. &lt;/p&gt;

&lt;h2&gt;
  
  
  Contents
&lt;/h2&gt;

&lt;p&gt;The notes I kept for &lt;em&gt;iWeek&lt;/em&gt; are all about communicating with my future self. Here are the sorts of things I wrote down:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Descriptions of being stuck&lt;/strong&gt;. In my &lt;a href="https://dev.to/montyharper/10-ideas-for-getting-un-stuck-2m8e"&gt;previous article&lt;/a&gt; I listed this as one way to get unstuck. Writing about your dilemma in detail can help you define the problem and identify possible solutions.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Good advice&lt;/strong&gt;. When I sought outside help from a friend or peer group, I wrote down their suggestions.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Brainstorming&lt;/strong&gt;. Often I listed several approaches that might solve a problem. As I tried each one I checked them off the list along with a note about how well it did or didn’t work. &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Solutions to problems&lt;/strong&gt;. This will help me navigate a similar situation more quickly in the future. Even if I never look it up again, the act of writing a solution down helps it stick in your memory. &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Checklists or todo lists&lt;/strong&gt;. This came in handy for things like coding all the buttons needed in a particular view.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Epiphanies&lt;/strong&gt;. I found a few of these as I read back through, marked with asterisks and/or exclamation points! These lessons learned will form the basis for some of the future articles in this series.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;References&lt;/strong&gt;. Links to particular topics, examples, or important bits of code often saved me from having to search for the same thing again.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Habits
&lt;/h2&gt;

&lt;p&gt;The notes you take are only useful if you use them. (Brilliant statement, don’t you think?) The following habits insured my notes were actually helping me with the project:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Date and time headings&lt;/strong&gt;. In Scrivener, Shift-Option-Command-D will plop the current date and time into your document. I started each entry this way, adding it to the bottom of the document. These headings make it easy to see where each new entry starts, and they help a lot when scanning for recent information.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Review&lt;/strong&gt;. Each time I sat down to work on the project, before diving into the code, I read the previous few entries in my notes to re-orient myself and set a goal for the current session.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Summarize&lt;/strong&gt;. At the end of each work session I left myself notes on what I accomplished and what should come next. When I was stuck, I described the situation and wrote down any possible solutions that came to mind. This kept me from having to start the next session with no idea where to start.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Use specific keywords&lt;/strong&gt;. Often I used Scrivener’s find function to review the history of a given class or function or UI element in my app. This works much better when the text references the actual names of the classes, functions, and elements used in the code. &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Keep a sense of humor&lt;/strong&gt;. Nobody else is reading my notes except for me. But I still gave them some personality and humor. That helps smooth over the rough patches. Here are some examples from my notes of language I would only use when writing for myself:&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;"It’s a thing of beauty. However, there are some bugs in there still, so I’m about to go bug hunting."&lt;/p&gt;

&lt;p&gt;"Now it seems to work. There is a ghost in the machine."&lt;/p&gt;

&lt;p&gt;"It’s a mess, man. It’s a real mess."&lt;/p&gt;

&lt;p&gt;"Okay, making some kind of slow-ass progress… "&lt;/p&gt;
&lt;/blockquote&gt;

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

&lt;p&gt;That’s about it. Do you keep project notes, too? How do they help you? Have I left anything out? Please post a comment!&lt;/p&gt;

</description>
      <category>mobile</category>
      <category>learning</category>
      <category>coding</category>
      <category>howto</category>
    </item>
    <item>
      <title>10 Ideas For Getting Un-Stuck</title>
      <dc:creator>Monty Harper</dc:creator>
      <pubDate>Fri, 31 May 2024 16:40:43 +0000</pubDate>
      <link>https://dev.to/montyharper/10-ideas-for-getting-un-stuck-2m8e</link>
      <guid>https://dev.to/montyharper/10-ideas-for-getting-un-stuck-2m8e</guid>
      <description>&lt;h2&gt;
  
  
  I'm Well and Truly Stuck!
&lt;/h2&gt;

&lt;p&gt;I'm trying to embrace the "learning in public" ideal here on Dev, but I find it flies against my instincts. I tend to want to understand something really well first, then write about my learning process with some confidence. I want to present the story that I figured something out, and here's how I thought through it, and here's the correct conclusion I came to. You'll see that narrative in some of my previous articles.&lt;/p&gt;

&lt;p&gt;Today I'm pushing myself to post what I'm doing right now. Which means I have to tell an incomplete story. I feel a bit vulnerable talking about how stuck I am, but hopefully this will be helpful to you as well as to myself.&lt;/p&gt;

&lt;h2&gt;
  
  
  Stick with me...
&lt;/h2&gt;

&lt;p&gt;In a moment I will type up a list of things to do when you're stuck. I'm reminding myself right now that I am capable of making a useful such list based on my life's experience as a songwriter, performer, teacher, and programming enthusiast - a list that will be helpful to all. &lt;/p&gt;

&lt;p&gt;But first I want to actually do something I know I'll put on the list, which is to write about the problem. I'm doing this partly just to vent, partly to give you some context for why I'm writing this article, and mostly to try and help get myself unstuck.&lt;/p&gt;

&lt;h2&gt;
  
  
  An Intractable Problem
&lt;/h2&gt;

&lt;p&gt;I'm working on a challenge app in the &lt;a href="https://www.hackingwithswift.com/100/swiftui" rel="noopener noreferrer"&gt;100DaysOfSwiftUI&lt;/a&gt; program by Paul Hudson, highly recommended for anyone interested in learning Swift.&lt;/p&gt;

&lt;p&gt;In the app, the user can select a photo from the &lt;code&gt;PhotosPicker&lt;/code&gt;, and a pointer to the data is stored as a &lt;code&gt;PhotosPickerItem&lt;/code&gt;. Then an &lt;code&gt;.onChange(of: selectedItem)&lt;/code&gt; triggers a sheet to open that displays the selected photo and asks the user to give it a title and description.&lt;/p&gt;

&lt;p&gt;Mostly this works great, but when I run the app in the simulator, there's one photo that refuses to load in when you select it. The sheet opens with the message "no photo to display," which I have programmed it to do when the value of the selected photo is &lt;code&gt;nil&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;However - and here's the baffling bit - the selected photo should never be &lt;code&gt;nil&lt;/code&gt; if the sheet is open because the property that triggers the sheet to open, &lt;code&gt;isDisplayingNewPhoto&lt;/code&gt;, is a &lt;code&gt;Bool&lt;/code&gt;, set to &lt;code&gt;(newPhoto != nil)&lt;/code&gt;. To state this again in plain language: The sheet can only open if the photo is not empty, yet the sheet is displaying the empty case for the photo.&lt;/p&gt;

&lt;p&gt;I'm leaving out a bit of detail, which involves loading the data for the photo. The &lt;code&gt;PhotosPickerItem&lt;/code&gt; is just a pointer to some data, which has to be loaded into an &lt;code&gt;Image&lt;/code&gt; property before it can be displayed as a photo. &lt;/p&gt;

&lt;p&gt;I suspect the problem is with timing; the particular image I'm struggling with is larger than the ones that work fine. Maybe by the time the sheet opens, the image hasn't loaded in yet. But then why is the sheet triggered to open at all? And also I'm using the async/await pattern that supposedly handles the time-consuming process of loading data so it will be present when needed.&lt;/p&gt;

&lt;p&gt;I've tried every variation I can think of, switching the order of things around, and while different approaches all work generally, they also all fail in the same way with this one photo.&lt;/p&gt;

&lt;p&gt;Now is a good time to share this meme, thanks to &lt;a class="mentioned-user" href="https://dev.to/avanichols"&gt;@avanichols&lt;/a&gt;, who posted it for this week's &lt;a href="https://dev.to/ben/meme-monday-4l95"&gt;Meme Monday&lt;/a&gt;. I may be sitting near the top of this bell curve. I'm not ready to say I've uncovered a bug, because I'm probably doing something wrong, but maybe?? &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flcyjtau6wpcutd63afuu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flcyjtau6wpcutd63afuu.png" alt="Meme showing a novice, intermediate, and expert programmer. The novice sits at the bottom left of a bell curve representing experience. The intermediate sits at the top and the expert sits at the bottom right. The novice says, " width="500" height="500"&gt;&lt;/a&gt; &lt;/p&gt;

&lt;h2&gt;
  
  
  What To Do When You're Well and Truly Stuck!!
&lt;/h2&gt;

&lt;p&gt;Okay, here's the list I promised you...&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Write about the problem.
&lt;/h3&gt;

&lt;p&gt;Explaining it carefully to yourself on paper can be clarifying.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Phone a friend.
&lt;/h3&gt;

&lt;p&gt;Maybe you're too used to looking at your own code to see the problem. Get a fresh pair of eyes on it. Your friend may see some obvious thing you're missing or some assumption you've made that you aren't aware of.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Ask AI.
&lt;/h3&gt;

&lt;p&gt;Sometimes Chat GPT can suggest a solution you haven't tried yet. Try asking your question in multiple different ways, from general to specific, with and without context. Try asking it to do different associated tasks: you can ask it to write code, review your code, or brainstorm different ways to solve a given problem. (Always keep in mind the fact that Chat GPT's personality doesn't allow it to just say "I don't know," which sometimes leads to unhelpful responses.)&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Read the documentation.
&lt;/h3&gt;

&lt;p&gt;Look up every relevant bit of code to make sure you know how it's supposed to work and what your options are. As shocking as this may sound, sometimes the official documentation is helpful.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Post to an online discussion.
&lt;/h3&gt;

&lt;p&gt;Maybe others have dealt with the same problem. It's helpful to isolate the issue first, and post some code just illustrating the problem, rather than posting your entire app. The process of isolating the problem may even shake loose a solution on its own! I'll make that a separate bullet point...&lt;/p&gt;

&lt;h3&gt;
  
  
  6. Try to isolate the problem with fresh code.
&lt;/h3&gt;

&lt;p&gt;Starting from scratch, write the simplest app you can to re-create the problem, and see if you can solve it in that simplified context.&lt;/p&gt;

&lt;h3&gt;
  
  
  7. Take a different approach.
&lt;/h3&gt;

&lt;p&gt;Maybe the code isn't designed to do what you're trying to do. There may be forty ways to code a solution, but there are also forty solutions to the bigger problem. What if you go back to the ultimate goal of your app and take a completely different approach to accomplishing it? A little brainstorming can get you going in a whole new direction.&lt;/p&gt;

&lt;h3&gt;
  
  
  8. Work on different code.
&lt;/h3&gt;

&lt;p&gt;This is one I need to listen to myself. Maybe the problem is unsolvable. Maybe the solution is obvious and you're just not seeing it. Either way, after you've spent a reasonable amount of time on it, move on to something else for a while. Start the next lesson. Taking in new, seemingly unrelated information can sometimes lead to a solution.&lt;/p&gt;

&lt;h3&gt;
  
  
  9. &lt;em&gt;Do&lt;/em&gt; something else entirely.
&lt;/h3&gt;

&lt;p&gt;Like take a walk, take a shower, do the dishes. Any task that involves your body but not your mind can loosen up those thoughts and help a solution pop into your head. Try not to think about it directly. Just let your brain crank away in the background.&lt;/p&gt;

&lt;h3&gt;
  
  
  10. Don't be too picky.
&lt;/h3&gt;

&lt;p&gt;I always like to think I should be able to make the code do exactly what I want. But maybe I just don't have the required skills yet, or maybe I'm asking the impossible. In my particular case (as described above), if I try to load the same image a second time, it works. To me, this isn't a very satisfying solution, asking the user to do a thing twice before it works. But I need to keep in mind the bigger picture - I'm coding this app to learn, and while I'm well and truly stuck, I'm not learning. So sometimes maybe good enough is good enough for now.&lt;/p&gt;

&lt;h3&gt;
  
  
  Bonus. Have faith and patience.
&lt;/h3&gt;

&lt;p&gt;Millions before you have learned to code. Millions before you have written apps that do something similar to what you're trying to do. You're as smart as they are. You'll figure it out, too.&lt;/p&gt;

&lt;h2&gt;
  
  
  Out of ideas
&lt;/h2&gt;

&lt;p&gt;I managed to come up with a few items I haven't tried yet, so hopefully my list will help. I hope it helps you as well!&lt;/p&gt;

&lt;p&gt;What have I left off? What do &lt;em&gt;you&lt;/em&gt; do when &lt;em&gt;you're&lt;/em&gt; stuck? Please add your thoughts in the comments!!&lt;/p&gt;

</description>
      <category>beginners</category>
      <category>programming</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Making a New Item in SwiftData go Directly to Edit View, or "How to Get Things Exactly Backwards"</title>
      <dc:creator>Monty Harper</dc:creator>
      <pubDate>Thu, 23 May 2024 03:45:13 +0000</pubDate>
      <link>https://dev.to/montyharper/making-a-new-item-in-swiftdata-go-directly-to-edit-view-or-how-to-get-things-exactly-backwards-kbl</link>
      <guid>https://dev.to/montyharper/making-a-new-item-in-swiftdata-go-directly-to-edit-view-or-how-to-get-things-exactly-backwards-kbl</guid>
      <description>&lt;p&gt;Please note that while I do use some Swift vocabulary in this article, and while it may be helpful to someone trying to do a specific thing in Swift, it's not really a tutorial. This is more of a story about how to troubleshoot and how to learn. &lt;/p&gt;

&lt;p&gt;I've been working on my own weird version of a to-do list app using SwiftData, and I recently found myself losing my mind over what should have been a simple bit of functionality. &lt;/p&gt;

&lt;h2&gt;
  
  
  The Challenge
&lt;/h2&gt;

&lt;p&gt;The problem was, I wanted to make a new &lt;code&gt;Item&lt;/code&gt; and open it in the edit view all with one tap. (Yes, I literally named my model "Item." At least I didn't call it "Thing.")&lt;/p&gt;

&lt;p&gt;I wanted to avoid doing this the way we did it in &lt;a href="https://www.hackingwithswift.com/100/swiftui" rel="noopener noreferrer"&gt;100DaysOfSwiftUI&lt;/a&gt; (highly recommended tutorials!):&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Make a "new item" button that creates a new item and inserts it into the model context.&lt;/li&gt;
&lt;li&gt;Use a navigation link for each item on the list to open that item in the edit view.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This requires the user to create a new item, then tap the new item to edit it. Why make my user (me) tap twice when once should be enough? If you make a new item, of course you don't want it sitting there in your list saying "look at me, I'm nothing, I'm just a new item." You're going to want to edit it right away. It can't be that difficult to make a "new item" button that creates a new item AND opens it for you in the edit view. Right? Right??  &lt;/p&gt;

&lt;h2&gt;
  
  
  First Attempt
&lt;/h2&gt;

&lt;p&gt;My foolproof plan was simple: 1) Create a new &lt;code&gt;Item&lt;/code&gt;, 2) Send it into the edit view. &lt;/p&gt;

&lt;p&gt;I did the obvious thing: I initialized a new &lt;code&gt;Item&lt;/code&gt; inside my &lt;code&gt;NavigationLink&lt;/code&gt;, which passed it to the edit view.&lt;/p&gt;

&lt;p&gt;This appeared to work; the code compiled and didn't crash. But testing revealed some odd behavior: edits to my new items were not taking effect.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Problem?
&lt;/h2&gt;

&lt;p&gt;I have a theory: My new &lt;code&gt;Item&lt;/code&gt; had not been inserted into the &lt;code&gt;modelContext&lt;/code&gt; where SwiftData could deal with it properly. Somewhere between making a new &lt;code&gt;Item&lt;/code&gt; and landing it in the edit view, I needed to inject it into SwiftData's &lt;code&gt;modelContext&lt;/code&gt;. Then the edit view would be able to handle it properly.&lt;/p&gt;

&lt;p&gt;Unfortunately, while you can use &lt;code&gt;NavigationLink&lt;/code&gt; to initialize a new &lt;code&gt;Item&lt;/code&gt;, it doesn't support &lt;em&gt;doing&lt;/em&gt; anything with said new &lt;code&gt;Item&lt;/code&gt; (such as injecting it into the &lt;code&gt;modelContext&lt;/code&gt;) before passing it along. (Maybe you can see the solution here - I'll get to it later in the article.)&lt;/p&gt;

&lt;p&gt;After struggling with that for a while, I tried injecting the new &lt;code&gt;Item&lt;/code&gt; from inside the edit view itself, using an .onAppear closure. This also appeared to work, however I got the same weird behavior as before. I'm guessing that's because the .onAppear happens after the view is initialized, so I was injecting the new &lt;code&gt;Item&lt;/code&gt; too late in the process? I don't know for sure.&lt;/p&gt;

&lt;p&gt;All I know is SwiftUI and SwiftData were conspiring to keep my new &lt;code&gt;Item&lt;/code&gt; out of the edit view without user intervention. Stubbornly, I still believed there had to be a way edit a new &lt;code&gt;Item&lt;/code&gt; directly! I turned to Google for answers.&lt;/p&gt;

&lt;p&gt;Lo and behold, the Apple Documentation for SwiftData (of all places!) includes &lt;a href="https://developer.apple.com/documentation/swiftdata/adding-and-editing-persistent-data-in-your-app" rel="noopener noreferrer"&gt;an example showing how to do exactly what I'd been trying to do&lt;/a&gt;. Why didn't I start there? &lt;em&gt;Huh? &lt;strong&gt;Why&lt;/strong&gt;?&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The Solution
&lt;/h2&gt;

&lt;p&gt;I'm giving you the long version here, since Apple's approach also solves the problem of what to do if the user wants to discard changes made in the edit view. If you'd rather look at the short version, skip to the next heading.&lt;/p&gt;

&lt;p&gt;Here's the way I tried to do it (which wasn't working):&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Navigate to an edit view, passing in a new item or an existing one as a &lt;code&gt;@Binding var&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;In an &lt;code&gt;.onAppear&lt;/code&gt; closure, make a backup copy of the &lt;code&gt;Item&lt;/code&gt;, and inject the &lt;code&gt;Item&lt;/code&gt; into the &lt;code&gt;modelContext&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;The user edits the &lt;code&gt;Item&lt;/code&gt; directly.&lt;/li&gt;
&lt;li&gt;Do nothing if the user taps "Save."&lt;/li&gt;
&lt;li&gt;Restore the &lt;code&gt;Item&lt;/code&gt; from its backup if the user taps “Never Mind.”&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Here's what Apple says to do:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;In the edit view, set up your item &lt;code&gt;var&lt;/code&gt; without a binding and make it optional - which means it's allowed to be empty.&lt;/li&gt;
&lt;li&gt;Navigate to the edit view by passing in an existing &lt;code&gt;Item&lt;/code&gt;, or pass in &lt;code&gt;nil&lt;/code&gt; (nothing) if you want to make a new &lt;code&gt;Item&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;The edit view should have an &lt;code&gt;@State var&lt;/code&gt; for each editable property of your &lt;code&gt;Item&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Provide your &lt;code&gt;@State var&lt;/code&gt;s with default values for a new &lt;code&gt;Item&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;If your &lt;code&gt;Item&lt;/code&gt; exists, copy its property values to the &lt;code&gt;@State var&lt;/code&gt;s in an &lt;code&gt;.onAppear&lt;/code&gt; closure. &lt;/li&gt;
&lt;li&gt;The user edits the &lt;code&gt;@State var&lt;/code&gt;s rather than directly editing the &lt;code&gt;Item&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;If the user clicks "Save", copy the &lt;code&gt;@State var&lt;/code&gt;s into the &lt;code&gt;Item&lt;/code&gt;’s properties. &lt;/li&gt;
&lt;li&gt;Or, if no &lt;code&gt;Item&lt;/code&gt; exists, create a new &lt;code&gt;Item&lt;/code&gt; using the &lt;code&gt;@State var&lt;/code&gt;s and insert the new &lt;code&gt;Item&lt;/code&gt; into the &lt;code&gt;modelContext&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;If the user clicks “Never Mind”, do nothing.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  The Short Version
&lt;/h2&gt;

&lt;p&gt;My approach:&lt;br&gt;
1) Create a new &lt;code&gt;Item&lt;/code&gt;, 2) Send it into the edit view.&lt;/p&gt;

&lt;p&gt;Apple's approach:&lt;br&gt;
1) Open the edit view with no &lt;code&gt;Item&lt;/code&gt;, 2) Create a new &lt;code&gt;Item&lt;/code&gt; after the user has entered some values.&lt;/p&gt;

&lt;p&gt;I had it exactly backwards. &lt;/p&gt;

&lt;p&gt;For a while, I thought I was missing something here. But after learning a few more things (see below), if I had to try and explain why Apple does this backwards, I believe it has more to do with the ability to undo your changes. In that aspect, Apple's approach is more elegant:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;You don't have to create a backup copy of the &lt;code&gt;Item.&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;You aren't making changes to the &lt;code&gt;Item&lt;/code&gt; as you edit; all changes are written when you close the edit view. (Doing it my way, changes take effect as you make them; if that process were to be interrupted by say a dead battery, you'd lose your ability to undo your changes.)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;(Also, using a binding as I did shouldn't be necessary since any &lt;code&gt;Item&lt;/code&gt; in the &lt;code&gt;modelContext&lt;/code&gt; will be automatically updated when changes are made.) &lt;/p&gt;

&lt;p&gt;However, I don't believe this backwards approach is essential to getting your new &lt;code&gt;Item&lt;/code&gt; into the &lt;code&gt;ModelContext&lt;/code&gt; for editing. Here's why...&lt;/p&gt;

&lt;h2&gt;
  
  
  An Alternate Approach
&lt;/h2&gt;

&lt;p&gt;A bit later, I stumbled upon another way to do this, and I wish I'd taken better notes so I could credit whatever kind soul put this out there, but at the time I didn't realize the significance of what I was looking at. I was trying to answer a different question about SwiftData, and in the example code a sample item was provided to the edit view via a computed variable.&lt;/p&gt;

&lt;p&gt;This was a head-slapping moment for me because it's quite obvious, once you think of it. &lt;/p&gt;

&lt;p&gt;Remember how I lamented that the &lt;code&gt;NavigationLink&lt;/code&gt; will allow you to initialize a new &lt;code&gt;Item&lt;/code&gt; but then you can't do anything with it other than pass it along?&lt;/p&gt;

&lt;p&gt;Well you &lt;em&gt;can&lt;/em&gt; do things with a new &lt;code&gt;Item&lt;/code&gt; outside the &lt;code&gt;NavigationLink&lt;/code&gt;, then pass it into the link; you just have to be a bit clever about it.&lt;/p&gt;

&lt;p&gt;Here's roughly what that looks like:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Make a computed variable (or a function, if you like) called "newItem" which creates a new item with default values and injects it into the &lt;code&gt;ModelContext&lt;/code&gt;, then returns the new item.&lt;/li&gt;
&lt;li&gt;Inside the &lt;code&gt;NavigationLink&lt;/code&gt; call for a &lt;code&gt;newItem&lt;/code&gt; and pass it into the edit view.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;There you go - the new item gets inserted into the context before it gets passed to the edit view, and you can edit it directly if you want.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Did I Learn?
&lt;/h2&gt;

&lt;p&gt;Besides the nuts and bolts of how to open a new item in the edit view with a single tap, there may be a few lessons lying around here, if I can get past my stubbornness and actually learn them!&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;When the system seems to be telling you you can't do a thing that ought to be doable, it's time to seek outside help.&lt;/li&gt;
&lt;li&gt;The Apple documentation does include tutorials on how to do basic stuff.&lt;/li&gt;
&lt;li&gt;Learning something (in this case SwiftData) from a single source doesn't mean you've learned it thoroughly. Check out different sources on the same topic to get a fuller picture.&lt;/li&gt;
&lt;li&gt;When working with a new framework (SwiftData) things can fail silently and error messages can be unhelpful, but (again) the documentation can be a help.&lt;/li&gt;
&lt;li&gt;If the "obvious" way to do a thing fails, there's probably a "just as obvious" way to do it correctly. &lt;/li&gt;
&lt;li&gt;Find a good balance between learning and creating; moving on through the 100Days has given me tools I wish I'd had while I was struggling with this app of mine. On the other hand, struggling to create something usable keeps me engaged and motivated.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;What's your ideal balance between learning from tutorials vs. making your own projects? Leave a comment if you like.&lt;/p&gt;

&lt;p&gt;Happy learning! &lt;/p&gt;

</description>
      <category>swift</category>
      <category>programming</category>
      <category>learning</category>
      <category>development</category>
    </item>
    <item>
      <title>A Song For StarWars Day</title>
      <dc:creator>Monty Harper</dc:creator>
      <pubDate>Sat, 04 May 2024 19:59:30 +0000</pubDate>
      <link>https://dev.to/montyharper/a-song-for-starwars-day-jdp</link>
      <guid>https://dev.to/montyharper/a-song-for-starwars-day-jdp</guid>
      <description>&lt;p&gt;To celebrate StarWars day, I thought I'd share this song I wrote about my favorite little green StarWars dude. Enjoy!&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://montyharper.com/track/2714275/grogu" rel="noopener noreferrer"&gt;Grogu Song&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://i.giphy.com/media/v1.Y2lkPTc5MGI3NjExNmRyeDZyN3EyZnc2ZDdlcGhhcTlsajByaWo4Mnlka3h3cGgxdTRxdCZlcD12MV9pbnRlcm5hbF9naWZfYnlfaWQmY3Q9Zw/s3SYj6zfj3QldFkici/giphy.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://i.giphy.com/media/v1.Y2lkPTc5MGI3NjExNmRyeDZyN3EyZnc2ZDdlcGhhcTlsajByaWo4Mnlka3h3cGgxdTRxdCZlcD12MV9pbnRlcm5hbF9naWZfYnlfaWQmY3Q9Zw/s3SYj6zfj3QldFkici/giphy.gif" width="480" height="270"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>music</category>
      <category>starwars</category>
      <category>maythefourthbewithyou</category>
      <category>maythe4th</category>
    </item>
    <item>
      <title>What Good Is a Mobile App?</title>
      <dc:creator>Monty Harper</dc:creator>
      <pubDate>Fri, 19 Apr 2024 20:16:00 +0000</pubDate>
      <link>https://dev.to/montyharper/what-good-is-a-mobile-app-44o</link>
      <guid>https://dev.to/montyharper/what-good-is-a-mobile-app-44o</guid>
      <description>&lt;p&gt;Serious question...&lt;/p&gt;

&lt;p&gt;What tasks are mobile apps uniquely good at accomplishing? Why would an organization turn to building a mobile app rather than using a desktop application, email, or web-based application? What can a mobile app do well that nothing else can? &lt;/p&gt;

&lt;p&gt;This is an important question for anyone trying to sell a potential client on the need for a mobile app, or for anyone who wants to design an app people will download - an in-demand app should include features people can't get elsewhere. &lt;/p&gt;

&lt;p&gt;So what needs can only be satisfied with the creation of a mobile app?&lt;/p&gt;

&lt;p&gt;Please post your thoughts! Thanks!&lt;/p&gt;

</description>
      <category>development</category>
      <category>ios</category>
      <category>android</category>
      <category>discuss</category>
    </item>
    <item>
      <title>Clear Vision, Not So Clear (or.. The User Is Me)</title>
      <dc:creator>Monty Harper</dc:creator>
      <pubDate>Wed, 27 Mar 2024 15:15:57 +0000</pubDate>
      <link>https://dev.to/montyharper/clear-vision-not-so-clear-or-the-user-is-me-27dd</link>
      <guid>https://dev.to/montyharper/clear-vision-not-so-clear-or-the-user-is-me-27dd</guid>
      <description>&lt;h2&gt;
  
  
  Weekly Updates?
&lt;/h2&gt;

&lt;p&gt;I began on DEV with the intention to "learn in public," but I tend to want to put everything about something into one article, and I get a bit bogged down. So I'm challenging myself to set a timer and put out something short but meaningful once per week. In that spirit...&lt;/p&gt;

&lt;h2&gt;
  
  
  My Current Project
&lt;/h2&gt;

&lt;p&gt;I've been learning SwiftData lately in Paul Hudson's &lt;a href="https://www.hackingwithswift.com/100/swiftui" rel="noopener noreferrer"&gt;100DaysOfSwiftUI&lt;/a&gt;. SwiftData is the new version of Apple's CoreData API for persisting data in a database-like structure. Compared with CoreData, SwiftData seems like a walk in the park; many functions that previously took a bunch of opaque, wacky code now only take a single line of opaque, wacky code! &lt;/p&gt;

&lt;p&gt;Anyhow, this seemed the right time to tackle an app from my wishlist which requires database capabilities. My new project is called "iWeek" for now, and it's my version of a fancy to-do list. Everybody's got one of those, right?&lt;/p&gt;

&lt;h2&gt;
  
  
  How It Started
&lt;/h2&gt;

&lt;p&gt;This will be my dream app for organizing my week in a simple way that makes sense to how I work. So I had a very clear vision for it. I knew what I wanted it to look like and how it should function. I made some quick sketches on paper and dove into the code feeling confident I could knock this thing out in a day or two.&lt;/p&gt;

&lt;h2&gt;
  
  
  How It's Going
&lt;/h2&gt;

&lt;p&gt;First I had to deal with some scary purple triangles - those are xCode's warnings that something you've done is very wrong - with unhelpful error descriptions that kept me running in circles for a couple of days.&lt;/p&gt;

&lt;p&gt;Once I figured that out (my errors were actually fairly trivial; the messages just had me looking in the wrong places!), I spent a couple of days creating a list view and an edit view. Some of the app's core behaviors are now working wonderfully. &lt;/p&gt;

&lt;p&gt;However, this morning I started thinking about how to complete the functionality required for my MVP (Minimum Viable Product). And... I'm feeling a bit bogged down. &lt;/p&gt;

&lt;p&gt;When the user adds or edits an item, are they adding or editing the item or the item type? Should it change that item for the current day, or for every future Wednesday? How can they easily update time spent on the item? How can I allow the user access to the various types of changes they might want to make? When you touch an item on the screen, what will be the response? If there are three different things the user might want to do, how can I make those accessible in an intuitive way? &lt;/p&gt;

&lt;p&gt;As you can see, what started as a clear vision has become bogged down in details.&lt;/p&gt;

&lt;h2&gt;
  
  
  Clear Vision, Not So Clear!
&lt;/h2&gt;

&lt;p&gt;I'm sure I'm not the first person to ever fool themselves into thinking they knew what they were trying to build. It's like waking from a vivid dream. I thought I had a solid sense of this app, but now all the details have muddled together into a pool of nonsense. &lt;/p&gt;

&lt;p&gt;If I poke it with a stick, my "clear vision" becomes: "Simple, intuitive to use, guides me through my day. Looks like a list of items for Monday, which I can swipe over to Tuesday, Wednesday, etc." &lt;/p&gt;

&lt;p&gt;I'd call that a clear-ish directive, but it's certainly not the fully-formed blueprint I thought I had in my head. &lt;/p&gt;

&lt;p&gt;I guess what I've discovered is: more thought is required.&lt;/p&gt;

&lt;h2&gt;
  
  
  The User Is Me!
&lt;/h2&gt;

&lt;p&gt;I haven't solved it all yet, but thinking about it this morning in the shower, I did gain one helpful insight: The User Is Me!&lt;/p&gt;

&lt;p&gt;I've been lost in a maze of "what if"s - what if the user wants to do this; what if the user wants to do that...&lt;/p&gt;

&lt;p&gt;Well, the user is me! So I don't really need to wonder. I know how I want this app to behave. I just need to actually imagine myself using it, in high-res detail, and many of my conundrums will clear themselves up. Right?&lt;/p&gt;

&lt;h2&gt;
  
  
  ..and Maybe You
&lt;/h2&gt;

&lt;p&gt;If I can make an app I love to use, I'm sure others will as well. So will keep my focus on what I want the app to do for me, and not worry about including every possible option on every screen. &lt;/p&gt;

&lt;p&gt;That's what I've been learning this week. I hope it's helpful to you. Please post a comment!&lt;/p&gt;

</description>
      <category>ios</category>
      <category>design</category>
      <category>database</category>
      <category>beginners</category>
    </item>
    <item>
      <title>SwiftUI - Row of Buttons Acting As One</title>
      <dc:creator>Monty Harper</dc:creator>
      <pubDate>Tue, 19 Mar 2024 01:40:05 +0000</pubDate>
      <link>https://dev.to/montyharper/swiftui-row-of-buttons-acting-as-one-43lk</link>
      <guid>https://dev.to/montyharper/swiftui-row-of-buttons-acting-as-one-43lk</guid>
      <description>&lt;h2&gt;
  
  
  What I thought was a bug, turned out to be a feature!
&lt;/h2&gt;

&lt;p&gt;Thanks to Paul Hudson at &lt;a href="https://www.hackingwithswift.com" rel="noopener noreferrer"&gt;Hacking With Swift&lt;/a&gt;, I recently learned that what I thought was a bug in SwiftUI is actually a feature. Paul says in one of his &lt;a href="https://www.hackingwithswift.com/100/swiftui" rel="noopener noreferrer"&gt;100 Days of SwiftUI&lt;/a&gt; videos - &lt;em&gt;which I highly highly recommend for anyone wanting to learn Swift and/or SwiftUI&lt;/em&gt; - even the most experienced iOS developers are often gobsmacked by this quirk of the code. I knew right away what he was talking about - I had encountered it myself, turned in a feedback report to Apple, and found a work-around. But according to Paul, it's not a bug, it's a feature! He encourages his viewers to spread the word, so that's what I'm doing.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cheeky Row of Buttons
&lt;/h2&gt;

&lt;p&gt;I encountered the problem, funnily enough, while working on the challenges to one of Paul's earlier 100 Days projects, an app that drills you on your multiplication facts. I was creating controls that would allow the user to choose which numbers to practice. I made a row of buttons, one for each number. To my enormous frustration, I could not select individual numbers. Selecting one number selected them all! &lt;/p&gt;

&lt;p&gt;With an appropriately placed print statement I confirmed that yes, what was happening was exactly what it looked like: pressing one button made every button in the row fire.&lt;/p&gt;

&lt;p&gt;I searched online for a solution and found nothing helpful. ChatGPT was at a loss. I even showed my code to the good folks at &lt;a href="https://www.meetup.com/a-flock-of-swifts/" rel="noopener noreferrer"&gt;A Flock of Swifts&lt;/a&gt;, and they all agreed that it must be a bug in SwiftUI. &lt;/p&gt;

&lt;h2&gt;
  
  
  My Work-Around
&lt;/h2&gt;

&lt;p&gt;With some sleuthing I figured out that the buttons only behaved badly when they were inside a &lt;code&gt;ForEach&lt;/code&gt; inside an &lt;code&gt;HStack&lt;/code&gt;, inside a &lt;code&gt;Form&lt;/code&gt;. I had designed custom buttons, so I thought it might have to do with the way I built them. I started messing with the pre-formatted button styles and discovered that if I added a &lt;code&gt;.buttonStyle(.plain)&lt;/code&gt; modifier, the problem went away; I could use my own styling and the buttons behaved independently, like good little buttons should.&lt;/p&gt;

&lt;p&gt;Here's the code, showing the problematic situation along with my solution:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Form {
   HStack {
      ForEach(0..&amp;lt;7) {number in                                     
         NumberButton(number)
            .buttonStyle(.plain)
      }                          
   }  
}                          
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  It's a Feature!?
&lt;/h2&gt;

&lt;p&gt;Imagine my surprise a few weeks later, when I was working through my 100Days lesson for the day, and Paul Hudson himself put a row of buttons into a form. My ears perked up when he said, "Please try it now - Very likely this will not work the way you hoped." Sure enough, all the buttons acted as one.&lt;/p&gt;

&lt;p&gt;This is because of the way Form is designed to behave. If you put a single button in a Form row, by default, you don't have to tap the button itself to activate it; you just need to tap anywhere in the row. That means every button responds when you tap anywhere in the row. To turn this "feature" off, you can modify your buttons with a &lt;code&gt;.plain&lt;/code&gt; button style.&lt;/p&gt;

&lt;p&gt;Well, now I know the logic behind my "workaround"! &lt;/p&gt;

&lt;h2&gt;
  
  
  I'd Love To See Your Comment
&lt;/h2&gt;

&lt;p&gt;I know I'm not the only one - have you encountered this? Did you report it to Apple like I did? Have you found any other weirdness in the iOS ecosystem? What's your favorite bug that turned out to be a feature? &lt;/p&gt;

&lt;h2&gt;
  
  
  Links
&lt;/h2&gt;

&lt;p&gt;If you're interested in exploring further...&lt;br&gt;
&lt;a href="https://github.com/MontyHarper/MultiplicationTables" rel="noopener noreferrer"&gt;Here's my Multiplication Tables app on GitHub&lt;/a&gt;.&lt;br&gt;
&lt;a href="https://github.com/MontyHarper/Bug-With-Form-HStack-ForEach" rel="noopener noreferrer"&gt;Here's an app I made to demonstrate the "problem."&lt;/a&gt;&lt;br&gt;
&lt;a href="https://www.hackingwithswift.com/books/ios-swiftui/adding-a-custom-star-rating-component" rel="noopener noreferrer"&gt;Here's Paul's video where he explains what's going on&lt;/a&gt;.&lt;br&gt;
Happy buttoning!&lt;/p&gt;

</description>
      <category>swift</category>
      <category>tutorial</category>
      <category>coding</category>
      <category>100daysofswiftui</category>
    </item>
    <item>
      <title>How to Refactor Spaghetti Code - One Bite at a Time!</title>
      <dc:creator>Monty Harper</dc:creator>
      <pubDate>Fri, 23 Feb 2024 18:09:55 +0000</pubDate>
      <link>https://dev.to/montyharper/how-to-refactor-spaghetti-code-one-bite-at-a-time-4b65</link>
      <guid>https://dev.to/montyharper/how-to-refactor-spaghetti-code-one-bite-at-a-time-4b65</guid>
      <description>&lt;p&gt;This week, I’ve been learning things the hard way!&lt;/p&gt;

&lt;p&gt;I’m refactoring my calendar app, partly because I’m applying for jobs now, and I want to present a well-constructed app in my portfolio, but also…&lt;/p&gt;

&lt;h2&gt;
  
  
  The Problem
&lt;/h2&gt;

&lt;p&gt;More importantly, I’ve hit the “spaghetti point” - that magical moment at which adding, testing, and debugging new features has become difficult because the base code is not so well-organized. And I do have a lot features I want to add or tweak, so I feel it’s worth the effort to do some re-organizing first.&lt;/p&gt;

&lt;p&gt;I’ve gotten feedback from a couple of fantastic mentors, one of whom I connected with here on Dev. &lt;a href="https://dev.to/lddmarc"&gt;Daria&lt;/a&gt; suggested I should break up my big classes into smaller objects, each of which would have a singular purpose. That’s just good &lt;a href="https://en.wikipedia.org/wiki/SOLID" rel="noopener noreferrer"&gt;SOLID&lt;/a&gt; practice! (I’ll write about SOLID principles another time.)&lt;/p&gt;

&lt;h2&gt;
  
  
  The Plan
&lt;/h2&gt;

&lt;p&gt;I knew I was stepping into a long dark tunnel by doing things this way, but… I decided to re-write one of my mega-classes FROM SCRATCH! &lt;/p&gt;

&lt;p&gt;Luckily, I had already learned one lesson the hard way: think about version control (Git) before launching into a big new refactor. So I…&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;…committed the project in Git, so I wouldn’t lose any recent changes.&lt;/li&gt;
&lt;li&gt;…started a new branch on which to mess things up, leaving a working version of the app as a back-up on my main branch.&lt;/li&gt;
&lt;li&gt;…deleted my giant class (called &lt;code&gt;SolarEventManager&lt;/code&gt;) and opened a new, blank file.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Now I had a non-working app with a long list of items to replace before it would even build again. &lt;/p&gt;

&lt;p&gt;I decided to limit the functionality of my new &lt;code&gt;SolarEventManager&lt;/code&gt; to “maintaining an array of solar events.” (Makes sense, right?) I created a separate &lt;code&gt;NetworkManager&lt;/code&gt; to actually make the network requests and a &lt;code&gt;ScreenStops&lt;/code&gt; struct, which calculates the resulting gradients. &lt;/p&gt;

&lt;p&gt;One reason I decided to start from scratch was that I had a lot of code in there I didn’t need at all: a bunch of &lt;code&gt;CoreData&lt;/code&gt; stuff (which was a requirement from my Udacity course) when really, &lt;code&gt;UserDefaults&lt;/code&gt; would do, plus some code duplicating the function of the system’s location manager. So I needed to replace all that with simpler implementation.&lt;/p&gt;

&lt;p&gt;And I also decided to change the way I was making the &lt;code&gt;SolarEventManager&lt;/code&gt; available to my views.&lt;/p&gt;

&lt;p&gt;So it was a lot. &lt;/p&gt;

&lt;h2&gt;
  
  
  Stumbling Blocks
&lt;/h2&gt;

&lt;p&gt;I’m not sorry I started from scratch; it was a good way to reinforce everything I’ve learned writing the original code, while solidly (oops, a pun!) comprehending the new structure I was building. &lt;/p&gt;

&lt;p&gt;However, it did mean days of typing code with no verification that any of it would actually work!&lt;/p&gt;

&lt;p&gt;And please note that I easily could have tackled each of the individual issues listed above one at a time. But no...&lt;/p&gt;

&lt;p&gt;Bravely I forged ahead, or… back, I suppose. Finding my way back to ground zero meant hitting three milestones:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Building the app without incurring any errors.&lt;/li&gt;
&lt;li&gt;Running the app without crashes.&lt;/li&gt;
&lt;li&gt;Getting the app to behave properly.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Because I changed so many things at once, finding and fixing problems at each stage presented a huge challenge. Here are a few of the issues I encountered once I finally got the thing to build again:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Crashes due to an &lt;code&gt;@EnvironmentObject&lt;/code&gt; not being available in the environment.&lt;/li&gt;
&lt;li&gt;Custom navigation buttons not working. One of them crashed the app. &lt;/li&gt;
&lt;li&gt;
&lt;code&gt;UserDefault&lt;/code&gt; key with a typo, which caused weird behavior and was quite difficult to track down. (I made an enum for those keys and updated the entire app accordingly.)&lt;/li&gt;
&lt;li&gt;Banner messages not showing up, due to a logic error in some if-else blocks.&lt;/li&gt;
&lt;li&gt;Crash due to loss of internet.&lt;/li&gt;
&lt;li&gt;Failure to update when the internet was turned back on.&lt;/li&gt;
&lt;li&gt;No background view! &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That last one stumped me for a while — all my assumptions about where my background went were wrong, wrong, wrong. Turns out, a combination of errors was the culprit: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;My JSON decoder had the wrong Type, &lt;/li&gt;
&lt;li&gt;My recursive fetching function wasn’t passing its closure on to the next iteration, and &lt;/li&gt;
&lt;li&gt;I had a &lt;code&gt;var&lt;/code&gt; property defined in the wrong spot so its scope wasn’t what it needed to be.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Those last three bugs were simple oversights. But tracking them down took a WHOLE LOT of detective work, since the error (or errors as it turns out) could have been anywhere in the large swath of code I had changed since the last time things were working correctly. &lt;/p&gt;

&lt;h2&gt;
  
  
  Lessons Learned
&lt;/h2&gt;

&lt;p&gt;Change one thing at a time. That is all. Change, build, test, fix, commit, change, build, test, fix, commit. Making relatively smaller changes and bringing the app back to working order after each would have helped me isolate problems and fix them more quickly. After all, a brand new problem can only be due to something you just changed, so… yeah, small changes make errors much easier to track down.&lt;/p&gt;

&lt;p&gt;The class I deleted was a mess, and I did believe I would end up writing cleaner code by starting from scratch. Maybe that’s true, but also, looking back, to be honest, I think I would have arrived at the same place, and maybe a bit faster. Or maybe a lot faster! &lt;/p&gt;

&lt;p&gt;What do you think? Is there ANY advantage to scrapping a whole section of code from a currently working app, and re-building it from the ground up? Or is it always better to change one bit of functionality at a time? Please post your thoughts!&lt;/p&gt;

</description>
      <category>beginners</category>
      <category>programming</category>
      <category>learning</category>
      <category>refactoring</category>
    </item>
    <item>
      <title>#DEVResolutions2024</title>
      <dc:creator>Monty Harper</dc:creator>
      <pubDate>Thu, 11 Jan 2024 02:14:17 +0000</pubDate>
      <link>https://dev.to/montyharper/devresolutions2024-36bb</link>
      <guid>https://dev.to/montyharper/devresolutions2024-36bb</guid>
      <description>&lt;p&gt;I have one big goal this year: find a remote entry-level iOS developer job!&lt;/p&gt;

&lt;p&gt;Breaking it down, I think finding a job will be a full-time job. Besides sending in applications, I plan to...&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;perfect my resume, LinkedIn, portfolio&lt;/li&gt;
&lt;li&gt;keep on learning - some things on my list: complete 100 days of SwiftUI, learn Firebase, bone up on Design Patterns, learn to do Unit Testing&lt;/li&gt;
&lt;li&gt;find a mentor&lt;/li&gt;
&lt;li&gt;keep posting here about the learning process&lt;/li&gt;
&lt;li&gt;work on an open source or other volunteer project&lt;/li&gt;
&lt;li&gt;do some pair coding&lt;/li&gt;
&lt;li&gt;get better at networking&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>devresolutions2024</category>
    </item>
    <item>
      <title>MarqueeView - Smoothly Scrolling Text in an Infinite Loop Using SwiftUI</title>
      <dc:creator>Monty Harper</dc:creator>
      <pubDate>Tue, 19 Dec 2023 06:47:24 +0000</pubDate>
      <link>https://dev.to/montyharper/marqueeview-smoothly-scrolling-text-in-an-infinite-loop-using-swiftui-2idp</link>
      <guid>https://dev.to/montyharper/marqueeview-smoothly-scrolling-text-in-an-infinite-loop-using-swiftui-2idp</guid>
      <description>&lt;h2&gt;
  
  
  What You'll Find Here
&lt;/h2&gt;

&lt;p&gt;Yes, I will share the code. If that's all you're after, you can scroll on down. But my purpose in posting on Dev is to document my learning journey. So if you read on, you'll also get my motivations, a glimpse into my thought process, all my failures along the way, and what I learned from creating the MarqueeView.&lt;/p&gt;

&lt;h2&gt;
  
  
  Milestones
&lt;/h2&gt;

&lt;p&gt;This month I completed my Udacity nanodegree in iOS Development! My final project was a calendar for my mom, whose temporal lobe epilepsy makes regular calendars unintelligible to her. I turned in an "MVP" (Minimum Viable Product) version of the app, as soon as it met all of Udacity's requirements.&lt;/p&gt;

&lt;p&gt;Now I'm working on a "MomVP" version; one that I can leave with my mom with some confidence it will help more than it will confuse her. This requires a lot of back and forth, observing her interact with the UI, and adjusting the features so they make sense and are useful to her.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Challenge
&lt;/h2&gt;

&lt;p&gt;One feature I realized I would need is a way of displaying messages that come and go at prescribed times. For example, "It's night-time right now. You should be in bed," or "It's Johnny's birthday!" At any given time several of these might be strung together. I wanted to display them in one line, regardless of the length. I also do not want her to have to do anything to view the information. This requires scrolling text. I wanted the text to scroll from right to left continuously and smoothly, like a stock ticker.&lt;/p&gt;

&lt;h2&gt;
  
  
  First Thought
&lt;/h2&gt;

&lt;p&gt;I started off looking for a pre-made solution. I did find a couple of different implementations of this online, but none of them did exactly what I wanted. Typically they achieved the effect by animating an offset. This moves text from right to left, but the challenge comes in bringing the text back onto the screen from the right. Some solutions left a long blank space before starting over, and others only scrolled across one time.&lt;/p&gt;

&lt;h2&gt;
  
  
  Second Thought
&lt;/h2&gt;

&lt;p&gt;After an exhaustive search (I mean, I must have googled four or five different phrases! 😜) I decided to have a go at coding this myself. I ended up making a solution I like better than any I was able to find, so I'm pretty excited about sharing it with you.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Long and Winding Road
&lt;/h2&gt;

&lt;p&gt;My first attempt was a loop that repeatedly moved the first character to the end of the string. I used SwiftUI's Timeline view to trigger the next iteration about five times per second. That worked as proof of concept, but was far from smooth-looking.&lt;/p&gt;

&lt;h3&gt;
  
  
  Animation?
&lt;/h3&gt;

&lt;p&gt;Then I tried adding an animation to the loop: Animate an offset to the left, then move the first character to the end, repeat. This worked, sort of. At first the animation was fading out the old text and fading in the new. But once I got it to actually slide the text... it still looked jerky and annoying!&lt;/p&gt;

&lt;h3&gt;
  
  
  Fixed-Width Font?
&lt;/h3&gt;

&lt;p&gt;The problem was, letters of differing widths require different offset amounts. So I changed my font to a fixed-width font. Problem solved, right? Almost, however... spaces are their own width and still caused the animation to hiccup. (Plus who wants to be limited to using a fixed-width font anyway?)&lt;/p&gt;

&lt;h3&gt;
  
  
  Custom Timeline?
&lt;/h3&gt;

&lt;p&gt;So I created a customized timeline for my Timeline view, with time intervals corresponding to the widths of my characters, calculated to keep things moving at a constant speed. Brilliant. This appeared to help... not at all. &lt;/p&gt;

&lt;h3&gt;
  
  
  Sync Trouble!
&lt;/h3&gt;

&lt;p&gt;The animation was still just as jerky. With some sleuthing I discovered that my time intervals were not syncing up with my characters. I couldn't figure out how to make the string start scrolling exactly when the Timeline view began broadcasting time intervals.&lt;/p&gt;

&lt;h3&gt;
  
  
  Parameter?
&lt;/h3&gt;

&lt;p&gt;Then it occurred to me I should use the Timeline view's date parameter, the way it was designed to be used (duh). Timeline spits out a date every however often you tell it to, and I hadn't been using it. But if I could determine what text to show and where to offset it based on that date parameter... This was a major change in perspective for me. Instead of trying to actually move the text, I needed to think about where the text should be at a given time and just put it there!&lt;/p&gt;

&lt;h3&gt;
  
  
  Array of Strings?
&lt;/h3&gt;

&lt;p&gt;At first I used a whole array of strings, one for each character of my message with that character at the front. I used the time parameter to calculate which string to use, then how much to offset that string. But all those stings seemed like overkill, so I simplified, using string slices to calculate a single string for a given time, starting with the right character. &lt;/p&gt;

&lt;h3&gt;
  
  
  Animation Mode!
&lt;/h3&gt;

&lt;p&gt;I set the Timeline view's timeline to ".animation" - leaving the actual time intervals up to the system. This worked great in my test app! For each Date the Timeline view spit out, I re-calculated the string and offset, and got smooth animation... except...&lt;/p&gt;

&lt;h3&gt;
  
  
  Stuttering Text!
&lt;/h3&gt;

&lt;p&gt;When I put my MarqueeView into my calendar app, the exact same code exhibited some very odd behavior. Instead of scrolling all the way through, every second or so the message would reset back to the start!&lt;/p&gt;

&lt;h3&gt;
  
  
  Getting By With a Little Help From My Friends
&lt;/h3&gt;

&lt;p&gt;At this point I was stumped so I took the problem to Saturday's Flock of Swifts meeting (was that really just two days ago?). The problem was, I refresh my content view (the parent view) once per second for other reasons, and even though my MarqueeView did not depend on any state-related inputs, it was getting re-launched once per second along with everything else.&lt;/p&gt;

&lt;h3&gt;
  
  
  App Window Overlay?
&lt;/h3&gt;

&lt;p&gt;The suggested solution was to attach the MarqueeView to my app window with an overlay. This would put it above the every-second refresh in the hierarchy. And that worked! But...&lt;/p&gt;

&lt;h3&gt;
  
  
  No Access to the Data!
&lt;/h3&gt;

&lt;p&gt;After the meeting I realized we had only tested that solution using a text literal. But there was no way to get text generated from my app into the view since my text-generating class was not available at the app window level. &lt;/p&gt;

&lt;h3&gt;
  
  
  Aha!
&lt;/h3&gt;

&lt;p&gt;One final tweak got me there... The actual reason my MarqueeView kept resetting was because I had put all the set-up code in the view's init function. So each time the view was re-initialized, it reset all the variables tracking how the text was supposed to display.&lt;/p&gt;

&lt;h3&gt;
  
  
  Get Your Business Out of My View!
&lt;/h3&gt;

&lt;p&gt;My solution was to take that business out of the view. Instead I put it into its own class, which I called "MarqueeController." Now in order to scroll some text, I could create a MarqueeController based on that text, then pass that to the view. When the view gets re-booted, it continues to draw values from the controller, which doesn't reset, since it lives outside of the view.&lt;/p&gt;

&lt;h2&gt;
  
  
  Lesson Learned (Again and Again)
&lt;/h2&gt;

&lt;p&gt;Certain core concepts seem easy to understand but weirdly difficult to put into practice. &lt;/p&gt;

&lt;p&gt;I've read a lot about the MVC (Model View Control) principal of separation, and it seems when it comes to defining what goes where, most writers get a little hand-wavy. It's a thing you learn through experience; you have to develop some intuition about it. This little project gave me some of that. &lt;/p&gt;

&lt;p&gt;My initial solution only worked for literal text, and only in its own stand-alone app. The model, view, and control were all encapsulated in a single struct. &lt;/p&gt;

&lt;p&gt;To integrate my MarqueeView into a larger app, it was necessary to separate the three components. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Model&lt;/strong&gt;&lt;br&gt;
The text to display is calculated from my data model, an array of calendar events. When the events get updated, the text is updated, and the new text is funneled into the view controller via a published variable.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;View&lt;/strong&gt;&lt;br&gt;
The MarqueeView itself is basically just a text view with modifiers inside a TimelineView. It's the minimum code required to put the text on the screen in an animation context.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Control&lt;/strong&gt;&lt;br&gt;
The MarqueeController class is the brains behind the whole operation. It takes in a given time and returns the information needed to place the text where it should go at that exact moment.&lt;/p&gt;

&lt;p&gt;An instance of MarqueeController works independently from the MarqueeView. This allows the system to destroy and re-create the view as needed. So long as it references the same controller, a new view instance will pick up smoothly where the old one left off. &lt;/p&gt;
&lt;h2&gt;
  
  
  How to Use the MarqueeView
&lt;/h2&gt;

&lt;p&gt;First, create a MarqueeController instance by passing in a String to be displayed.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;let marqueeController = MarqueeController(message: yourMessageHere)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then place the view by passing in your MarqueeController.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;MarqueeView(controller: marqueeController)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's it. The string &lt;code&gt;yourMessageHere&lt;/code&gt; will scroll forever and ever.&lt;/p&gt;

&lt;p&gt;You could also test it out by placing this inside your ContentView:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;MarqueeView(controller: MarqueeController(message: "This is a test. This text will scroll smoothly from right to left forever and ever.  *  "))
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Customization
&lt;/h2&gt;

&lt;p&gt;You can change the speed of the scroll by changing the value for &lt;code&gt;let speed&lt;/code&gt; in the MarqueeController.&lt;/p&gt;

&lt;p&gt;You can also change the font or font size by making changes to &lt;code&gt;let marqueeFont&lt;/code&gt; in the MarqueeController. Make sure to use UIFont in order for the width calculations to work.&lt;/p&gt;

&lt;h2&gt;
  
  
  Here's the Code! Enjoy!
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;//
//  MarqueeView.swift
//
//  Created by Monty Harper on 12/11/23.
//

import Foundation
import SwiftUI

struct MarqueeView: View {

    // Making the controller optional allows you to place the MarqueeView before text is available to display without crashing your app.
    var controller: MarqueeController?

    init(controller: MarqueeController?) {
        self.controller = controller
    }

    var body: some View {

        if let controller = controller {
            TimelineView(.animation) {context in
                Text(controller.frame(context.date).text)
                    .padding()
                    .lineLimit(1)
                    .font(Font(controller.marqueeFont))
                    .foregroundColor(.primary)
                    .offset(x: controller.frame(context.date).offset, y: 0.0)
                    .background(.white)
                    .fixedSize(horizontal: true, vertical: false)
                    .clipped()
            }
        } else {
            Text("There is nothing to display yet...")
        }
    }
}


class MarqueeController {

    let message: String
    var characterWidths = [Double]()
    var timeMarkers = [TimeInterval]()
    var startTime = 0.0
    var runningTime = 0.0
    let speed = 90.0 // points/second
    let marqueeFont = UIFont.systemFont(ofSize: 24, weight: .black) // Using a UIFont because the width can be measured.

    init(message: String) {
        self.message = message
        var text = message
        for _ in 0..&amp;lt;message.count {
            let first = String(text.removeFirst())
            let width = first.size(withAttributes: [.font: marqueeFont]).width
            characterWidths.append(width)
            runningTime += width/speed
            timeMarkers.append(runningTime)
            text += first
        }
        startTime = Date().timeIntervalSince1970
    }

    // Given a time, return the text and offset that should be displayed at that moment.
    func frame(_ date: Date) -&amp;gt; (text: String, offset: Double) {
        let time = (date.timeIntervalSince1970 - startTime).truncatingRemainder(dividingBy: runningTime)
        let index = (timeMarkers.firstIndex(where: {time &amp;lt; $0}) ?? 0)
        let startStringIndex = message.startIndex
        let endStringIndex = message.endIndex
        let midStringIndex = message.index(message.startIndex, offsetBy: index)
        let text = String(message[midStringIndex..&amp;lt;endStringIndex]) + String(message[startStringIndex..&amp;lt;midStringIndex])
        let offset = characterWidths[index] * ((timeMarkers[index] - time)/(timeMarkers[index] - (index == 0 ? 0 : timeMarkers[index - 1])) - 1.0)
        return(text: text, offset: offset)
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>swift</category>
      <category>coding</category>
      <category>ios</category>
      <category>learning</category>
    </item>
    <item>
      <title>Non-Linear Thinking Part 2 - A Mysterious Doouubbllee.</title>
      <dc:creator>Monty Harper</dc:creator>
      <pubDate>Sun, 03 Dec 2023 18:44:26 +0000</pubDate>
      <link>https://dev.to/montyharper/non-linear-thinking-part-2-a-mysterious-doouubbllee-210p</link>
      <guid>https://dev.to/montyharper/non-linear-thinking-part-2-a-mysterious-doouubbllee-210p</guid>
      <description>&lt;p&gt;As I refine my app in preparation for turning it in, I continue to struggle with the non-linear nature of object-oriented programming.&lt;/p&gt;

&lt;p&gt;Don't get me wrong, it's fantastic. It allows me to do stuff I couldn't have dreamed of in a previous life! But it also opens the door to weird and challenging behaviors. &lt;/p&gt;

&lt;h2&gt;
  
  
  A Mysterious Mysterious Double Double
&lt;/h2&gt;

&lt;p&gt;Yesterday I solved one of those mysteries. &lt;/p&gt;

&lt;p&gt;My app displays events from Apple's Calendar App, so the user is presented a list of Apple calendars and asked to choose which ones will supply events to be displayed. That page was working great except on first launch, when some or all of the available calendars were showing up twice. This happened consistently, although which of the calendars got doubled seemed random.&lt;/p&gt;

&lt;h2&gt;
  
  
  Careful Sleuthing
&lt;/h2&gt;

&lt;p&gt;I used some print statements and breakpoints to determine more specifically what was happening.&lt;/p&gt;

&lt;p&gt;The function that collects my calendars into an array clears out the current array, then adds new calendars to it. I put some print statements in, believing it was silly because the function itself runs linearly from top to bottom as functions do, so my print statements should &lt;em&gt;&lt;strong&gt;obviously&lt;/strong&gt;&lt;/em&gt; output:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"I'm clearing the calendar array."&lt;br&gt;
"I'm adding new calendars."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;But when I ran the app, here's what I got instead:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"I'm clearing the calendar array."&lt;br&gt;
"I'm clearing the calendar array."&lt;br&gt;
"I'm adding new calendars."&lt;br&gt;
"I'm adding new calendars."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That explains the doubling, sort of. But how is it possible? The function seems to be looping where there aren't any loops!&lt;/p&gt;

&lt;p&gt;The only explanation I could think of would be that the function is getting called twice at the same time. Sure enough, adding a break point showed that this was the case; it was running concurrently on two different threads. But why?&lt;/p&gt;

&lt;h2&gt;
  
  
  More Sleuthing
&lt;/h2&gt;

&lt;p&gt;So I searched the code for the function name, and no - I only ever call it explicitly one time, from the init of my EventManager class. The app creates only one instance of EventManager, so... &lt;/p&gt;

&lt;p&gt;Well, there is one other place the function gets called, in the same init, buried within this statement:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;NotificationCenter.default.addObserver(self, selector: #selector(self.updateCalendarsAndEvents), name: .EKEventStoreChanged, object: eventStore)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This notification will call the updateCalendarsAndEvents function whenever the data in the Apple Calendar App changes. But I'm not making any changes! &lt;/p&gt;

&lt;p&gt;Although... the user IS asked for permission to access the Calendar app at the start of my update function. The way permissions work, the system only actually asks the user for permission once - on first launch. That could explain why the calendar list only misbehaves on first launch!&lt;/p&gt;

&lt;h2&gt;
  
  
  A Working Theory
&lt;/h2&gt;

&lt;p&gt;So here's my theory: The app calls the update function when it initializes my EventManager. The function pauses for a response to the permissions request. Meanwhile, the Notification command is executed, so we are now subscribed. When the user responds with permission, the update function continues. Simultaneously, NotificationCenter interprets the change in permissions as reason enough to trigger the update function. So before the function call from init can be completed, the same function gets a second call from notifications, and now it's running on two different threads. The timing is close enough that both calls create new calendars after both calls erase existing calendars. It's also close enough that sometimes a new calendar created by the first call gets erased by the second call, which explains why the number of duplicated calendars seems random.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Fix
&lt;/h2&gt;

&lt;p&gt;A fix seemed impossible for a moment... All three parts are required: I need to updateCalendarsAndEvents when the EventManager is initialized, I need to ask the user for permission to access Calendar, and I need to subscribe to changes, so my app can fetch new calendars and events when they become available. &lt;/p&gt;

&lt;p&gt;So I dug into the documentation, and soon discovered that the logic of my app was based on a misunderstanding.&lt;/p&gt;

&lt;p&gt;I had thought I needed to check permissions &lt;em&gt;every time&lt;/em&gt; I accessed the EventStore. But that is not the case. Requesting permission is a separate function from fetching data. So!&lt;/p&gt;

&lt;p&gt;My mistaken code looked like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;func updateCalendarsAndEvents() {
eventStore.requestAccess(to: EKEntityType.event) {
 // closure containing the logic for erasing the current array and replacing it with new calendars
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I fixed it by creating a Bool to check my current permission status, and moving the request for access into my EventManager init, like so:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;init() {
        NotificationCenter.default.addObserver(self, selector: #selector(self.updateCalendarsAndEvents), name: .EKEventStoreChanged, object: eventStore)

        if StateBools.shared.noPermissionForCalendar {
            eventStore.requestAccess(to: EKEntityType.event) {_,_ in}
            // If permission is newly given, notifications will fetch new data
        } else {
            // If permission is already given, fetch new data.
            updateCalendarsAndEvents()
        }
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With my new logic in place, the doubling has ceased! I just needed to make sure permissions were requested only when necessary, and allow the correct function call to handle the update so they weren't both trying to do it at once.&lt;/p&gt;

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

&lt;p&gt;Non-linear programming can lead to odd behaviors such as duplicated data caused by one function running twice concurrently, but careful sleuthing and clear logic will save the day!&lt;/p&gt;

</description>
      <category>programming</category>
      <category>beginners</category>
      <category>learning</category>
      <category>swift</category>
    </item>
    <item>
      <title>Non-Linear Thinking, part 1</title>
      <dc:creator>Monty Harper</dc:creator>
      <pubDate>Sat, 25 Nov 2023 05:02:46 +0000</pubDate>
      <link>https://dev.to/montyharper/non-linear-thinking-part-1-2cgk</link>
      <guid>https://dev.to/montyharper/non-linear-thinking-part-1-2cgk</guid>
      <description>&lt;h2&gt;
  
  
  Swift is object-oriented!
&lt;/h2&gt;

&lt;p&gt;I was weened long ago on BASIC (Don’t look that up or you may fall into a time vortex from which there is no escape), which flows logically from top to bottom, while Swift (or any modern programming language), flows…? &lt;/p&gt;

&lt;p&gt;I’ll put it this way: if BASIC is the lazy river ride at your local water park, Swift is kayaking in a time machine through the Sea of Holes during a monsoon in the middle of a hurricane. &lt;/p&gt;

&lt;p&gt;How does non-linear programming work? I understand arrays and if-then statements and loops and switches and functions, reference types vs. value types, views with parent-child relationships, etc. etc. All the parts make sense. But getting them to work together - deciding where things go - understanding when things pop in and out of existence - getting information from where it is to where it needs to be at the time when it’s needed - following asynchronous processes through a tangle of threads… I get tied up in knots.&lt;/p&gt;

&lt;p&gt;I’m struggling to think in terms of objects, so that’s what I’ll be writing about for a bit.&lt;/p&gt;

&lt;h2&gt;
  
  
  Re-Evaluation
&lt;/h2&gt;

&lt;p&gt;This week I came to a milestone in the app I’m working on. After much struggle, I’ve connected quite an assortment of parts and… it works! All the basic features are popping. I still need to tidy some things up, though, before I can turn this in as my final assignment in Udacity’s iOS Dev nano-degree.&lt;/p&gt;

&lt;p&gt;So this is a good time for re-evaluation. Over the past two days, I’ve read through my entire body of code - more than 20 files - updating and adding comments and taking notes. I collected a list of 34 to-dos! I think I’ve got a strong foundation to work from, so adding and tweaking those features won’t be too very difficult.&lt;/p&gt;

&lt;p&gt;I also took the opportunity to reflect on the big-picture organization of my app. I certainly had a lot of help getting to this point, so I want to make sure I understand how I put it together and why.&lt;/p&gt;

&lt;h2&gt;
  
  
  Published Property vs. Function Return?
&lt;/h2&gt;

&lt;p&gt;I built several classes that provide information to my main view. In some cases that information is transferred as a property - an array of objects - passed in with an @StateObject wrapper. In other cases the information is supplied as the return value of a function. My question is, why one method over the other? Was I consistent in my thinking? Or was this a random choice each time? Is one method always better than the other? Or does it depend on context? &lt;/p&gt;

&lt;p&gt;The act of writing those questions put my brain to work, asynchronously synthesizing information on its background thread. The answers came to me suddenly in the shower. And here they are:&lt;/p&gt;

&lt;h2&gt;
  
  
  Answers
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Use @StateObject for information that may change behind the scenes, regardless of what’s happening on the screen.&lt;/li&gt;
&lt;li&gt;Use a function return when the information depends on the current view or state and won’t change based on input from elsewhere.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For example, in my app, the EventManager is a class that collects event information from the Apple Calendar App and provides it to the main view. It keeps an array of events as a @Published property. When the user changes an event in the Apple Calendar App, the Event Manager reacts by updating its own array of events. When the view notices the change, via the @StateObject property wrapper, it updates as well. So change propagates from behind the scenes to the main view.&lt;/p&gt;

&lt;p&gt;On the other hand, my background view is a complicated color gradient, rendered from an array of color stops. The stops depend on the current timeline, which depends on user interaction via the main view. So the view passes its timeline to the color stops function in my SolarEventsManager, which returns an array of stops for it to render.&lt;/p&gt;

&lt;h2&gt;
  
  
  Considering the Counter-Factual
&lt;/h2&gt;

&lt;p&gt;To further understand why these are the right choices, I considered the alternatives. What if I tried to use a function to provide events from the EventManager to the main view? When events were changed by the user, the view would be unaware of the changes. It would need to call on the function every second or so just in case changes had occurred. Mostly it would be receiving the same response over and over, which is pretty inefficient.&lt;/p&gt;

&lt;p&gt;For the background view, my timeline changes once per second and also whenever the user zooms in or out. To provide the color gradient as an @StateObject, my SolarEventsManager would need to access those changes to the view, then publish the new array, triggering the view to update again. Since the view is already updating every second, this just doesn't seem like a good idea. Would it create an endless loop of updates? I don't know. It seems a lot simpler for the view to grab a new gradient whenever it knows its own changes call for one.&lt;/p&gt;

&lt;p&gt;(Maybe I could simplify the background by creating one big gradient, shared via the @StateObject wrapper, then have the view display only the needed portion at any given moment, rather than re-generate a whole new gradient once per second. That’s something to look into later. Copying this to my to-do list!)&lt;/p&gt;

&lt;h2&gt;
  
  
  To summarize:
&lt;/h2&gt;

&lt;p&gt;&lt;u&gt;Lessons on Learning&lt;/u&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It’s a great learning exercise to go back through your code and make notes.&lt;/li&gt;
&lt;li&gt;Writing down questions can trigger your brain to provide answers; this is a great way to synthesize and solidify what you already know.&lt;/li&gt;
&lt;li&gt;Examine both sides of the coin: Why does it work this way? Why does it not work the other way?&lt;/li&gt;
&lt;li&gt;This kind of analysis can lead to new insights and tightening of your code.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;u&gt;Lessons in Object-Oriented Programming&lt;/u&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Your view should access &lt;strong&gt;stored&lt;/strong&gt; information if that information may change on its own.&lt;/li&gt;
&lt;li&gt;Your view should &lt;strong&gt;re-generate&lt;/strong&gt; information if that information depends on your view.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let me know what you think. If you're learning Swift, what general principals do you find tricky?&lt;/p&gt;

</description>
      <category>programming</category>
      <category>beginners</category>
      <category>learning</category>
      <category>swift</category>
    </item>
  </channel>
</rss>
