2016-11-01 58 views
3

剛開始使用Realm進行iOS項目時,我查看了示例和文檔,但似乎無法弄清楚如何獲取Realm結果數組的細粒度通知。將通知添加到領域結果數組

例如,如果它只是一個結果對象,你可以做到這一點

// Observe Results Notifications 
notificationToken = results.addNotificationBlock { [weak self] (changes: RealmCollectionChange) in 
    guard let tableView = self?.tableView else { return } 
    switch changes { 
    case .initial: 
    // Results are now populated and can be accessed without blocking the UI 
    tableView.reloadData() 
    break 
    case .update(_, let deletions, let insertions, let modifications): 
    // Query results have changed, so apply them to the UITableView 
    tableView.beginUpdates() 
    tableView.insertRows(at: insertions.map({ IndexPath(row: $0, section: 0) }), 
         with: .automatic) 
    tableView.deleteRows(at: deletions.map({ IndexPath(row: $0, section: 0)}), 
         with: .automatic) 
    tableView.reloadRows(at: modifications.map({ IndexPath(row: $0, section: 0) }), 
         with: .automatic) 
    tableView.endUpdates() 
    break 
    case .error(let error): 
    // An error occurred while opening the Realm file on the background worker thread 
    fatalError("\(error)") 
    break 
    } 
} 

,這只是正常的無段正常的tableview,因爲它只是插入新電池放入一節0

然而,看看GroupedTableView(有些章節的tableview)的例子,他們只是簡單地向Realm對象本身添加一個通知塊。它通知你的任何變化,而不是特定的插入/缺失等

像這樣:

// Set realm notification block 
    notificationToken = realm.addNotificationBlock { [unowned self] note, realm in 
     self.tableView.reloadData() 
    } 

雖然這個作品,它確實是不是最好的解決方案,因爲你不可能像iOS的所提供的漂亮的動畫自由。

我的問題其實只是,我怎麼能添加細粒度通知結果

var objectsBySection = [Results<DemoObject>]()

數組我想過通過數組循環並添加通知塊每個結果對象,但是由於新的Result對象可以添加到這個2D數組中,所以這看起來不是一個好的解決方案。

有沒有人有經驗使用Realm具有動態增長的部分/單元格的分段tableview?

~~~~~~~~~~~~~更新與答案~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~

所以感謝@bogdanf,我找到了解決辦法。我在這裏發佈我的解決方案,因爲它和@bogdanf的建議不完全一樣,但是他的回答讓我看到了解決方案。

首先,在我的應用程序部分並不完全是無限的。添加對象時用戶添加到它們,但它們的數量是有限的。 I.e我可以創建一個數組並將我的實際Realm對象附加到它們,從而允許我通過其適當的部分對這些對象進行分組。

因此,這是第一步,我創建了我的所有部分的數組,在我的應用程序中這大約有48個部分,所以在添加通知時運行時不會太糟糕。

創建我的部分陣列後,我查詢的境界,其對應於像這樣的章節正確的對象:

func initObjectsBySection() { 
    print("Initializing") 
    for (index, section) in sections.enumerated() { 
     let unsorted = realm.objects(Object.self).filter("section == %@" , section) 
     let sorted = unsorted.sorted(byProperty: "year", ascending: false) 
     objectsBySection.append(sorted) 
     registerNotification(for: objectsBySection[index], in: index) 
    } 
} 

而且registerNotifcation是什麼bogdanf建議,有了一些變化:

func registerNotification(for objects: Results<Object>, in section: Int) { 
    let token = objects.addNotificationBlock { [unowned self] (changes: RealmCollectionChange) in 
     switch changes { 
     case .initial: 
      // Results are now populated and can be accessed without blocking the UI 
      self.tableView.reloadData() 
      break 
     case .update: 
      // Query results have changed, so apply them to the UITableView 
      self.tableView.beginUpdates() 
      self.tableView.reloadSections(IndexSet.init(integer: section), with: .automatic) 
      self.tableView.endUpdates() 
      break 
     case .error(let error): 
      // An error occurred while opening the Realm file on the background worker thread 
      fatalError("\(error)") 
      break 
     } 

    } 
    notifTokens.append(token) 
} 

我只是簡單地重新加載部分而不是刪除或插入特定行的原因是因爲它做的是同樣的事情,它更簡潔,關鍵的一點是它允許重新計算部分標題/高度。

由於我以48節的數組開始,這意味着如果用戶要從新安裝開始,它們將是48個空的節,並且看起來很可怕。

相反,我做什麼,只是設置了部分0的標題,即:

override func numberOfSections(in tableView: UITableView) -> Int { 
    return objectsBySection.count 
} 

override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { 
    return objectsBySection[section].count 
} 

override func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat { 
    return objectsBySection[section].count > 0 ? 44 : 0 
} 

而這基本上它。

+1

你怎麼知道每個部分有哪些對象(換句話說,如何創建* objectsBySection *)?如果標準可以表達爲Realm查詢,那麼解決方案非常簡單。 –

+0

@bogdanf在我鏈接(來自Realm)的例子中,他們找出哪些對象用於哪些部分使用查詢,[看這裏。](https://github.com/realm/realm-cocoa/blob/master/examples /ios/swift-3.0/GroupedTableView/TableViewController.swift#L56-L60) 所以這是一個Realm查詢。 – Luis

+0

您是否嘗試將對象一次添加到幾個部分?我認爲它會崩潰你的應用程序,因爲少數tableView更新在主線程上運行在同一時間 –

回答

2

我會是這樣的,通過數組循環如你所說:

var objectsBySection = [Results<DemoObject>]() 

// Fill the objectsBySection array like in your example 
... 


for (index, objects) in objectsBySection.enumerated() { 
    registerNotifications(for: objects, in: index) 
} 

其中registerNotifications(for:in:)方法是這樣定義的:

func registerNotifications(for results: Results<DemoObject>, in section:Int) { 

    let notificationToken = results.addNotificationBlock { [weak self] (changes: RealmCollectionChange) in 
     guard let tableView = self?.tableView else { return } 

     switch changes { 
     ... 
     case .update(_, let deletions, let insertions, let modifications): 
      // Query results have changed, so apply them to the UITableView 
      tableView.beginUpdates() 
      tableView.insertRows(at: insertions.map({ IndexPath(row: $0, section: section) }), with: .automatic) 
      tableView.deleteRows(at: deletions.map({ IndexPath(row: $0, section: section)}), with: .automatic) 
      tableView.reloadRows(at: modifications.map({ IndexPath(row: $0, section: section) }), with: .automatic) 
      tableView.endUpdates() 
      break 
     ... 
     } 
    } 
    notificationTokens.append(notificationToken) 
} 

我們假設var notificationTokens在類級別定義。

現在,你提到可以隨時添加新的部分,所以我們來處理。因此,我們添加普通的舊的非細粒度通知塊,並檢查是否添加了新的部分。

notificationToken = realm.addNotificationBlock { [unowned self] note, realm in 
    // Let's see what the section list looks like now 
    let sections = Set(realm.objects(DemoObject.self).value(forKey: "sectionTitle") as! [String]) 

    if !Set(sectionTitles).isSuperset(of: sections) { 
     sectionTitles = Array(sections) 

     self.tableView.reloadData() 
    } 
} 

所以,在我簡單化的方法中,只有在添加了新節時才重新加載所有節點。如果你想從漂亮的插入動畫中受益,你可以檢查添加了哪些部分,將它們逐個插入表中,然後將新對象添加到它們中。

注意:我的方法檢查是否添加了部分是相當密集的,基本上它遍歷數據庫中的所有對象,因此您可能想要在應用程序中使用實際負載來檢查它。不幸的是,直到Realm允許distinctgroup by查詢這是我能想象解決這個問題的唯一方法。

+0

我在實際的應用程序im中有一個擴展,用於刪除相同的對象,並讓它們獨一無二。感謝真棒寫作,當我回家時,會給這個鏡頭,並更新答案! – Luis

+0

所以這個解決方案並不適合我,但我標記你爲答案,因爲這個令人敬畏的答案讓我找出解決方案。用我使用的解決方案更新了我的問題。 – Luis

+0

我認爲@distinctUnionOfObjects適用於領域,但我不知道如何在Swift中使用它。你如何改變你的回答Bogdan關於部分? https://realm.io/news/nspredicate-cheatsheet/ –