Use AnyHashable instead of AnyObject as representedObject for tree nodes.

This commit is contained in:
Brent Simmons 2017-11-04 15:27:32 -07:00
parent 1adaebf2bf
commit c08bbaa970
11 changed files with 47 additions and 32 deletions

View File

@ -40,7 +40,7 @@ final class AppInfo {
var article: Article?
var articles: Set<Article>?
var navigationKey: Int?
var objects: [AnyObject]?
var objects: [AnyHashable]?
var feed: Feed?
static let appInfoKey = "appInfo"

View File

@ -41,7 +41,7 @@ private extension FolderTreeControllerDelegate {
func createNode(_ folder: Folder, parent: Node) -> Node {
let node = Node(representedObject: folder as AnyObject, parent: parent)
let node = Node(representedObject: folder, parent: parent)
node.canHaveChildNodes = false
return node
}

View File

@ -34,16 +34,16 @@ private extension SidebarTreeControllerDelegate {
// This will be expanded later to add synthetic feeds (All Unread, for instance)
// and other accounts.
return childNodesForContainerNode(rootNode, AccountManager.shared.localAccount.children)
return childNodesForContainerNode(rootNode, AccountManager.shared.localAccount.children as! [AnyHashable])
}
func childNodesForFolderNode(_ folderNode: Node) -> [Node]? {
let folder = folderNode.representedObject as! Folder
return childNodesForContainerNode(folderNode, folder.children)
return childNodesForContainerNode(folderNode, folder.children as! [AnyHashable])
}
func childNodesForContainerNode(_ containerNode: Node, _ children: [AnyObject]) -> [Node]? {
func childNodesForContainerNode(_ containerNode: Node, _ children: [AnyHashable]) -> [Node]? {
var updatedChildNodes = [Node]()
@ -83,15 +83,15 @@ private extension SidebarTreeControllerDelegate {
func createNode(folder: Folder, parent: Node) -> Node {
let node = Node(representedObject: folder as AnyObject, parent: parent)
let node = Node(representedObject: folder, parent: parent)
node.canHaveChildNodes = true
return node
}
func nodeInArrayRepresentingObject(_ nodes: [Node], _ representedObject: AnyObject) -> Node? {
func nodeInArrayRepresentingObject(_ nodes: [Node], _ representedObject: AnyHashable) -> Node? {
for oneNode in nodes {
if oneNode.representedObject === representedObject {
if oneNode.representedObject == representedObject {
return oneNode
}
}

View File

@ -38,10 +38,10 @@ import RSCore
@objc dynamic func unreadCountDidChange(_ note: Notification) {
guard let representedObject = note.object else {
guard let representedObject = note.object as? AnyHashable else {
return
}
let _ = configureCellsForRepresentedObject(representedObject as AnyObject)
let _ = configureCellsForRepresentedObject(representedObject)
}
@objc dynamic func containerChildrenDidChange(_ note: Notification) {
@ -172,7 +172,7 @@ private extension SidebarViewController {
}
}
func postSidebarSelectionDidChangeNotification(_ selectedObjects: [AnyObject]?) {
func postSidebarSelectionDidChangeNotification(_ selectedObjects: [AnyHashable]?) {
let appInfo = AppInfo()
if let objects = selectedObjects {
@ -186,7 +186,7 @@ private extension SidebarViewController {
NotificationCenter.default.post(name: .SidebarSelectionDidChange, object: self, userInfo: appInfo.userInfo)
}
func updateUnreadCounts(for objects: [AnyObject]) {
func updateUnreadCounts(for objects: [AnyHashable]) {
// On selection, update unread counts for folders and feeds.
// For feeds, actually fetch from database.
@ -300,7 +300,7 @@ private extension SidebarViewController {
return cells
}
func cellsForRepresentedObject(_ representedObject: AnyObject) -> [SidebarCell] {
func cellsForRepresentedObject(_ representedObject: AnyHashable) -> [SidebarCell] {
let availableCells = availableSidebarCells()
return availableCells.filter{ (oneSidebarCell) -> Bool in
@ -308,11 +308,11 @@ private extension SidebarViewController {
guard let oneNode = oneSidebarCell.objectValue as? Node else {
return false
}
return oneNode.representedObject === representedObject
return oneNode.representedObject == representedObject
}
}
func configureCellsForRepresentedObject(_ representedObject: AnyObject) -> Bool {
func configureCellsForRepresentedObject(_ representedObject: AnyHashable) -> Bool {
//Return true if any cells were configured.
@ -333,7 +333,7 @@ private extension SidebarViewController {
}
@discardableResult
func revealAndSelectRepresentedObject(_ representedObject: AnyObject) -> Bool {
func revealAndSelectRepresentedObject(_ representedObject: AnyHashable) -> Bool {
return outlineView.revealAndSelectRepresentedObject(representedObject, treeController)
}

View File

@ -43,7 +43,7 @@ class TimelineViewController: NSViewController, KeyboardDelegate {
}
}
private var representedObjects: [AnyObject]? {
private var representedObjects: [AnyHashable]? {
didSet {
if !representedObjectArraysAreEqual(oldValue, representedObjects) {
fetchArticles()
@ -479,7 +479,7 @@ private extension TimelineViewController {
}
}
func representedObjectArraysAreEqual(_ objects1: [AnyObject]?, _ objects2: [AnyObject]?) -> Bool {
func representedObjectArraysAreEqual(_ objects1: [AnyHashable]?, _ objects2: [AnyHashable]?) -> Bool {
if objects1 == nil && objects2 == nil {
return true
@ -493,7 +493,7 @@ private extension TimelineViewController {
var ix = 0
for oneObject in objects1 {
if oneObject !== objects2[ix] {
if oneObject != objects2[ix] {
return false
}
ix += 1

View File

@ -10,12 +10,14 @@ import Foundation
import Data
import RSCore
public final class Folder: DisplayNameProvider, Container, UnreadCountProvider {
public final class Folder: DisplayNameProvider, Container, UnreadCountProvider, Hashable {
public weak var account: Account?
public var children = [AnyObject]()
var name: String?
static let untitledName = NSLocalizedString("Untitled ƒ", comment: "Folder name")
public let hashValue: Int
// MARK: - Fetching Articles
@ -52,7 +54,8 @@ public final class Folder: DisplayNameProvider, Container, UnreadCountProvider {
self.account = account
self.name = name
self.hashValue = name?.hashValue ?? Folder.untitledName.hashValue
NotificationCenter.default.addObserver(self, selector: #selector(unreadCountDidChange(_:)), name: .UnreadCountDidChange, object: nil)
}
@ -137,6 +140,12 @@ public final class Folder: DisplayNameProvider, Container, UnreadCountProvider {
}
}
// MARK: - Equatable
static public func ==(lhs: Folder, rhs: Folder) -> Bool {
return lhs === rhs
}
}
// MARK: - Private

View File

@ -44,7 +44,7 @@ public extension NSOutlineView {
}
@discardableResult
public func revealAndSelectRepresentedObject(_ representedObject: AnyObject, _ treeController: TreeController) -> Bool {
public func revealAndSelectRepresentedObject(_ representedObject: AnyHashable, _ treeController: TreeController) -> Bool {
guard let nodePath = NodePath(representedObject: representedObject, treeController: treeController) else {
return false

View File

@ -11,7 +11,7 @@ import Foundation
public final class Node: Equatable {
public weak var parent: Node?
public let representedObject: AnyObject
public let representedObject: AnyHashable
public var canHaveChildNodes = false
public var isGroupItem = false
public var childNodes: [Node]?
@ -59,7 +59,7 @@ public final class Node: Equatable {
}
}
public init(representedObject: AnyObject, parent: Node?) {
public init(representedObject: AnyHashable, parent: Node?) {
self.representedObject = representedObject
self.parent = parent
@ -90,14 +90,14 @@ public final class Node: Equatable {
}
}
public func childNodeRepresentingObject(_ obj: AnyObject) -> Node? {
public func childNodeRepresentingObject(_ obj: AnyHashable) -> Node? {
guard let childNodes = childNodes else {
return nil
}
for oneNode in childNodes {
if oneNode.representedObject === obj {
if oneNode.representedObject == obj {
return oneNode
}
}

View File

@ -30,7 +30,7 @@ public struct NodePath {
self.components = tempArray.reversed()
}
public init?(representedObject: AnyObject, treeController: TreeController) {
public init?(representedObject: AnyHashable, treeController: TreeController) {
if let node = treeController.nodeInTreeRepresentingObject(representedObject) {
self.init(node: node)

View File

@ -10,6 +10,12 @@ import Foundation
// Handy to use as the represented object for a root node. Not required to use it, though.
final class TopLevelRepresentedObject {
final class TopLevelRepresentedObject: Hashable {
let hashValue: Int = 0
static func ==(lhs: TopLevelRepresentedObject, rhs: TopLevelRepresentedObject) -> Bool {
return true
}
}

View File

@ -45,11 +45,11 @@ public final class TreeController {
visitNode(rootNode, visitBlock)
}
public func nodeInArrayRepresentingObject(nodes: [Node], representedObject: AnyObject, recurse: Bool = false) -> Node? {
public func nodeInArrayRepresentingObject(nodes: [Node], representedObject: AnyHashable, recurse: Bool = false) -> Node? {
for oneNode in nodes {
if oneNode.representedObject === representedObject {
if oneNode.representedObject == representedObject {
return oneNode
}
@ -63,7 +63,7 @@ public final class TreeController {
return nil
}
public func nodeInTreeRepresentingObject(_ representedObject: AnyObject) -> Node? {
public func nodeInTreeRepresentingObject(_ representedObject: AnyHashable) -> Node? {
return nodeInArrayRepresentingObject(nodes: [rootNode], representedObject: representedObject, recurse: true)
}