class SceneDelegate: UIResponder, UIWindowSceneDelegate {
var window: UIWindow?
static let itemStore = ItemStore() // static 으로 선언
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
guard let _ = (scene as? UIWindowScene) else { return }
// Access the ItemsViewController and set its item store
let navController = window!.rootViewController as! UINavigationController
let itemsController = navController.topViewController as! ItemsViewController
itemsController.itemStore = SceneDelegate.itemStore
}
}
위에처럼 하니까 itemStore 를 모든 scene 에서 공유하기 때문에 다른 창을 켜던가 아님 다른 뷰에 넘어갔다 오면 모든 창에서 업데이트가 되어 있는데 화면 전환 없이는 한 창에서의 변화가 다른 창에서 즉각적으로 적용되지 않았다.
그래서 변화가 있을 때마다 앱에서 공유 중인 NotificationCenter.default 를 통해 알리고, 알림을 받을 수 있도록 해야겠다고 생각했는데 여기서부터 멍청함과 가보자고 마인드의 환장의 콜라보...
일단 NotificaitonCenter.default 가 앱 단위로 하나씩 존재하기 때문에 하나의 앱에서 여러 window(scene) 을 허용한 현재의 경우 얘를 쓰면 되는데 멍청한 착각으로 서로 다른 앱 간의 알림을 가능케 하는 DistributedNotificationCenter 를 써야한다고 생각했다...절대 선언이 안돼서 이것 때문에 시간 순삭 굿...
암튼 뭔가 한 윈도우에서 아이템 스토어에 변화가 생기면 다른 윈도우에서도 모두 뷰를 업데이트 해줘야 하므로 itemStoreDidUpdate
라는 Notification 을 새로 만들어주고, ItemsViewController 와 DetailViewController 에서 해당 notification 에 구독하도록 했다.
ItemsViewController 에서는 알림이 오면 tableView.reloadData() 를 통해 화면을 업데이트했고 DetailViewController 에서는 모든 라벨을 다시 업데이트 하도록 했다.
extension Notification.Name {
static let itemStoreDidUpdate = Notification.Name("itemStoreDidUpdate")
}
class ItemsViewController: UITableViewController {
required init?(coder: NSCoder) {
super.init(coder: coder)
navigationItem.leftBarButtonItem = editButtonItem
NotificationCenter.default.addObserver(self,
selector: #selector(reloadData(for:)),
name: .itemStoreDidUpdate,
object: nil)
}
@objc private func reloadData(for notification: Notification) {
if let notifyingController = notification.object as? UIViewController,
self != notifyingController {
tableView.reloadData()
}
}
}
class DetailViewController: UIViewController, UITextFieldDelegate {
required init?(coder: NSCoder) {
super.init(coder: coder)
NotificationCenter.default.addObserver(self,
selector: #selector(updateLabels),
name: .itemStoreDidUpdate,
object: nil)
}
@objc private func updateLabels(for notification: Notification) {
if let notifyingController = notification.object as? UIViewController,
self != notifyingController {
updateLablesToMatchItem()
}
}
private func updateLablesToMatchItem() {
nameField.text = item.name
serialNumberField.text = item.serialNumber
valueField.text = numberFormatter.string(from: NSNumber(value: item.valueInDollars))
dateLabel.text = dateFormatter.string(from: item.dateCreated)
}
}
class ItemsViewController: UITableViewController {
var itemStore: ItemStore!
@IBAction func addNewItem(_ sender: UIBarButtonItem) {
let newItem = itemStore.createItem()
if let index = itemStore.allItems.firstIndex(of: newItem) {
let indexPath = IndexPath(row: index, section: 0)
tableView.insertRows(at: [indexPath], with: .automatic)
// 알림
NotificationCenter.default.post(name: .itemStoreDidUpdate,
object: self)
}
}
override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) {
if editingStyle == .delete {
let item = itemStore.allItems[indexPath.row]
itemStore.removeItem(item)
tableView.deleteRows(at: [indexPath], with: .automatic)
// 알림
NotificationCenter.default.post(name: .itemStoreDidUpdate,
object: self)
}
}
override func tableView(_ tableView: UITableView, moveRowAt sourceIndexPath: IndexPath, to destinationIndexPath: IndexPath) {
itemStore.moveItem(from: sourceIndexPath.row, to: destinationIndexPath.row)
// 알림
NotificationCenter.default.post(name: .itemStoreDidUpdate,
object: self)
}
}
class DetailViewController: UIViewController, UITextFieldDelegate {
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
view.endEditing(true)
item.name = nameField.text ?? ""
item.serialNumber = serialNumberField.text ?? ""
if let valueText = valueField.text,
let value = numberFormatter.number(from: valueText) {
item.valueInDollars = value.intValue
} else {
item.valueInDollars = 0
}
// 알림
NotificationCenter.default.post(name: .itemStoreDidUpdate,
object: self)
}
}
@objc private func reloadData(for notification: Notification) {
if let notifyingController = notification.object as? UIViewController,
self != notifyingController {
tableView.reloadData()
}
}