崩溃问题 attempt to delete item whi
代码:
let newInsertItemIdx:Int = 0
let firstItemIndexPath:NSIndexPath = NSIndexPath(forRow: newInsertItemIdx, inSection: 0)
self.tableView.reloadRowsAtIndexPaths([firstItemIndexPath], withRowAnimation: UITableViewRowAnimation.Automatic)
出错:
2015-12-02 15:28:37.409 JianDao[18264:1143873] *** Assertion failure in -[UITableView _endCellAnimationsWithContext:], /BuildRoot/Library/Caches/com.apple.xbs/Sources/UIKit_Sim/UIKit-3512.29.5/UITableView.m:1426
2015-12-02 15:28:44.998 JianDao[18264:1143873] *** Terminating app due to uncaught exception ‘NSInternalInconsistencyException’, reason: ‘attempt to delete row 0 from section 0 which only contains 0 rows before the update’
*** First throw call stack:
(
0 CoreFoundation 0x0000000110a65f45 __exceptionPreprocess + 165
1 libobjc.A.dylib 0x000000010fcfedeb objc_exception_throw + 48
2 CoreFoundation 0x0000000110a65daa +[NSException raise:format:arguments:] + 106
3 Foundation 0x000000010f94b5ee -[NSAssertionHandler handleFailureInMethod:object:file:lineNumber:description:] + 198
4 UIKit 0x000000011169b19b -[UITableView _endCellAnimationsWithContext:] + 4799
5 JianDao 0x000000010f3ae3d3 _TFFC7JianDao26ConversationViewController22addNewConversationItemFS0_FCS_16ConversationItemT_U_FT_T_ + 675
6 JianDao 0x000000010f389bd7 _TTRXFo__dT__XFdCb__dT__ + 39
7 libdispatch.dylib 0x00000001133dce5d _dispatch_call_block_and_release + 12
8 libdispatch.dylib 0x00000001133fd49b _dispatch_client_callout + 8
9 libdispatch.dylib 0x00000001133e52af _dispatch_main_queue_callback_4CF + 1738
10 CoreFoundation 0x00000001109c62e9 __CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__ + 9
11 CoreFoundation 0x00000001109878a9 __CFRunLoopRun + 2073
12 CoreFoundation 0x0000000110986e08 CFRunLoopRunSpecific + 488
13 GraphicsServices 0x0000000115106ad2 GSEventRunModal + 161
14 UIKit 0x000000011157530d UIApplicationMain + 171
15 JianDao 0x000000010f355f2d main + 109
16 libdyld.dylib 0x000000011343192d start + 1
17 ??? 0x0000000000000001 0x0 + 1
)
libc++abi.dylib: terminating with uncaught exception of type NSException
iphone – Crash on reloadRowsAtIndexPath but not on reloadData – Stack Overflow
Reloading the Table View – UITableView Class Reference
Reloads the rows and sections of the table view.
Declaration
SWIFT
func reloadData()
Discussion
Call this method to reload all the data that is used to construct the table, including cells, section headers and footers, index arrays, and so on. For efficiency, the table view redisplays only those rows that are visible. It adjusts offsets if the table shrinks as a result of the reload. The table view’s delegate or data source calls this method when it wants the table view to completely reload its data. It should not be called in the methods that insert or delete rows, especially within an animation block implemented with calls tobeginUpdatesandendUpdates.
”
感觉是:
应该把此处的:
reloadRowsAtIndexPaths
换成
reloadData
-》因为此处是datasource中的data变化了。
-》所以不应该调用reloadRowsAtIndexPaths,而应该直接用reloadData???
-》但是不会导致效率很低吗?
有点看懂了:
此处是:
对于tableView的datasource的数组:
conversationItemList
最开始conversationItemList是空的,count是0
此处之前已经调用了:
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
print("ConversationViewController numberOfRowsInSection")
return conversationItemList.count
}
所以当时是numberOfRowsInSection返回的是0
而此处虽然是已经添加数据了:
if conversationItemList.count == 0 {
conversationItemList.append(newConversationItem)
}
else {
conversationItemList.insert(newConversationItem, atIndex: newInsertItemIdx)
}
但是此时tableView并不知道你的数据源变化了
-》所以此时调用reloadRowsAtIndexPaths,发现:
section 0中,并没有数据
而reload需要
先删除delete
再添加add
所以此时delete不存在的row的话,就报错了。
-》所以,此处应该是先调用reloadData
-》让系统知道数据变化了。
iphone – Crash on reloadRowsAtIndexPath but not on reloadData – Stack Overflow
中的解释,也和我猜的一样:
“I know that it has been a while since this question was asked but I think the problem might be that, reloadRowsAtIndexPaths relies on the prior existence of those rows in the table and internally deletes, recreates and inserts them back in (under the hood). So when you are calling the specific reload without those rows already being in the table, it is trying to delete a row that is not there.
I came across the same problem with a collection view. The reason why a full reload works is because it refreshes the whole thing and does not rely on prior state, only on the current condition of your data source.
This is my take on the problem.”
[总结]
所以结论很简单:
当你之前的对应的row中的cell并存在的话
(注意:即使你数据源中的list中已经刚(通过insert或append)添加了对应的数据,但是却没有调用reloadData的话,对应的UI界面中的UITableViewCell还是不存在的)
则此时调用reloadRowsAtIndexPaths,就会出错:
因为:
reloadRowsAtIndexPaths是依赖于之前的状态的
之前的状态是还不存在对应的UITableViewCell
reloadRowsAtIndexPaths需要先去delete对应的cell,然后再去重新添加对应的cell的
解决办法是:
在添加了数据源中对应的行的数据后,先去调用reloadData
(其实也就不需要:再去调用reloadRowsAtIndexPaths)了。。。
转载自:https://www.crifan.com/swift_has_update_datasource_but_reloadrowsatindexpaths_still_attempt_to_delete_row_0_from_section_0/