- WANG Shudao
This week I suddenly had a momentary thought to make this weekly journal paid reading, publishing it on platforms like Xiaobao Tong or Zhubai or enabling paid reading for this public WeChat account. But then I thought of how many top experts and masters have been continuously outputting high quality articles for free, like fatbobman, if I charged for these ramblings it would be too outrageous, so I quickly dismissed that idea.
This week I did paired programming with Claude 2 to implement the drafts feature decided on last week. I thought it would only take a day or two but this feature ended up taking the entire week of writing and rewriting, on Saturday I even decided to scrap everything and start over.
All the coding work this week was related to Core Data, learning a lot of new things about Core Data.
It was only through Zhouzi Ge's blog that I learned every managed object in Core Data has an
objectID property, and you can easily get a managed object through this property and the
existingObject(with:) method. Previously when I needed to get a specific managed object, I would build a predicate using a custom
id property on the model, query, and just take the first result.
However, this property seemingly can't be used in predicates, I tried several ways but all got errors, the answers from Claude 2 also got errors.
My initial thought was: when editing a diary entry, first convert the Entry to a Draft, then bind all editable variables to the Draft using Combine for realtime saving. But I discovered a problem doing this - after generating the Draft from the Entry, the original relational properties of the Entry disappeared. Below is the reason explained by Claude 2:
CRUD Through Different Contexts
For Entry objects gotten through @FetchRequest in the view, if you edit and save them directly through
performBackgroundTask(_:) there's no issue changing properties on the Entry itself, but changing relational properties causes a crash. After consulting Claude 2, unifying the contexts solved this problem.
By default all Core Data properties are Optional, meaning a property can be empty when saved to Core Data. But I didn't know this previously - the autogenerated NSManagedObject code from Core Data has all properties as Optional too, so I thought it was the same as Swift Optionals.
To avoid checking Optionals, I changed some Draft entity properties to non-Optional and set default values, but the autogenerated code still had the properties as Optional... Asking Claude 2 also resulted in nonsense answers. So in the end I still couldn't remove the ? from each property.
Additionally, always respect every Optional variable, this was something I learned the hard way this week. Diary list data comes from converting Entry to EntryViewModel. Because Entry's id property was Optional, in the conversion process I assigned a default value to the corresponding EntryViewModel id property - I thought this was just an operation to resolve warnings, but it created a hidden danger that took half a day to discover the cause. Because the default UUID, it caused the id for a EntryViewModel generated from an Entry without id to be different each time, then leading to being unable to find the original Entry when updating the generated Draft...
Despite the various issues, the drafts feature finally got completed. On Sunday afternoon I sent TestFlight build 11, testers immediately discovered all kinds of bugs, so Sunday night I sent 3 more builds to fix those bugs. In any case, I still want to release 1.7.6 next week, then I can focus on adapting to iOS 17 and developing a new app.