2017-08-23 4 views
0

申し訳ありませんが、私はIOSを学ぶ初心者です。
私は自分のtableViewとリロードデータに関する問題があります。
「getData」を頻繁に呼び出すと、クラッシュしてエラーが発生します。
しかし、データがクラッシュする場所はわかりません。
私は最初にreloadDataを呼び出して、次にグローバル・スレッドでlist.countが変更されていると思います。
これを避けるためのアドバイスはありますか?
ありがとうございます。

GCDの主要脅威の「tableView.reloadData」を頻繁に呼び出すとクラッシュエラーが発生する「インデックスが範囲外です」

クラッシュログ:

fatal error: Index out of range 

モデル:

class ChatroomList:Model { 

    var all:[Chatroom] { 
    var rooms:[Chatroom] = [Chatroom]() 
    self.chatrooms.forEach({ (id,chatroom) in 
     if showType.contains(chatroom.type) { 
      rooms.append(chatroom) 
     } 
    }) 
    return rooms 
    } 
} 

のViewController:

import RxCocoa 
import RxSwift 
import Alamofire 

class ListViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {      

    let chatrooms:ChatroomList = ChatroomList() 
    var list:[Chatroom] = [Chatroom]() 
    var subscribe:Disposable? 

    override func viewDidLoad() { 
    super.viewDidLoad() 

    self.tableView.dataSource = self 
    self.tableView.delegate = self 

    } 

    override func viewWillAppear(_ animated: Bool) { 
     super.viewWillAppear(animated) 

     subscribe = rooms.notifySubject.subscribe({ json in 
       self.getData() //here is called frequently 
     }) 
     self.getData() 
    } 

    override func viewWillDisappear(_ animated: Bool) { 
     super.viewWillDisappear(animated) 

     subscribe?.dispose() 
    } 

    func getData() { 

     var idList:[String] = [] 

     self.list.removeAll() 
     self.list = chatrooms.all 

     guard self.list.isEmpty == false else { 
      return 
     } 

     DispatchQueue.global().async() { 

      self.list.sort(by: { (a,b) in 
       if a.message.datetime.isEmpty { 
        return false 
       } 

      return a.message.datetime > b.message.datetime 
      }) 

      self.list = self.list.filter { (chatroom) -> Bool in 
       if chatroom.id.isEmpty { 
        return true 
       } 
       if idList.contains(chatroom.id) { 
        return false 
       } 
       idList.append(chatroom.id) 
       return true 
      } 

      DispatchQueue.main.sync() { 

       self.tableView.reloadData() 
     } 
     } 
    } 
} 
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { 
    return list.count 
} 

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { 

    if list[indexPath.row].type == .city { 

     let cell: ChatroomCityTableViewCell = ChatroomCityTableViewCell(style: .default, reuseIdentifier: nil) 

     cell.loadByCityChatroom(chatroom: list[indexPath.row], cityId: list[indexPath.row].cityId) 

     return cell 
    }else{ 

     let cell: ChatroomTableViewCell = ChatroomTableViewCell(style: .default, reuseIdentifier: nil) 
     cell.loadByChatroom(chatroom: list[indexPath.row]) 

     return cell 
    } 
} 
+0

グローバルキューの括弧内でメインキュークロージャを移動する必要があります。また、グローバルキューasync – Woof

+0

を作成する必要がありますが、tableView.reloadDateはグローバルキューで有効ですか? – Beginnerrrrrr

+0

DispatchQueue.global()。async()で試してください。 –

答えて

1

問題が最も可能性の高いあなたが現在(GCDをどのように使用するかによって引き起こされますグランドセントラルディスパtch)。

リロードすると、tableViewは、行数やこれらの行のセルなど、さまざまな質問をします。これらの呼び出しの1つの間でデータが変更されると、データをもはや表さない行を追加または削除しようとしたために矛盾の例外が発生します。

getData関数が任意の時点でリストを変更できる間にメインスレッドでtableViewを非同期に再ロードすると、上記のエラーが発生します。

解決方法は簡単ではありません。テーブルビューのデータをリロードしている間は変更されないようにリストを更新する方法を再考する必要があります。

func getData() { 
    // You cannot clear or change self.list here 

    guard !chatrooms.all.isEmpty else { return } 

    DispatchQueue.global().async() { 
     let updatedData = process(newData: self.chatrooms.all) 

     DispatchQueue.main.sync() { 
      self.list = updatedData 
      self.tableView.reloadData() 
     } 
    } 
} 

private func process(newData data: [Chatroom]) -> [Chatroom] { 
    // Do all your logic without making any changes to self.list 
} 

キーが同期リロードする前に、メインスレッドジュスト上以外のtableViewを再ロードする際に使用されているデータに変更を加えることはありませんすることです:あなたが試みることができる

一つのことのような何かを行うことです。

+0

申し訳ありません@Kedio、クラッシュも起こります。 – Beginnerrrrrr

+0

@Beginnerrrrrそれはあなたが望むものではないかもしれませんが、デバッグ目的のためです:あなたはクラッシュなしで期待される結果を得るためにDispatchQueue呼び出しを完全に削除できますか? – Kedio

+0

私は試してみますが、ソートとフィルタのデータがあるので、アプリの使用が非常に遅くなります。 – Beginnerrrrrr

関連する問題