Loading SampleData in CoreData
When I started developing my first app, I based a lot of what I was doing on what I learned from Paul Hudson’s 100 Days of SwiftUI and his Hacking With Swift+ Ultimate Portfolio app. For my sample data, I created a function that loops through and create some sample data. Unfortunately, because I need to have multiple nested loops, I ended up with a lot of generic entries, like “Prayer List 1”, “Prayer Subject 2”, etc. I know it is just sample data, but I wanted something that was a little more realistic, especially when I loaded it into my simulator.
I could have done it within my function, making it larger and more complicated, but instead I decided to look into what it would take to load my sample data from a JSON file. That way, I can quickly change the data I want to add without having to rewrite my function. It turns out , it is pretty easy.
The first thing that I did was create an extension for my Persistence Controller in a new file so that my sample data logic is self contained.
1
2
3
extension PersistenceController {
}
Next I created a json file to hold my prayer data. The structure starts with my prayer list, which contains prayer subjects, which contains individual prayers. I decided not to put all of the attributes in JSON. Some things can be auto-generated like dates.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
[
{
"name": "Daily",
"order": 0,
"weekdays": [ 1, 2, 3, 4, 5, 6, 7 ],
"prayerSubjects": [
{
"name": "Personal",
"order": 0,
"prayer": [
{
"name": "Discipline & Focus",
"order": 0
}
]
},
{
"name": "Spouse",
"order": 1,
"prayer": []
}
]
}
]
Next, I needed to create the models for may prayer list to be imported to. Since these models specifically for my JSON, I just included them in the extension I created.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
extension PersistenceController {
struct SamplePrayerList: Codable {
let name: String
let order: Int16
let weekdays: [Int16]
let prayerSubjects: [SamplePrayerSubject]
}
struct SamplePrayerSubject: Codable {
let name: String
let order: Int16
let prayer: [SamplePrayer?]
}
struct SamplePrayer: Codable {
let name: String
let order: Int16
let details: String?
}
}
Finally, I created a function to load the data from JSON and then looped through it to add everything to CoreData.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
extension PersistenceController {
func loadSampleData() {
let context = container.viewContext
guard let url = Bundle.main.url(forResource: "sampleData", withExtension: "json") else {
print("JSON file not found")
return
}
do {
let data = try Data(contentsOf: url)
let decoder = JSONDecoder()
decoder.dateDecodingStrategy = .iso8601
let samplePrayerLists = try decoder.decode([SamplePrayerList].self, from: data)
for list in samplePrayerLists {
let newList = PrayerList(context: context)
newList.name = list.name
newList.order = list.order
newList.creationDate = Date().minus(7)
for weekday in list.weekdays {
let weekdayItem = WeekdayItem(context: context)
weekdayItem.value = weekday
newList.addToWeekdays(weekdayItem)
}
for subject in list.prayerSubjects {
let subjectItem = PrayerSubject(context: context)
subjectItem.name = subject.name
subjectItem.order = subject.order
subjectItem.creationDate = Date().minus(7)
newList.addToSubjects(subjectItem)
for prayer in subject.prayer {
if let prayer = prayer {
let newPrayer = Prayer(context: context)
newPrayer.name = prayer.name
newPrayer.order = prayer.order
newPrayer.details = prayer.details
newPrayer.creationDate = Date().minus(7)
subjectItem.addToPrayers(newPrayer)
}
}
}
}
try context.save()
} catch {
print("Failed to load sample data: \(error)")
}
}
// Define a struct to match the JSON structure
struct SamplePrayerList: Codable {
let name: String
let order: Int16
let weekdays: [Int16]
let prayerSubjects: [SamplePrayerSubject]
}
struct SamplePrayerSubject: Codable {
let name: String
let order: Int16
let prayer: [SamplePrayer?]
}
struct SamplePrayer: Codable {
let name: String
let order: Int16
let details: String?
}
}
This way, no matter how much data I want to load in, my function stays the same. All I have to do is edit my JSON file to change the contents of my test database. It also makes it easier to have multiple datasets. All I need to do is change out the JSON file.