gpt4 book ai didi

ios - CoreData导入和升级策略

转载 作者:行者123 更新时间:2023-12-04 19:30:03 25 4
gpt4 key购买 nike

关于CoreData有很多值得一看的地方,但是我觉得数据导入不是其中之一。我对您用于导入/升级策略的内容有一些疑问,很想听听您的意见。

关于如何提供初始数据库内容,存在一些思路。有些人会在首次运行时从文件中导入数据,而其他人会提供在第一次运行时已复制并使用的数据存储-这是我个人所做的。如果还有其他选择,我很想听听他们的意见。

这些方法中的每一个我的问题是,当您进行升级时该怎么办。当您向现有用户希望看到的初始数据集中添加/更改/删除数据后,该怎么办?

您是否将使用中的数据模型的版本存储在NSUserDefaults中,然后在首次运行新版本时执行一些迁移代码以插入/更新默认数据?我在这里严格来说是数据,而不是模式。所有这些似乎都很骇人听闻,因为我只能看到低评级浪潮的到来,因为您在编写升级代码时没有想到什么。在CoreData中存储默认的应用程序数据(用户没有真正修改)甚至是一件好事吗?

所以我想我的问题是,您首选的导入策略是什么?在发布将来的版本时,通常如何升级这些数据?

最佳答案

tl; dr 在提交任何解决方案之前,您应该考虑一下期望更新的行为。通常,任何更新都可以是完全替换或部分替换(先进行差异处理,然后再替换那些部分)。完全替换和部分替换都有其优点和缺点。两种解决方案的技术实现可能会有很大不同。

如果我正确理解这一点,则您的应用程序附带了一组初始数据。您要在新版本的应用程序中更改初始数据集。用户可能会或可能不会修改数据。
从我的角度来看,解决此问题的一种好方法取决于您的应用程序以及当前在应用程序中存储和使用默认数据的方式。
用户实体和初始实体(可能已修改)在一起
如果应用程序是使用其默认数据集创建的,则用户以后可以修改这些整体,删除这些整体,添加自己的整体,并且无法确定某个条目是初始数据集的一部分还是用户修改的条目,那么更新默认应用程序数据集将变得更加棘手,但也更加有趣。
由于您要问“如果修改数据该怎么办?”,所以我假设您也发现这种情况更有趣。
您的预期行为是什么?
就个人而言,在尝试技术解决方案之前,我会尝试定义您期望的确切行为。有些情况非常简单,例如:

  • “如果应该删除默认数据集中的一个条目并且用户已经删除了它,那么什么也不做”
  • “如果应将新条目添加到默认数据集,则将其添加”
  • “如果条目不是默认数据集的一部分,则什么也不做”。

  • 但是,这些方法有许多细微的变化,例如
  • “如果应删除默认日期集中的条目,并且用户已对其进行了修改,则...”。

  • 在这种情况下,您可能应该将数据视为用户数据的一部分,而不要对其进行修改,但是也许您有充分的理由要对其进行更新。当您开始写下这些内容时,您会清楚地看到,以前可能没有很多情况。此外,通过记下这些案例,可以记录您的决策,以便您以后可以回头查看它们。
    您对 future 有什么计划?
    一旦详细确定了数据更新的目标是什么,您就可以继续思考如何为这些目标实施解决方案。这也是开始思考 future 的好时机。如果您认为现在需要更新初始数据集,则很有可能在将来再次更新它们。也许这是个好时机,考虑以后如何使这些更新变得更容易。毕竟,这也许是一个更新架构的好时机。但也许不是。一些针对更新问题的解决方案不需要架构更新。
    为将来的数据更新而设计
    如果在考虑如何更新此数据时,您偶然有“如果只是XYZ”的感觉。然后,您可能有一个地方可以开始设计将来的更新机制。如果不了解数据的复杂性,数据的大小或更新中插入,删除和未更改的整体的大致比例,很难给出有关如何设计好的更新解决方案的具体技巧。但是,我将尝试指出要考虑的事情。
    进入非常高的抽象水平,有两种主要方法可更新一组数据:替换所有内容或计算差异并仅替换已更改的内容

    1.更换一切
    设计
    如果初始数据量非常小(即足够小而不需要高级更新机制),则可以在每次更新时简单地更新整个默认数据集。为了能够在不更改用户数据的情况下替换默认数据,您将需要将默认数据与用户数据分开(或在已经分开的情况下提供解决方案),或者至少能够识别条目是否属于其中初始数据集与否。
    将默认数据与用户数据分开
    为了能够简单地“用新的默认数据替换所有旧的默认数据”,要求可以识别并删除所有旧的数据。这可以通过几种不同的方式来完成。如果可以启发式地识别条目是否是默认数据集的一部分,可能是通过创建时的时间戳或类似的东西进行,那么就不需要进行重大修改。所有这些条目都可以标识为默认数据。如果没有,那么首先更新将更加困难。
    如上所述,您应该设计更多将来的更新。因此,如果您不能确定默认数据集中的数据是什么,以及用户数据是什么,那么您可能应该修改模型,以便可以通过某种方式将其分离。一个简单的布尔值是一个很小的修改。
    值得注意的是,由于Core Data在关系建立之后会在后台进行大量工作,并根据每个关系的删除规则采取行动,因此删除大型Core Data可能会非常缓慢。如果删除整个数据集,则很有可能将默认数据分离到自己的存储中,即将其自己的SQLite文件放在磁盘上。然后,可以删除整个SQLite文件,因为其中的所有实体都将被删除。但是,这将增加解决方案的复杂性,因此请在做出任何性能决定之前测量一次删除所花费的时间。
    那修改的条目呢?
    如上所述,修改后的实体在更新时可以完成一些不同的操作,并且取决于是否应将修改后的实体视为用户实体,必须更改这些实体,以使它们显示为用户实体。用户实体使用更新机制(即删除所有默认实体的事物)。
    (附带说明:应该将经过修改然后又修改回其原始值的默认实体视为用户实体还是默认实体?我们如何跟踪此类更改?)
    更新步骤
    根据初始数据是否单独存储以及是否选择分离初始数据,可能需要首次迁移。如果无法确定默认集合中包含哪些数据,则可能还需要进行迁移。迁移后,如果需要,可以分别更新其初始数据,而无需迁移以用于将来的数据更新。
    根据确切的解决方案,有可能在后台使用父/子上下文进行更新。在解决方案2(“diff”)中对此进行了进一步描述。
    优点:
  • 编写
  • 的代码更少
  • 通过替换所有
  • 可以处理任何复杂的数据

    缺点:
  • 可能需要迁移才能从用户数据
  • 中拆分默认数据
  • 在更新数据
  • 时,可能会导致默认数据集中已被删除或修改的条目重新出现
  • 可能是更复杂的数据模型
  • 在大型数据集上的表现会很差

  • 2.只补差价
    设计
    根据数据的复杂程度以及更新中更改后的条目与未更改的条目的比率,适合少量更改后的条目的一种设计可能是单独存储所有更新。但是,这要求可以用这种方式描述所有更新。如果您知道旧的默认数据集和新的默认数据集之间的区别,那么所有更新都可以描述为删除,插入或修改。
    (这类似于版本控制系统的工作方式:不是复制整个文件(而是进行版本控制),而是仅添加修改(“diff”)。在更新的情况下,您不保留过时的数据,而是替换好处是相似的。更新时间与更新的大小成正比,而不与数据的总大小成正比。)
    插入物
    插入可能是最简单的插入。通过存储所有要单独插入的新条目,可以对其进行迭代并添加到用户数据中。
    删除内容
    只要可以唯一地标识整个对象,并且可以确保没有以任何方式对其进行修改,则删除同样容易。通过存储必要的信息以唯一地标识实体并确保未对其进行修改。这些条目可以从核心数据中获取和删除。
    修改
    根据更改的复杂程度,修改后的条目可能非常棘手。单值修改几乎是微不足道的,但关系修改带来了许多新问题,在进一步研究之前,应先加以考虑(如上)。
    如何存储更新?
    您可能已经注意到,对于如何存储这些更新,我一直含糊不清。因为那也取决于手头的需求和资源。一个简单的解决方案是以某种方式将它们作为预先填充的数据包括在更新的应用程序中。但是,不必将更新存储在设备本身上。如果所有更新的总大小足够小,则可以将它们放在服务器上并在后台下载到设备。将更新存储在服务器上可带来巨大的好处,即无需更新应用程序本身即可将新更新推送到数据中。
    无论如何,无论是否下载更新,一旦更新存储在设备上,就应该以某种方式存储它们。它们可以存储在应用程序中的另一个Core Data模型中,在这种情况下,您不必进行迁移,因为更新是另一个模型中的实体。将更新存储在平面文件或任何其他非核心数据方式中也具有此优势。
    确定如何存储更新与首先确定如何存储任何类型的数据类似。它应类似于您决定将Core Data用作主要数据的过程。
    更新步骤
    当用户启动更新的应用程序时,由于不必更改模型本身,因此无需锁定UI即可进行长时间迁移。假设更新已经以某种方式存储在设备上并存储在可以在后台进行迭代的位置。如果您仅针对iOS 5,则可以使用父/子上下文设置在后台对Core Data进行更新。 Core Data for Mac, iPhone & iPad Update中的 iDeveloper.tv是用于在Core Data中进行后台导入的一个很好的资源。当然,还有“核心数据的新功能” WWDC视频,其中也涵盖了父/子上下文设置。
    如果采用这样的解决方案,则可以创建一个后台上下文,并在其中对低优先级队列进行所有修改。根据要更新的数据量,我将分批保存对“真实” Core Data上下文的所有修改,还可以删除更新表中已处理的实体。这样,如果更新花费了很长时间并且用户退出了,或者如果应用程序在其中途崩溃,则整个更新过程将能够恢复到原来的状态。
    通常,没有限制如何批量插入或删除大量数据,最好分批保存,并以某种方式指示已经处理了哪些数据,以便应用程序可以恢复导入/删除。每次输入后都不必保存。如果应用程序崩溃了并且一些条目无法保存,那么如果可以在处理这些条目之前再次进行处理并再次处理它们,那仍然是一个巨大的胜利。通过指示某些数据仅在保存后才进行处理,此导入可以知道在哪里恢复而不丢失任何数据。
    如果使用要插入/删除/修改的数据列表:通过将更改后的实体表示保存在Core Data中后从这些列表中删除实体,更新机制可以跟踪尚未处理的插入/更新/删除。
    一旦所有更新都保存到“真实”上下文中,那么您将只剩下一个空的更新列表。
    注意:在父/子上下文中,您将不得不在一个或另一个位置保存“主”上下文,因为它是唯一实际将数据持久保存到磁盘的上下文。其他保存仅在内存中。
    优点:
  • 对于较小的更新或大量的未更改数据,性能更高。
  • 可能要为更新
  • 传输/存储的数据量很小
  • (如果下载更新)可以更新默认数据,而不必更新应用程序

  • 缺点:
  • 编写
  • 的大量代码
  • 在迁移“正常”模型以使两个模型保持同步时,将需要迁移“更新”模型。

  • 我注意到这个答案比我最初打算的要长。我意识到我试图在解决方案中保持非常笼统的含义,但这对于您的解决方案可能不够精确。如果您愿意,您可以评论我的答案,并添加有关您的问题和约束的更多详细信息。这样,我也许可以更好地满足您的需求。

    关于ios - CoreData导入和升级策略,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8661423/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com