最新消息:20210816 当前crifan.com域名已被污染,为防止失联,请关注(页面右下角的)公众号

[基本解决]swift中给TableView中插入一行并滚动到对应的行

Swift crifan 3747浏览 0评论

对于tableview中,在某个位置

可能是中间某个位置

也可能是最后

插入一行

然后最后是通过:

messageTableView.reloadData()

搞定了数据的刷新问题。

因为之前没发用:

reloadRowsAtIndexPaths

否则会出错:

[已解决]swift中已更新对应行的数据源但tableView的reloadRowsAtIndexPaths却还是出错崩溃:attempt to delete row 0 from section 0 which only contains 0 rows before the update

现在还是希望去搞懂:

对于新的insert的row,

如何在reloadData之后

去scroll到对应位置

去参考:

[已解决]Swift中如何在TableView的最后添加一行cell并且滚动到底部

去试试:

结果直接去insert并scroll:

        //first do reload table data
//        msgTVC.messageTableView.reloadData()
       
       
//then do scroll
        dispatch_async(dispatch_get_main_queue(), { () -> Void in
           
//scroll to that row
            msgTVC.messageTableView.beginUpdates()
           
let insertedRowIndexPath:NSIndexPath = NSIndexPath(forRow: insertedRowIdx, inSection: 0)
           
print("insertedRowIndexPath=\(insertedRowIndexPath)")
            msgTVC.
messageTableView.insertRowsAtIndexPaths(
                [insertedRowIndexPath],
                withRowAnimation:
UITableViewRowAnimation.Automatic)
            msgTVC.
messageTableView.endUpdates()
           
            msgTVC.
messageTableView.scrollToRowAtIndexPath(insertedRowIndexPath, atScrollPosition: UITableViewScrollPosition.Middle, animated: true)
        })

还是insert时就出错:

Terminating app due to uncaught exception ‘NSInternalInconsistencyException’, reason: ‘Invalid update: invalid number of rows in section 0.  The number of rows contained in an existing section after the update (2) must be equal to the number of rows contained in that section before the update (0), plus or minus the number of rows inserted or deleted from that section (1 inserted, 0 deleted) and plus or minus the number of rows moved into or out of that section (0 moved in, 0 moved out).’

加了reloadData:

        msgTVC.messageTableView.reloadData()

也还是同样错误。

swift tableview insert row and scroll

ios – inserting row at bottom in uitableview swift – Stack Overflow

iphone – Keep uitableview static when inserting rows at the top – Stack Overflow

Inserting row at bottom in uitableview swift – www.scriptscoop.net

Programmatic UITableView Scrolling – Grok Swift

最后经过,调试,两种办法都是可以:

第一种是:

插入新的行对应的数据之后,再在主界面的线程中reloadData和滚动到对应的新插入的行

代码如下:

        //method 1: insert data and reloadData, and scroll
       
       
//insert to correct position according datetime
        var insertedRowIdx:Int = 0
       
var hasInserted:Bool = false
       
for (curIdx, curMessage) in msgTVC.messageList.enumerate() {
           
print("[\(curIdx)] newMessage.timestamp=\(newMessage.timestamp), curMessage.timestamp=\(curMessage.timestamp), newMessage.text=\(newMessage.text)")
           
if newMessage.timestamp < curMessage.timestamp {
                msgTVC.
messageList.insert(newMessage, atIndex: curIdx)
                insertedRowIdx = curIdx
                hasInserted =
true
               
break
            }
        }
       
       
if !hasInserted {
            msgTVC.
messageList.append(newMessage)
            insertedRowIdx = msgTVC.
messageList.count 1
            hasInserted =
true
        }
       
       
//reload table data
        dispatch_async(dispatch_get_main_queue(), { () -> Void in
            msgTVC.
messageTableView.reloadData()
           
           
let insertedRowIndexPath:NSIndexPath = NSIndexPath(forRow: insertedRowIdx, inSection: 0)
           
print("insertedRowIndexPath=\(insertedRowIndexPath)")
           
//scroll to that row
            msgTVC.messageTableView.scrollToRowAtIndexPath(insertedRowIndexPath, atScrollPosition: UITableViewScrollPosition.Middle, animated: true)
        })

其中:

由于reloadData是对于整个列表的数据都刷新的

-》感觉应该是效率不是太高

-》虽然官网文档中说了,只是刷新显示那些当前处于可见的行

-》但是至少还是刷新多行的

-》感觉应该是下面的,只刷新当然新插入的行,效率更高些

第二种是:

确保都处于主界面线程中:

先去:beginUpdates

再去插入数据源中新行的数据:messageList.insert或messageList.append

然后再去插入(界面中的)新的行:insertRowsAtIndexPaths

最后再去:endUpdates

之后就可以(随意的,按照你所希望的)去滚动到对应的新插入的行了:

scrollToRowAtIndexPath

        //method 2: insert data and row, then scroll
        //insert/append and scroll
        dispatch_async(dispatch_get_main_queue(), { () -> Void in
           
//1. beginUpdates
            msgTVC.messageTableView.beginUpdates()

            //2. insert new data for tablview row
            //insert to correct position according datetime
            var insertedRowIdx:Int = 0
           
           
//TODO: calculate correct index position, not in main UI thread, to improve perfomance
            var hasInserted:Bool = false
           
for (curIdx, curMessage) in msgTVC.messageList.enumerate() {
               
print("[\(curIdx)] newMessage.timestamp=\(newMessage.timestamp), curMessage.timestamp=\(curMessage.timestamp), newMessage.text=\(newMessage.text)")
               
if newMessage.timestamp < curMessage.timestamp {
                    msgTVC.
messageList.insert(newMessage, atIndex: curIdx)
                    insertedRowIdx = curIdx
                    hasInserted =
true
                   
break
                }
            }

            if !hasInserted {
                msgTVC.
messageList.append(newMessage)
                insertedRowIdx = msgTVC.
messageList.count 1
                hasInserted =
true
            }
           
           
//3. insert new row for tablview cell
            let insertedRowIndexPath:NSIndexPath = NSIndexPath(forRow: insertedRowIdx, inSection: 0)
           
print("insertedRowIndexPath=\(insertedRowIndexPath)")
            msgTVC.
messageTableView.insertRowsAtIndexPaths(
                [insertedRowIndexPath],
                withRowAnimation:
UITableViewRowAnimation.Automatic)
           
//4. endUpdates
            msgTVC.messageTableView.endUpdates()
           
           
//scroll to that row
            msgTVC.messageTableView.scrollToRowAtIndexPath(insertedRowIndexPath, atScrollPosition: UITableViewScrollPosition.Middle, animated: true)

        })

即可。

两种方式,都不会再出现那种NSInternalInconsistencyException的错误了。

都可以正常刷新对应的新的列表的行,且滚动到对应的新插入的行的位置了。

如图:

新收到的消息,插入到最底部,现在可以滚动到最底部了:

[后记 2015-12-15]

后来发现,先去执行:

messageList.insert

再去:

beginUpdates+insertRowsAtIndexPaths+endUpdates

以及:

scrollToRowAtIndexPath

是可以的:

        // insert new data for tablview row
        //insert to correct position according datetime
        var insertedRowIdx:Int = 0
       
       
var hasInserted:Bool = false
       
for (curIdx, curMessage) in msgTVC.messageList.enumerate() {
           
print("[\(curIdx)] newMessage.timestamp=\(newMessage.timestamp), curMessage.timestamp=\(curMessage.timestamp), newMessage.text=\(newMessage.text)")
           
if newMessage.timestamp < curMessage.timestamp {
                msgTVC.
messageList.insert(newMessage, atIndex: curIdx)
                insertedRowIdx = curIdx
                hasInserted =
true
               
break
            }
        }
       
       
if !hasInserted {
            msgTVC.
messageList.append(newMessage)
            insertedRowIdx = msgTVC.
messageList.count 1
            hasInserted =
true
        }
       
       
//method 3: insert data and row, then scroll
        //insert/append and scroll
        dispatch_async(dispatch_get_main_queue(), { () -> Void in
           
//1. beginUpdates
            msgTVC.messageTableView.beginUpdates()
           
           
//2. insert new row for tablview cell
            let insertedRowIndexPath:NSIndexPath = NSIndexPath(forRow: insertedRowIdx, inSection: 0)
           
print("insertedRowIndexPath=\(insertedRowIndexPath)")
            msgTVC.
messageTableView.insertRowsAtIndexPaths(
                [insertedRowIndexPath],
                withRowAnimation:
UITableViewRowAnimation.Automatic)
           
//3. endUpdates
            msgTVC.messageTableView.endUpdates()
           
           
//scroll to that row
            msgTVC.messageTableView.scrollToRowAtIndexPath(insertedRowIndexPath, atScrollPosition: UITableViewScrollPosition.Bottom, animated: false)
        })

不会报错的。

而之前为何出错,则估计是insert参数有误?

结果后续测试发现,

scrollToRowAtIndexPath

却又出错了。。。

insertedRowIndexPath=<NSIndexPath: 0xc000000000000016> {length = 2, path = 0 – 0}
2015-12-15 17:45:38.442 JianDao[34102:1771517] *** Terminating app due to uncaught exception ‘NSRangeException’, reason: ‘-[UITableView _contentOffsetForScrollingToRowAtIndexPath:atScrollPosition:]: row (0) beyond bounds (0) for section (0).’
*** First throw call stack:
(
0   CoreFoundation                      0x000000010edd9e65 __exceptionPreprocess + 165
1   libobjc.A.dylib                     0x0000000111180deb objc_exception_throw + 48
2   CoreFoundation                      0x000000010edd9d9d +[NSException raise:format:] + 205
3   UIKit                               0x000000010fd9e059 -[UITableView _contentOffsetForScrollingToRowAtIndexPath:atScrollPosition:] + 1445
4   UIKit                               0x000000010fd9ed7e -[UITableView scrollToRowAtIndexPath:atScrollPosition:animated:] + 39
5   JianDao                             0x000000010e11b26c _TTSf2n_d_i___TFFC7JianDao26ConversationViewController22insertMessageAndScrollFS0_FTCS_7Message6msgTVCCS_26MessageTableViewController_T_U_FT_T_ + 748

搜:

swift insert new cell

swift scroll after insert new cell

swift scroll after insert   cell

iphone – Scroll to last UITableViewCell using scrollToRowAtIndexPath:atScrollPosition:animated using NSFetchedResultsControllerDelegate methods – Stack Overflow

UITableView 在顶部insertRowsAtIndexPaths 后,如何保持当前位置不变 | iOS开发 – CocoaChina CocoaChina_让移动开发更简单

swift scrollToRowAtIndexPath insertRowsAtIndexPaths contentOffsetForScrollingToRowAtIndexPath

ios – Best way to select a row after inserting it? – Stack Overflow

UITableView _contentOffsetForScrollingToRowAtIndexPath:atScrollPosition: How to solve This issue?

swift scrollToRowAtIndexPath contentOffsetForScrollingToRowAtIndexPath

ios – Swift 1.2: UITableView.reloadData() Isn’t called quick enough. How can I make sure the data is loaded before I scroll? – Stack Overflow

斯威夫特1.2:UITableView.reloadData()不是足够快。我怎么能确保数据加载滚动? – Swift 1.2: UITableView.reloadData() Isn’t called quick enough. How can I make sure the data is loaded before I scroll?IT怪 挨踢怪 28印象 二八印象

iphone – error with scrollToRowAtIndexPath – Stack Overflow

swift contentOffsetForScrollingToRowAtIndexPath

ios – Xcode – [UITableView _contentOffsetForScrollingToRowAtIndexPath:atScrollPosition:]: row (7) beyond bounds (0) for section (0).’ – Stack Overflow

Ray Wenderlich | Tutorials for Developers and Gamers

说是collection view的bug

-》感觉此处好像也是UITableView的bug。。。

结果代码都改为了:

当list有row时,且确保要滚动的位置小于最大row:

            //scroll to that row
            //Terminating app due to uncaught exception ‘NSRangeException’, reason: ‘-[UITableView _contentOffsetForScrollingToRowAtIndexPath:atScrollPosition:]: row (0) beyond bounds (0) for section (0).’
            let messageListCount:Int = msgTVC.messageList.count
           
print("messageListCount=\(messageListCount)")
           
let curMaxRowNum:Int = msgTVC.tableView(msgTVC.messageTableView, numberOfRowsInSection: 0)
           
print("curMaxRowNum=\(curMaxRowNum)")
           
if curMaxRowNum > 0 {
               
let curMaxRowIdx:Int = curMaxRowNum – 1
               
print("curMaxRowIdx=\(curMaxRowIdx)")
               
if insertedRowIndexPath.row <= curMaxRowIdx {
                msgTVC.
messageTableView.scrollToRowAtIndexPath(insertedRowIndexPath, atScrollPosition: UITableViewScrollPosition.Bottom, animated: false)
                }
            }
else {
               
print("can not scroll to that row, due to still not updated table data")
            }

然后确保list中count也是1了:

messageListCount=1
MessageTableViewController numberOfRowsInSection
curMaxRowNum=1
(lldb) po msgTVC.messageList.count
1
curMaxRowIdx=0

却还是出错:

Terminating app due to uncaught exception ‘NSRangeException’, reason: ‘-[UITableView _contentOffsetForScrollingToRowAtIndexPath:atScrollPosition:]: row (0) beyond bounds (0) for section (0).’

swift row (0) beyond bounds (0) for section (0)

iphone – UITableView scrollToRowAtIndexPath – Stack Overflow

swift insertRowsAtIndexPaths NSInternalInconsistencyException reason Invalid update: invalid number of rows in section 0

iphone – NSInternalInconsistencyException (invalid number of rows) – Stack Overflow

最后的最后,用的是如下代码:

        //method 1: insert data and reloadData, and scroll
       
       
//insert to correct position according datetime
        var insertedRowIdx:Int = 0
       
var hasInserted:Bool = false
       
for (curIdx, curMessage) in msgTVC.messageList.enumerate() {
           
print("[\(curIdx)] newMessage.timestamp=\(newMessage.timestamp), curMessage.timestamp=\(curMessage.timestamp), newMessage.text=\(newMessage.text)")
           
if newMessage.timestamp < curMessage.timestamp {
                msgTVC.
messageList.insert(newMessage, atIndex: curIdx)
                insertedRowIdx = curIdx
                hasInserted =
true
               
break
            }
        }
       
       
if !hasInserted {
            msgTVC.
messageList.append(newMessage)
            insertedRowIdx = msgTVC.
messageList.count 1
            hasInserted =
true
        }
       
        msgTVC.
messageTableView.reloadData()

        //reload table data
        dispatch_async(dispatch_get_main_queue(), { () -> Void in
           
let insertedRowIndexPath:NSIndexPath = NSIndexPath(forRow: insertedRowIdx, inSection: 0)
           
print("insertedRowIndexPath=\(insertedRowIndexPath)")
           
//            //scroll to that row
//            msgTVC.messageTableView.scrollToRowAtIndexPath(insertedRowIndexPath, atScrollPosition: UITableViewScrollPosition.Middle, animated: true)

//            let messageListCount:Int = msgTVC.messageList.count
//            print("messageListCount=\(messageListCount)")
//            if messageListCount > 0 {
//                let lastRowIndexPath:NSIndexPath = NSIndexPath(forRow: messageListCount – 1, inSection: 0)
//                print("lastRowIndexPath=\(lastRowIndexPath)")
//                msgTVC.messageTableView.scrollToRowAtIndexPath(lastRowIndexPath, atScrollPosition: UITableViewScrollPosition.Bottom, animated: false)
//            }

           
let curMaxRowNum:Int = msgTVC.messageTableView.numberOfRowsInSection(0)
           
print("curMaxRowNum=\(curMaxRowNum)")
           
if curMaxRowNum > 0 {
               
let curMaxRowIdx:Int = curMaxRowNum – 1
               
print("curMaxRowIdx=\(curMaxRowIdx)")
               
if (insertedRowIndexPath.row <= curMaxRowIdx) {
                    msgTVC.
messageTableView.scrollToRowAtIndexPath(insertedRowIndexPath, atScrollPosition: UITableViewScrollPosition.Bottom, animated: false)
                }
            }
else {
               
print("can not scroll to that row, due to still not updated table data")
            }

        })

暂时可以工作,没有挂掉。

转载请注明:在路上 » [基本解决]swift中给TableView中插入一行并滚动到对应的行

发表我的评论
取消评论

表情

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址
84 queries in 0.193 seconds, using 22.41MB memory