菜鸟教程小白 发表于 2022-12-11 19:48:47

ios - NSFetchedResultsController - 用户驱动的更改


                                            <p><h1>概述</h1>

<ul>
<li>我有一个 <code>NSFetchedResultsController</code></li>
<li>用户将能够添加新记录(<strong>编辑模式下的表格 View </strong>)</li>
<li>当用户点击添加按钮时,我能够检测到事件并创建一个新的 <code>Car</code>(<code>NSManagedObject</code> 的子类,与 <code>NSFetchedResultsController</code>的谓词)</li>
</ul>

<h1>问题:</h1>

<ul>
<li>当用户发起操作时,如何在表格 View 中插入新行?</li>
<li>根据我当前的实现,应用崩溃了。崩溃消息如下。</li>
<li>如何准确检测模型更改何时生效? (根据崩溃消息,我觉得我插入行太早了)</li>
</ul>

<h1>注意:</h1>

<ul>
<li>我知道 <code>NSFetchedResultsControllerDelegate 检测到模型更改</code>,但问题是模型已更新,我需要表格 View 来匹配它。</li>
<li>通常 <code>NSFetchedResultsControllerDelegate</code> 会检测模型更改,我可以使用委托(delegate)方法进行更新。</li>
<li>我的问题是,既然用户添加了行,那么首先更新模型,然后表格 View 必须根据它进行调整。</li>
</ul>

<p>引用:<a href="https://developer.apple.com/documentation/coredata/nsfetchedresultscontrollerdelegate" rel="noreferrer noopener nofollow">https://developer.apple.com/documentation/coredata/nsfetchedresultscontrollerdelegate</a> </p>

<h1>NSFetchedResultsController 的创建:</h1>

<pre><code>let fetchRequest : NSFetchRequest&lt;Car&gt; = Car.fetchRequest()

fetchRequest.predicate = NSPredicate(format: &#34;color = %@&#34;, argumentArray: [&#34;green&#34;])

let orderIDSortDescriptor = NSSortDescriptor(keyPath: \Car.price, ascending: true)

fetchRequest.sortDescriptors =

fetchedResultsController = NSFetchedResultsController(fetchRequest: fetchRequest,
                                                      managedObjectContext: context,
                                                      sectionNameKeyPath: nil,
                                                      cacheName: nil)
</code></pre>

<h1>编辑风格</h1>

<pre><code>override func tableView(_ tableView: UITableView,
                        editingStyleForRowAt indexPath: IndexPath) -&gt; UITableViewCellEditingStyle {

    let newCarIndex = fetchedResultsController?.fetchedObjects?.count ?? 0

    let editingStyle : UITableViewCellEditingStyle

    switch indexPath.row {

    case newCarIndex:
      editingStyle = .insert

    default:
      break            
    }

    return editingStyle
}
</code></pre>

<h1>提交用户操作</h1>

<pre><code>override func tableView(_ tableView: UITableView,
                        commit editingStyle: UITableViewCellEditingStyle,
                        forRowAt indexPath: IndexPath) {

    switch editingStyle {

    case .insert:
      createGreenCar(at: indexPath) //Creating a new Car with color = Green
      tableView.insertRows(at: , with: .automatic) //This causes the app to crash
    default:
      break
    }
}
</code></pre>

<h1>崩溃错误信息:</h1>

<p><code>由于未捕获的异常“NSInternalInconsistencyException”而终止应用程序,原因:“无效更新:第 1 节中的行数无效。更新后现有节中包含的行数 (1) 必须等于更新前该节中包含的行数 (1),加上或减去从该节插入或删除的行数(1 插入,0 删除),加上或减去移入或移出该节的行数( 0 移入,0 移出)。'</code></p></p>
                                    <br><hr><h1><strong>Best Answer-推荐答案</ strong></h1><br>
                                            <p><p>感谢@Jake 和@pbasdf,他们的建议帮助我发现并纠正了问题。</p>

<p>我正在回答完整性。</p>

<h1>根本原因:</h1>

<p>我的表格 View 中有多个部分,我将行插入错误的部分。因此,当模型发生变化时,相关部分中的表格 View 行数并没有发生变化。</p>

<h1>接近用户驱动的更新:</h1>

<h1>1。使用数组</h1>

<p>我觉得将结果转换成一个数组并使用数组作为数据源而不是 <code>NSFetchedResultsController</code> 来进行用户驱动的更新会更好。</p>

<h2>2。使用 NSFetchedResultsController:</h2>

<p>当用户插入/删除/移动行时<code>UITableViewDataSource</code>方法被调用:</p>

<ul>
<li>当用户插入/删除行时<code>tableView(_:commit:forRowAt:)</code>会被调用</li>
<li>当用户移动行时 <code>tableView(_:moveRowAt:to:)</code> 会被调用</li>
<li>为上述方法相应地更新核心数据</li>
</ul>

<p>更新核心数据会导致<code>NSFetchedResultsControllerDelegate</code>被调用</p>

<ul>
<li>在 <code>controller(_:didChange:at:for:newIndexPath:)</code> 中执行以下操作:

<ul>
<li>对于插入 - 添加 indexPaths</li>
<li>对于删除 - 删除 indexPaths</li>
<li>对于移动 - 什么都不做,因为 UI 已经是最新的(用户已经移动了行),稍后在 <code>controllerDidChangeContent(_:)</code> 调用 <code>tableView.reloadData()</code> 延迟 <strong>0.5 秒</strong>。</li>
</ul></li>
</ul>

<h3>注意:</h3>

<p>当用户在 <code>iOS 11.2</code> 上移动该行(使用 <code>NSFetchedResultsController</code>)时,我确实遇到了以下警告:</p>

<pre><code>UITableView internal inconsistency: _visibleRows and _visibleCells must be of same length. _visibleRows
</code></pre>

<p>我不知道如何解决它,所以暂时坚持使用数组实现。</p></p>
                                   
                                                <p style="font-size: 20px;">关于ios - NSFetchedResultsController - 用户驱动的更改,我们在Stack Overflow上找到一个类似的问题:
                                                        <a href="https://stackoverflow.com/questions/49070451/" rel="noreferrer noopener nofollow" style="color: red;">
                                                                https://stackoverflow.com/questions/49070451/
                                                        </a>
                                                </p>
                                       
页: [1]
查看完整版本: ios - NSFetchedResultsController - 用户驱动的更改