Save and persist data with UserDefaults | Todo List #4
Summary
TLDR在这个视频中,Nick 介绍了如何在他们正在开发的应用程序中实现数据持久化。他们指出,尽管应用程序可以正常工作,但之前并未保存任何数据,导致关闭并重新打开应用程序后,所有新增的待办事项都会丢失。为了解决这个问题,Nick 决定使用 UserDefaults 来保存待办事项列表。他解释说,UserDefaults 适用于存储较小的数据片段,例如用户 ID 或当前用户的名称。在本例中,由于待办事项模型只包含标题和布尔值,因此使用 UserDefaults 是合适的。Nick 展示了如何将待办事项模型转换为 JSON 数据,然后存储到 UserDefaults 中,并在需要时再将其转换回模型。他还展示了如何通过在待办事项数组上使用计算属性和 didSet 来确保每次更改数组时都会保存到 UserDefaults。最后,他演示了如何从 UserDefaults 中检索数据,并更新应用程序中的待办事项列表。这个视频不仅提供了关于如何使用 UserDefaults 的实用指导,还练习了使用 guard 语句和 if let 语句进行可选绑定。
Takeaways
- 📝 课程中构建的应用程序可以正常工作,但之前没有实现数据保存功能,关闭再打开应用后,新添加的待办事项会丢失。
- 🔄 为了解决数据保存问题,视频介绍了如何使用用户默认设置(UserDefaults)来保存待办事项列表,使其在会话之间持久化。
- 📚 用户默认设置(UserDefaults)主要用于存储较小的数据片段,例如用户ID或用户名,而不适用于大型数据库。
- 🛠️ 通过将待办事项列表(Item Models)转换为JSON数据,可以存储在UserDefaults中,之后可以再次转换回待办事项列表。
- 🔑 为了能够将待办事项列表编码为数据,Item Model需要符合Codable协议,这样可以实现数据的编码和解码。
- 🔩 在ListView Model中创建了一个新的函数`saveItems`,用于将待办事项列表编码并存储到UserDefaults中。
- 🔄 通过计算属性和`didSet`属性观察器,确保每次待办事项列表(items array)发生变化时,都会调用`saveItems`函数进行保存。
- 🔑 引入了一个常量`itemsKey`作为UserDefaults中的键,避免直接在代码中硬编码键名,提高代码的可维护性。
- 📈 为了从UserDefaults中恢复待办事项列表,需要使用JSON Decoder将存储的数据解码回Item Models数组。
- 🛡️ 使用`guard`语句来安全地解包可选类型,确保数据存在且可以成功转换为待办事项列表。
- 🔄 通过在应用启动时从UserDefaults获取数据,并更新待办事项列表,实现了数据的持久化。
- 🎉 关闭应用后再打开,可以看到之前添加和修改的待办事项都被保存了下来,演示了数据持久化的成功实现。
Q & A
为什么在应用程序中添加了新的任务后,关闭再打开应用,任务会消失?
-这是因为应用尚未实现数据持久化功能,关闭应用后,之前添加的任务没有被保存,所以重新打开应用时会恢复到初始状态。
为了使应用中的数据在关闭后重新打开依然存在,应该使用什么技术?
-在视频中,Nick提到如果是为了上架App Store的应用,可能会使用Core Data。但在这个例子中,为了简单,选择使用了UserDefaults。
为什么在Swift UI Bootcamp课程中没有覆盖Core Data的内容?
-Nick没有在Swift UI Bootcamp中覆盖Core Data的内容,可能是因为课程的重点在于其他方面,或者是时间限制,或者是为了让课程更加集中和易于消化。
UserDefaults适合存储哪些类型的数据?
-UserDefaults主要适合存储较小的数据,例如用户ID或当前用户的姓名。对于较大的数据集,应该使用其他存储解决方案,如Core Data。
为什么在ListView Model中使用UserDefaults而不是App Storage?
-因为App Storage更适合在视图中直接使用,而ListView Model是一个类,所以在这个上下文中使用UserDefaults更为合适。
如何将Item Model转换为可以存储在UserDefaults中的数据?
-通过将Item Model转换为JSON数据。首先,需要让Item Model符合Codable协议,然后使用JSON编码器将模型数组编码为数据。
为什么需要将Item Model符合Codable协议?
-Codable协议允许数据模型被编码和解码,这意味着可以将模型转换为数据(如JSON格式),并从数据重建模型。
在ListView Model中,如何确保每次更新items数组时都保存数据?
-通过在items属性上使用计算属性,并在didSet属性观察器中调用saveItems函数来实现。
如何从UserDefaults中检索并恢复保存的任务列表?
-首先从UserDefaults中获取保存的数据,然后使用JSON解码器将数据解码回Item Model的数组,并用这个数组更新items属性。
为什么在获取UserDefaults中的数据时要使用guard语句?
-使用guard语句是为了安全地处理可选值。如果从UserDefaults中获取的数据不存在,或者无法将其解码为Item Model数组,guard语句可以防止程序崩溃,并提供一个明确的退出点。
在视频中提到的“saveItems”函数的作用是什么?
-“saveItems”函数的作用是将当前的items数组(包含待办事项)编码为JSON数据,并将其存储到UserDefaults中,以实现数据的持久化。
为什么在视频中不直接在每个修改items数组的函数末尾添加saveItems调用?
-为了代码的效率和清晰,通过在items属性的didSet属性观察器中调用saveItems,可以确保无论何时items数组被修改,都会自动保存,而不是在每个修改函数中重复添加保存逻辑。
Outlines
🔄 应用数据持久化问题
Nick在视频中介绍了他们的应用虽然已经可以正常运行,但存在一个问题:应用没有保存任何数据。这意味着,如果关闭应用再重新打开,新添加的待办事项并不会被保存。为了解决这个问题,他计划通过使用用户默认设置(UserDefaults)来保存待办事项列表,确保数据在会话之间持久化。他还提到,如果应用要上架App Store,可能会使用Core Data,但由于在Swift UI训练营中尚未涉及Core Data,因此选择使用UserDefaults。他强调UserDefaults主要用于存储较小的数据片段,如用户ID或用户名,对于待办事项列表这种数据量不大的情况,使用UserDefaults是合适的。
📝 UserDefaults的使用和数据编码
为了使用UserDefaults保存待办事项,Nick创建了一个名为saveItems的新函数。他解释说,UserDefaults无法直接存储ItemModel对象,因此需要将这些对象转换为JSON数据。他通过使ItemModel符合Codable协议,从而能够将ItemModel编码和解码为数据。在saveItems函数中,他使用JSON编码器将待办事项数组编码为数据,并将其存储在UserDefaults中。为了确保每次待办事项数组发生变化时都能保存,他在items数组上添加了一个计算属性,并在该属性的didSet属性中调用saveItems。此外,他还修改了获取待办事项的函数,以便从UserDefaults中检索数据,并将其转换回ItemModel数组。
📱 应用数据的恢复和测试
最后,Nick展示了如何从UserDefaults中恢复数据,并在模拟器中测试应用。他首先移除了用于初始化的三个假待办事项,然后通过添加新事项、保存、标记完成和编辑等操作来测试数据是否能够正确保存和恢复。他强调了使用guard语句和if let语句的重要性,这些语句在Swift中用于安全的可选值解包。通过这些步骤,他证明了应用现在能够保存待办事项,并且在重新启动后能够恢复这些数据。视频以鼓励观众继续关注和学习结尾,并邀请观众订阅频道。
Mindmap
Keywords
💡用户默认值(UserDefaults)
💡数据持久化
💡SwiftUI
💡Codable协议
💡JSON数据
💡待办事项列表(To-Do List)
💡视图模型(ViewModel)
💡计算属性(Computed Property)
💡守卫语句(Guard Statement)
💡数据模型(Data Model)
💡模拟器(Simulator)
Highlights
在课程中构建的应用程序可以正常工作,但尚未实现数据保存功能。
关闭应用程序后,新添加的待办事项不会保存。
通过使用用户默认设置(UserDefaults)来保存待办事项列表。
用户默认设置主要适用于存储较小的数据片段,例如用户ID或用户名。
如果待办事项列表很大,不应使用用户默认设置来存储。
将创建一个新的函数来保存待办事项数组。
使用JSON数据格式来存储Item模型,因为UserDefaults无法直接存储Item模型。
Item模型需要符合Codable协议,以便能够编码和解码成JSON数据。
通过编码将待办事项数组转换为JSON数据,并存储到UserDefaults中。
使用guard语句来安全地解包从UserDefaults中检索的数据。
如果从UserDefaults中成功获取数据,将使用JSON解码器将其解码回Item模型数组。
通过计算属性和didSet方法,在每次待办事项数组更改时自动保存数据。
不再使用固定的三个初始待办事项,而是从UserDefaults中获取并追加保存的待办事项。
演示了应用程序关闭后重新打开,待办事项数据仍然被保存和持久化。
提供了对guard语句和if let语句的实践,展示了它们在不同情况下的用法。
代码实现高效且简洁,展示了如何将待办事项列表保存在用户默认设置中。
感谢观看,并鼓励订阅频道,以便继续学习。
Transcripts
[Music]
what's up everyone i'm nick
and so far in this course we've built
the majority of our app our app is
totally working
but you might have noticed that it
doesn't actually save any of our data
so if we close the app and reopen the
app it doesn't save any of those
new to do items that we added so in this
video really quickly we're just going to
incorporate
user defaults so that we can save our
to-do list items so that they persist
and save between sessions
all right so i'm back in our project
and so far in this course we have done
the bulk of the code the bulk of the app
we have our app we have our screens we
can add items
to our app we can delete items
we can toggle their completion
but one thing you might have noticed is
that if we edit this list
and we close the app
and then reopen the app it defaults back
to the starting state
and right now it has that those three
item models that we create on the init
when we call get items
and all the work that we just did adding
updating items
is not saving and that's because we
haven't saved it anywhere and we're not
persisting the data
so we need a place to save our items
array
when we change it when we update it
now if this was an app that i was
putting in the app store i would
probably use
core data to do this but i haven't
covered core data in the swift ui
bootcamp
so even simpler than core data we're
just going to use user defaults
and before we get into it i want to
quickly note that user defaults
should predominantly be used for smaller
pieces of data
so something like a user id or your
current user's
name but in this case our item model is
fairly
small pieces of data it is just a title
and a boolean
and we only have a couple item models we
don't have like
thousands or a hundred thousand
different items in our to-do list
so it's not a big deal that we're using
user defaults
but if we had a larger database i just
want you guys to be aware that user
defaults should
really be used for smaller pieces of
information
and it do not start incorporating large
data sets into
user defaults but with that said user
defaults is
very easy to use and it is perfect for
what we are going to do
here so we are going to create a new
function at the bottom of our
list view model so i'm in the list view
model i'm going to go down to the bottom
and after update item i'm going to add
func save
items open close parenthesis and open
the brackets
and i did a whole video in the swiftjaw
bootcamp on app storage
and you might be wondering why we're not
using app storage in right now and
that's because we are in a class
an app storage should be used if you're
going to use it in the view directly but
since we're in a class
it's better to use user defaults so
we're going to call
userdefault.standard.set
and if we look at these value types here
that we can
add you'll notice that none of them
clearly say
item model and that's because user
defaults has no idea what an item model
is
and we can't actually save an item model
into user defaults
so i'm going to delete this quickly and
what we're going to do is basically
convert
all these item models into json
data so if you have been a developer
maybe like a web developer or something
you're probably familiar with json data
is basically just a data blob and it's
going to take our item model it's going
to convert it into this data blob
we're going to put that data into user
defaults
and then when we retrieve it we're just
going to convert it back from the data
to item models so to do that
we're going to jump into the item model
i'm going to jump to definition
and all we have to do is make this
conform to codable so i'll do comma
space
codable and in the next series i'm going
to do a whole video on codable because
there's a lot going on behind the scenes
here and this is super powerful
but all you need to know is that because
item model is now conforming to
codable we can decode and
encode this item so we can transform an
item model
into basically into data and then out of
data
so now that it's conformed to codable
let's go back
to our save items and we're going to
take
this items array here which is an array
of item model
and try to encode it into data
so very simply we'll say if let
encoded data equals
try with a question mark
we're going to create a json encoder
with an open and close parenthesis
and then on this encoder we're going to
call dot encode
and what do we want to encode here we
want to include our items array
then we're going to open the brackets
because this is an if let's statement
we have to use this try method for the
json encoder
and that basically is just going to try
to do this and it's possible that it
might fail but that's okay and that's
why we're in this if let's statement
so if this is successful we would have
created a json encoder
which which can convert things into json
data
and then we're going to encode our items
so our items array is going to convert
from an items array
into json data and that's what this
encoded data is and we're just going to
put this encoded data
into our user defaults so we'll call
userdefaults.standard.set
we'll go down to the value with any and
we're going to include our encoded data
and for key and now we need a key for
the user defaults and i'm just going to
call this
items underscore list
now we're going to have to reference
this key again when we want to pull the
data back from user defaults
so i don't like that we're typing it in
here directly because if we
later have to have to refer to this key
and maybe we
mistype it or we forget what we put here
it could run into issues
so i'm going to make this key a
standalone variable
so at the top underneath our items let's
call
let items key of type string
and we'll set it equal to items
underscore list
we're going to take this items key and
we're going to put it down here
as our 4 key now we have our function to
save items it's going to convert our
items array into data
and then put that data into user
defaults
and all we have to do now is actually
call save items
from somewhere in our code and i want to
make sure that these user defaults are
is always updated and in line with
what's going on in our list
so if we delete an item i want to call
save item
if we move an item if we add an item if
we update an item
i always want to call save items so i
could
go and add this to the end of all these
functions and that would work
but i'm going to undo this and what's
what we're really doing here is anytime
we change this
item's array so we're changing it in all
of these functions
anytime we change this items array we
want to call save items
so an even more efficient way than
adding it into each of these functions
we're going to scroll up to the items
array here
and we're going to add a computed
property so at the end of this i'm just
going to open the brackets
and then i'm going to use a swift
function called did
set and open the brackets
and basically this did set gets called
any time
we set this item's right so anytime we
change
this items array this function will get
called
and i'm just going to call in here save
items
it's that simple so if we do anything
that affects this item's array
which includes deleting moving adding
updating we're always going to call save
items which is perfect
and the last thing we need to do here is
get items
because instead of always getting these
three fake items
we actually want to take the items that
are saved in user default and then
append
those items so i'm going to highlight
all these lines
press the command and backslash to
comment them out because we don't need
them anymore
and let's try to get the items from our
user defaults
so first we need to get the data from
user defaults we'll say let data
equals userdefaults.standard.data4key
and we already have our key here because
we've created a constant
so add in items key
and if we hold the option button and
click on data
you'll see that it is optional because
there is a chance that there is nothing
saved at this
key so what we need to do is safely
unwrap this
so instead of just let data let's say
guard
let data equals this else open brackets
and return
so it's going to try to get the data
from this
key here and if it's true it's going to
run the rest of this code
if it's false it's going to return out
of this function and that's because we
need this data to move forward
and then next we need to convert this
data from
a data json blob into our array of
item models so what we're going to do is
basically the opposite of what we did
down here with our
if-let statement here we took the json
encoder and
encoded the items and now we're going to
decode with a json decoder
from the data back to items
so we'll say let saved items
equal try the question mark
json decoder open close parenthesis dot
decode from and we need to now tell it
what kind
of data type we want to decode it to
so to this decodable.protocol is and we
made our item model
conform to codeable before so we can use
item models here
but we know this saved items is an array
of item models so we'll do array of
item model and we want to be
the type of this so not an actual array
so we'll do
dot self
and then from data is our data that we
just got right here so we'll do
data if i hold the option button and
click on
saved items you'll see that it now gives
us an optional array of item
model so again this is optional i want
to make sure that we do have items
so we can add another guard let
else return
and what's kind of cool about these
guard statements is that we can actually
combine
multiple multiple of them so in this
first one we're checking that we have
data
and then the second one we're checking
that we can convert that data
into items but we can actually just
combine both of these
statements so what i'm going to do is
press enter before this let and
press enter before this else
so first we're going to say guard let
data equals this
comma and then i'm going to copy our
let's save items equals this and paste
it in here
so now this guard statement actually has
both of these combined and we can delete
the second one
so guard let data equals this let's save
items equals this
and we'll return out of the function if
we can't get the data or the items
but if we get both we will continue down
here
and now if we hold the option button and
click on
saved items it is not optional it is an
actual array of item
model so we can call self.items
equals saved items
and now our items array will be updated
with that saved data
i'm going to delete this because we
don't need it anymore you can leave it
in your code if you want
and let's click play on
the simulator and see if it works
all right so right now we have nothing
in our screen
and that's because we're not appending
those three fake items anymore
so let's start adding some items we're
going to add
let's do my first item
save bounce is back let's add another
second item save
i'm going to make this first item
completed
and then i'm going to edit them and make
the first item actually
second press done and now let's
close the app and open it up again
and now we can see that our items have
actually saved and persisted
because every time we edit these items
we
saved them to user defaults and when we
open our app we are fetching the saved
data from user defaults
and putting it back in our app so i hope
this wasn't too confusing you guys don't
have to
worry too much about if this tried
decoder decode it looks confusing
all we're doing is converting an array
of item model
to json data and then back from json
data
and i wanted to give you guys some
practice here with guard
let statements as well as if let
statements
because time we use ifled or garlic
they're kind of interchangeable so we
could have used a guard
statement here and we also could have
used an if let statement here
but now you guys have practice with both
of them and our code is looking
so efficient so clean i hope you guys
are getting excited we are almost done
with this app as always thank you guys
for watching
i'm nick this is swiffle thinking do not
forget to the subscribe button if you're
learning something if you're enjoying
this course
and stay excited and i will see you all
in the next video
Voir Plus de Vidéos Connexes
Create a custom data model for Todo items in SwiftUI | Todo List #2
Create a List of Todo items in SwiftUI | Todo List #1
User Experience and Animations in SwiftUI app | Todo List #5
Add a ViewModel with @EnvironmentObject in SwiftUI | Todo List #3
Adding an App Icon and Launch Screen to SwiftUI | Todo List #7
macOS Menu Bar App (Code Along) | SwiftUI, Xcode
5.0 / 5 (0 votes)