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 }
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)
}
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)
}
}