100daysofswiftui


Nov. 26, 2022

FriendFace 61 Feedback

As usual after a challenge, I compare my efforts to Paul’s model solution. Just to quickly recap the app, it sucks up some data (Users who have multiple friends) and displays it. The change in this challenge was to convert it to add that data to a Core Data store so that if a future network error prevented accessing new data, it could still display the old.

Merge Policy

The first difference is that Paul adds a merge policy. A Merge policy tells Core how to deal with any constraints defined in the data model. In this app, I’d defined the CachedUser.id as a constraint. The purpose of this is that under normal conditions the app would be picking up mostly the same data each time it started up. We don’t want scabs of duplicate data, so constraining users based on their unique id is smart.

Nov. 25, 2022

61 Done

I think I’ve finally completed the minimum work for Day 61 of #100DaysOfSwiftUI . The task was to suck up some data in JSON, decode it. back it up into a Core Data graph then display the data from the Core Data.

I got stuck on dealing with the one:many relationship and had to revisit that from a different source to get my head around it, after that it was straightforward. Other small problem I ran into was that I created the id in the CachedUser as a UUID from (newly formed) habit. Then when I went to copy it in from the JSON version, it wouldn’t let me. When I realised my mistake and changed it in the data model, I still could not figure out why it wasn’t working - but of course I hadn’t regenerated the code for the ManagedObject. I just had to change the property type in the already generated code from UUID to string and I was back in business.

Nov. 15, 2022

FriendFace Feedback

After each app, I use my HackingWithSwift+ membership to view Paul’s version of the app as a way to judge my performance. Yesterday’s app was “FriendFace ” - download some JSON of a number of people (including their friends) and display it.

UUID

In my struct, I’d just specified the User.id as a string, Paul uses UUID - this makes no difference to the app as it stands, but is much better if we ever needed to add users.

Nov. 14, 2022

FriendFace

The Day 60 Milestone is a demo app that vacuums up some JSON and displays it in a list in a NavigationView that links to a details page. Nothing super strenuous, the steps were something like this:

  1. Download the JSON and have a look at the structure. Firefox has a simple JSON viewer built in, so it was straightforward to see this is an array of users, which along with some (mostly string) properties contains an array of tag strings, and another array of friends.

Nov. 11, 2022

Project 12 Feedback

adel and taylor swift with ed sheeran, watercolor painting - stable diffusion

As usual, I watch Paul’s solution video, and compare it to mine.

Task 1

This was passing in the predicate as a String. I passed the whole thing, but as I figured out along the way, Paul meant just the operator word. He also added some buttons to test it better, which I didn’t think of till Task 3 - it would have saved me some simulator runs.

Nov. 10, 2022

Project 12 Challenges

taylor swift with ed sheeran and adel, watercolor painting - Stable Diffusion

Project 12 was a series of code tutorials around developing CoreData concepts rather than a real app, but the challenges are based on a very small app that uses a subview to allow dynamic (ie changeable at runtime) filtering of a list of data. The reason this would be tricky is that the @FetchRequest is a property of a view - and therefore mutable. The trick is to have a subview to build that part of the view, and to pass parameters into it which build the fetchrequest using an underscore.

Nov. 9, 2022

You Can Take Big Steps When You Feel Safe

Day 58 of #100Days feels like complex topics are being dropped in pretty fast. We tackle one:many data relationships and how to set them up in CoreData, using CoreData constraints and setting a merge policy to manage conflicts, and even the underscore to access the actual property inside a wrapped property struct (needed for dynamic filtering in a view).

I’ve mentioned before that I think Paul Hudson is an excellent teacher, and an example of this is that even though this was a day with a lot of challenging material, I’m not worried. I followed the discussion and tried the code, and more importantly I’m anticipating these new skills will be practiced in the next app, and probably shortly after I’ll be writing an app using them.

Nov. 7, 2022

Bookworm Feedback

I did so well on this one that it’s not going to make a very interesting post. My first two challenge solutions were pretty much character for character the same - so not much to report.

On the third challenge, there was a minor difference in the display process. I had done this:

let date = book.date ?? Date()
Text(date.formatted(.dateTime.day().month().year()))
    .foregroundColor(.secondary)
    .opacity(date == book.date ? 1 : 0)

But @twostraws went:

Nov. 6, 2022

Bookworm Challenges

cartoon worm on a book - Stable Diffusion

Another set of challenges for a #100DaysofSwiftUI tutorial app. Project 11 was a book tracking app - the big new thing was using CoreData. Here’s the challenges for it .

Right now it’s possible to select no title, author, or genre for books, which causes a problem for the detail view. Please fix this, either by forcing defaults, validating the form, or showing a default picture for unknown genres – you can choose.

Nov. 4, 2022

CoreData and the Preview

looking through a keyhole to a room, diagram, colorful - Stable Diffusion

I’ve noticed Paul is inclined to ignore the preview and run his code in the simulator to check its operation. That’s valid, but it seems quicker, and reassuring, to see it in the preview as I type.

This led to a small problem with Day 53 that uses CoreData. When I added a student in the preview, it looked like this, and was immediately followed with a crash report.

Nov. 3, 2022

Cupcake Corner Feedback

cute cupcake, cartoon drawing - Stable Diffusion

As usual, here’s my thoughts comparing my attempts at the challenges to Paul’s. Usually he’s better!

1) Whitespace

The task was to validate the order address properties, not just by checking they are not empty, but also that they don’t just contain spaces. I went the bruteforce route since there was no .isEmptyIncludingWhitespace method.

var hasValidAddress: Bool {
    let trimmedName = name.trimmingCharacters(in: .whitespacesAndNewlines)
    let trimmedStreetAddress = streetAddress.trimmingCharacters(in: .whitespacesAndNewlines)
    let trimmedCity = city.trimmingCharacters(in: .whitespacesAndNewlines)
    let trimmedZip = zip.trimmingCharacters(in: .whitespacesAndNewlines)

    if trimmedName.isEmpty || trimmedStreetAddress.isEmpty || trimmedCity.isEmpty || trimmedZip.isEmpty {
        return false
    }
    return true
}

As soon as Paul mentioned extending String, I facepalmed - of course, just create the method I want on string. Paul’s is a one line extension - neater, and Swiftyier.

Nov. 2, 2022

Cupcake Corner challenges

cute cupcake, cartoon - Stable Diffusion

Day 52 of #100Days was the challenges to the Cupcake Corner app - an app that allows you to build a one-row order, encode it as JSON and submit it to an API with a URLSession. To allow the order to be passed around, it’s an @ObservedObject which meant that a few extra hoops needed to be jumped through to make it Codable.

1) Whitespace validation

The tutorial app validates the order address by checking that each field is not empty, but it can be fooled by just entering some spaces. The first challenge was to fix that.

Nov. 1, 2022

Top Four Reasons why @TwoStraws is a Good Teacher

Good Questions

At various points in the 100 Days of SwiftUI course, you get asked sets of questions to check you’ve understood the preceding material. They’re usually presented as two different statements, one of which is true, and the other false. It’s actually a really good technique - the student feels like they’ve got a couple of opportunities to figure it out, plus they are forced to read both statements and think about them. Paul does a similar thing in the Unwrapped app - there, the questions are often presented as “Is this valid Swift code” and the user needs to scan through it all looking for mistakes. It’s checking your understanding, and making you a thoughtful debugger!

Oct. 27, 2022

Day 47 - Habits App

pretty! woman holding a bag of trash, Artstation - Stable Diffusion

I’ve been mucking around with the Habits app too long - it’s started to look like procrastination. It already meets the specification , so I’m calling it an MVP and moving on.

This is the first app of mine I’ve loaded onto my phone and started using, and there are a couple of things I’d like to do with it. It currently just lets you specify how many days between an activity repeating - so if you say you should go to the gym every second day, and you complete that activity on Monday, “Gym” will make it’s way to the top of the list on Wednesday. While it’s waiting in the list for Wednesday to come around, it will show the “Due” time as being exactly 48 hours after you last pressed “done” on it. But if the habit you want is to go to the gym after work at 6:00pm that’s when you want it to be due. I’d like that.

Oct. 19, 2022

Drawing Feedback

Hedy Lamarr standing in front of a drawing, Kuvshinov Ilya - Stable Diffusion

Here’s the summary of my learning from comparing my efforts with Paul’s solutions to the Project Nine challenges from Day 46 of his 100 Days of SwiftUI course .

Create an Arrow shape – having it point straight up is fine. This could be a rectangle/triangle-style arrow, or perhaps three lines, or maybe something else depending on what kind of arrow you want to draw.

Oct. 18, 2022

Project 9 - Drawing

Screenshot of Xcode and the preview showing some fancy graphics

These few days of #100DaysOfSwiftUI we made some pretty shapes by playing around with some of the SwiftUI systems for drawing on the screen, including paths, shapes, transformations, ImagePaint, drawingGroup() to use Metal rendering, blurs, blend modes and using animatableData for animating - which I think is the solution to an animation problem in my TimesTable app I hadn’t been able to solve yet.

Oct. 15, 2022

Moonshot Feedback

Girl with a headset in a space command center, Kuvshinov Ilya, Mitsumayo - Stable Diffusion

I’ve watched Paul’s solution to the Moonshot challenges (the solutions are one of the perks of being a Hacking With Swift subscriber). When I’m solo learning like this its one of the few ways I can get any feedback on my coding, so I highly value it, and usually write one of these posts as a way to ensure I reflect on it.

Oct. 14, 2022

Moonshot Challenges

Another few coding challenges at the end of a tutorial app in the 100 Days of SwiftUI course. The app is a sort of information app - composed of navigation views going down into more detail about the Apollo space missions. The most exciting revelation for me was how straightforward it is to pull JSON into your apps data structures.

Challenge 1

Add the launch date to MissionView, below the mission badge. You might choose to format this differently given that more space is available, but it’s down to you.

Oct. 12, 2022

iExpense Feedback

I finally got around to looking at Paul’s solutions for the iExpense challenges .

Use the user’s preferred currency, rather than always using US dollars.

Same approach as me,

.currency(code: Locale.current.currency?.identifier ?? "USD")

except that he does the work in a local variable which is a bit neater. Since it appears in two places - the display view and the view for adding an expense, this would mean duplicating it, making it global (not rare for user default type settings) or passing it down through the view hierarchy. I feel either of the first two options are fine for this project, but Paul is thorough and extends the FormatStyle protocol, only for currency, to have a new computed property .localcurrency - which is a great solution.

Oct. 2, 2022

iExpense Challenges

Day 38 is three challenges on the iExpense app - a simple expense tracking app that uses UseDefaults for storing it’s data.

Locale

Use the user’s preferred currency, rather than always using US dollars.

One of the joys of modern programming (as opposed to mid-1990’s programming) is the ability of the internet to give you answers. I knew the answer to this would be lurking in the locale environment variable, but instead of looking it up , just googled, and found a viable looking solution on Reddit .