OSDN Git Service

staticプロパティをインスタンスプロパティに変更
[kcd/KCD.git] / KCD / ShipViewController.swift
index cb0de3f..a5f0a74 100644 (file)
 
 import Cocoa
 
-fileprivate enum ViewType: Int {
+private enum ViewType: Int {
+    
     case exp
+    
     case power
+    
     case power2
+    
     case power3
 }
 
-class ShipViewController: MainTabVIewItemViewController {
-    let managedObjectContext = ServerDataStore.default.managedObjectContext
+/// 2018.02.24
+/// #keyPath(Ship.master_ship.soku)がkeyであるNSSortDescriptorが含まれるとクラッシュする可能性があるため
+/// 新設した#keyPath(Ship.soku)をkeyにするように書き換える
+private func exchangeSortKey(original: [NSSortDescriptor]) -> [NSSortDescriptor] {
     
-    deinit {
-        NotificationCenter.default.removeObserver(self)
+    return original
+        .map { sortDesc -> NSSortDescriptor in
+            
+            if sortDesc.key == #keyPath(Ship.master_ship.soku) {
+                
+                return NSSortDescriptor(key: #keyPath(Ship.soku), ascending: sortDesc.ascending)
+            }
+            
+            return sortDesc
     }
+}
+
+final class ShipViewController: MainTabVIewItemViewController {
+    
+    @objc let managedObjectContext = ServerDataStore.default.context
+    
+    @IBOutlet private var shipController: NSArrayController!
+    @IBOutlet private var expTableView: NSScrollView!
+    @IBOutlet private var powerTableView: NSScrollView!
+    @IBOutlet private var power2TableView: NSScrollView!
+    @IBOutlet private var power3TableView: NSScrollView!
+    @IBOutlet private weak var standardDeviationField: NSTextField!
     
-    @IBOutlet var shipController: NSArrayController!
-    @IBOutlet var expTableView: NSScrollView!
-    @IBOutlet var powerTableView: NSScrollView!
-    @IBOutlet var power2TableView: NSScrollView!
-    @IBOutlet var power3TableView: NSScrollView!
-    @IBOutlet weak var standardDeviationField: NSTextField!
+    private var sortDescriptorsObservation: NSKeyValueObservation?
+    private var arrangedObjectsObservation: NSKeyValueObservation?
     
-    override var nibName: String! {
-        return "ShipViewController"
+    private var notificationObserver = NotificationObserver()
+    
+    override var nibName: NSNib.Name {
+        
+        return .nibName(instanceOf: self)
     }
+    
     override var hasShipTypeSelector: Bool { return true }
-    override var selectedShipType: ShipType {
+    override var selectedShipType: ShipTabType {
+        
         didSet {
-            shipController.filterPredicate = predicate(for: selectedShipType)
+            
+            shipController.filterPredicate = shipTypePredicte(for: selectedShipType)
             shipController.rearrangeObjects()
         }
     }
     
-    var standardDeviation: Double {
-        guard let ships = shipController.arrangedObjects as? [Ship],
-            !ships.isEmpty,
-            let avg = shipController.value(forKeyPath: "arrangedObjects.@avg.lv") as? Double
-            else { return 0.0 }
+    @objc var standardDeviation: Double {
+        
+        guard let ships = shipController.arrangedObjects as? [Ship], !ships.isEmpty else {
+            
+            return 0.0
+        }
+        guard let avg = shipController.value(forKeyPath: "arrangedObjects.@avg.lv") as? Double else {
+            
+            return 0.0
+        }
+        
         let total = ships.reduce(0.0) {
+            
             let delta = Double($1.lv) - avg
+            
             return $0 + delta * delta
         }
+        
         return sqrt(total / Double(ships.count))
     }
     
-    fileprivate weak var currentTableView: NSView?
+//    @objc dynamic var sortDescriptors: [NSSortDescriptor] {
+//        get { return UserDefaults.standard[.shipviewSortDescriptors] }
+//        set { UserDefaults.standard[.shipviewSortDescriptors] = sortDescriptors }
+//    }
+    
+    private weak var currentTableView: NSView?
     
     override func viewDidLoad() {
+        
         super.viewDidLoad()
         
         currentTableView = expTableView
         
         do {
+            
             try shipController.fetch(with: nil, merge: true)
+            
         } catch {
+            
             fatalError("ShipViewController: can not fetch. \(error)")
+            
+        }
+        
+        shipController.sortDescriptors = exchangeSortKey(original: UserDefaults.standard[.shipviewSortDescriptors])
+
+        sortDescriptorsObservation = shipController.observe(\NSArrayController.sortDescriptors) { [weak self] _, _ in
+
+            UserDefaults.standard[.shipviewSortDescriptors] = self?.shipController.sortDescriptors ?? []
+        }
+        arrangedObjectsObservation = shipController.observe(\NSArrayController.arrangedObjects) { [weak self] _, _ in
+            
+            self?.notifyChangeValue(forKey: #keyPath(standardDeviation))
         }
-        shipController.sortDescriptors = UserDefaults.standard.shipviewSortDescriptors
-        shipController.addObserver(self, forKeyPath: NSSortDescriptorsBinding, context: nil)
-        shipController.addObserver(self, forKeyPath: "arrangedObjects", context: nil)
         
         let tableViews = [expTableView, powerTableView, power2TableView, power3TableView]
         tableViews
             .forEach {
-                NotificationCenter.default
-                    .addObserver(forName: .NSScrollViewDidEndLiveScroll, object: $0, queue: nil) { notification in
-                        guard let target = notification.object as? NSScrollView else { return }
+                
+                notificationObserver
+                    .addObserver(forName: NSScrollView.didEndLiveScrollNotification, object: $0, queue: .main) {
+                        
+                        guard let target = $0.object as? NSScrollView else {
+                            
+                            return
+                        }
+                        
                         let visibleRect = target.documentVisibleRect
                         tableViews
                             .filter { $0 != target }
@@ -84,35 +144,34 @@ class ShipViewController: MainTabVIewItemViewController {
             standardDeviationField.isHidden = false
         #endif
     }
-    override func observeValue(forKeyPath keyPath: String?,
-                               of object: Any?,
-                               change: [NSKeyValueChangeKey: Any]?,
-                               context: UnsafeMutableRawPointer?) {
-        if keyPath == NSSortDescriptorsBinding {
-            UserDefaults.standard.shipviewSortDescriptors = shipController.sortDescriptors
-            return
-        }
-        if keyPath == "arrangedObjects" {
-            willChangeValue(forKey: "standardDeviation")
-            didChangeValue(forKey: "standardDeviation")
-            return
-        }
-        
-        super.observeValue(forKeyPath: keyPath, of: object, change: change, context: context)
-    }
     
-    fileprivate func showView(with type: ViewType) {
+    private func showView(with type: ViewType) {
+        
         let newSelection: NSView = {
+            
             switch type {
+                
             case .exp: return expTableView
+                
             case .power: return powerTableView
+                
             case .power2: return power2TableView
+                
             case .power3: return power3TableView
+                
             }
         }()
-        if currentTableView == newSelection { return }
-        guard let tableView = currentTableView
-            else { return }
+        
+        if currentTableView == newSelection {
+            
+            return
+        }
+        
+        guard let tableView = currentTableView else {
+            
+            return
+        }
+        
         newSelection.frame = tableView.frame
         newSelection.autoresizingMask = tableView.autoresizingMask
         view.replaceSubview(tableView, with: newSelection)
@@ -121,25 +180,40 @@ class ShipViewController: MainTabVIewItemViewController {
     }
     
     private func tag(_ sender: AnyObject?) -> Int {
-        guard let sender = sender
-            else { return -1 }
-        if let control = sender as? NSSegmentedControl,
-            let cell = sender.cell as? NSSegmentedCell {
-            return cell.tag(forSegment: control.selectedSegment)
-        }
-        if let control = sender as? NSControl {
+        
+        switch sender {
+            
+        case let segmented as NSSegmentedControl:
+            let cell = segmented.cell as? NSSegmentedCell
+            
+            return cell?.tag(forSegment: segmented.selectedSegment) ?? -1
+            
+        case let control as NSControl:
+            
             return control.tag
+            
+        default:
+            
+            return -1
+            
         }
-        return -1
     }
+    
     @IBAction func changeView(_ sender: AnyObject?) {
-        ViewType(rawValue: tag(sender)).map { showView(with: $0) }
+        
+        ViewType(rawValue: tag(sender)).map(showView)
     }
 }
 
 extension ShipViewController: NSTableViewDelegate {
+    
     func tableView(_ tableView: NSTableView, viewFor tableColumn: NSTableColumn?, row: Int) -> NSView? {
-        guard let identifier = tableColumn?.identifier else { return nil }
-        return tableView.make(withIdentifier: identifier, owner: nil)
+        
+        guard let identifier = tableColumn?.identifier else {
+            
+            return nil
+        }
+        
+        return tableView.makeView(withIdentifier: identifier, owner: nil)
     }
 }