在模态 UIViewController 解除后视图生命周期中更新控制器的位置
Where in view lifecycle to update controller after modal UIViewController dismissed
我有一个 UIViewController
和一个需要显示 "lbs" 或 "kg" 的 UILabel
。我的应用程序有一个设置屏幕(另一个 UIViewController
),它以模态方式显示在第一个视图控制器上,用户可以 select 两个单元中的任何一个并保存他们的偏好。如果单位被更改并且模态设置屏幕被关闭,我当然希望第一个视图控制器上的标签用新的单位值更新(但不刷新整个视图)。我以为我知道如何让它发挥作用,但显然我不知道。
在我的模式设置屏幕上,我有一个 UISegmentedControl
允许用户 select 单位。任何时候更改,此函数都会更新 userDefaults
:
func saveUnitsSelection() {
if unitsControl.selectedSegmentIndex == 0 {
UserDefaultsManager.sharedInstance.preferredUnits = Units.pounds.rawValue
} else {
UserDefaultsManager.sharedInstance.preferredUnits = Units.kilograms.rawValue
}
}
然后他们可能会关闭设置屏幕。所以,我在我的第一个视图控制器中将其添加到 viewDidLoad
:
override func viewDidLoad() {
super.viewDidLoad()
let preferredUnits = UserDefaultsManager.sharedInstance.preferredUnits
units.text = preferredUnits
}
那没用,所以我把它移到了 viewWillAppear()
,那也没用。我做了一些研究和一些穴居人调试,发现在视图第一次 loaded/presented 之后,这些函数都没有被调用。如果我在由 UINavigationController
管理的 UITableViewController
的层次结构中工作,似乎 viewWillAppear
将被第二次调用,但是当我关闭我的模态 [=] 时不会被调用13=] 以显示其下方的 UIViewController
。
编辑 1:
这是我正在使用的视图层次结构:
我有点卡在这一点上了,不确定接下来要尝试什么。
编辑 2:
用户可以点击导航栏中的 'Done' 按钮,当他们点击时,dismissSettings()
函数会关闭设置视图:
class SettingsViewController: UITableViewController {
let preferredUnits = UserDefaultsManager.sharedInstance.preferredUnits
// some other variables set here
override func viewDidLoad() {
super.viewDidLoad()
self.navigationController?.navigationBar.topItem?.title = "Settings"
navigationItem.rightBarButtonItem = UIBarButtonItem(title: "Done", style: .Plain, target: self, action: #selector(self.dismissSettings(_:)))
if preferredUnits == Units.pounds.rawValue {
unitsControl.selectedSegmentIndex = 0
} else {
unitsControl.selectedSegmentIndex = 1
}
}
func dismissSettings(sender: AnyObject?) {
navigationController?.dismissViewControllerAnimated(true, completion: nil)
}
}
真正的问题
您拼写错误 viewWillAppear
。你称它为:
func viewWillAppear()
就 Cocoa Touch 而言,这是一个随机的无关函数,它没有挂钩。你的意思是:
override func viewWillAppear(animated: Bool)
第一个函数的全称是:“viewWillAppear
”
第二个函数的全称是:“viewWillAppear:animated
”
一旦你习惯了这一点,Cocoa Touch 使用的极端方法 "overloading" 就会变得更容易。
这在其他语言中非常不同,您可能至少会收到警告。
大家在发题时需要学习的另一课是:Include All Related Code!
有用的日志记录功能,我用它来代替 print 或 NSLog,以帮助找到这些东西:
class Util {
static func log(message: String, sourceAbsolutePath: String = #file, line: Int = #line, function: String = #function, category: String = "General") {
let threadType = NSThread.currentThread().isMainThread ? "main" : "other"
let baseName = (NSURL(fileURLWithPath: sourceAbsolutePath).lastPathComponent! as NSString).stringByDeletingPathExtension ?? "UNKNOWN_FILE"
print("\(NSDate()) \(threadType) \(baseName) \(function)[\(line)]: \(message)")
}
}
[由于猜测不正确,删除了之前剩余的讨论]
我有一个 UIViewController
和一个需要显示 "lbs" 或 "kg" 的 UILabel
。我的应用程序有一个设置屏幕(另一个 UIViewController
),它以模态方式显示在第一个视图控制器上,用户可以 select 两个单元中的任何一个并保存他们的偏好。如果单位被更改并且模态设置屏幕被关闭,我当然希望第一个视图控制器上的标签用新的单位值更新(但不刷新整个视图)。我以为我知道如何让它发挥作用,但显然我不知道。
在我的模式设置屏幕上,我有一个 UISegmentedControl
允许用户 select 单位。任何时候更改,此函数都会更新 userDefaults
:
func saveUnitsSelection() {
if unitsControl.selectedSegmentIndex == 0 {
UserDefaultsManager.sharedInstance.preferredUnits = Units.pounds.rawValue
} else {
UserDefaultsManager.sharedInstance.preferredUnits = Units.kilograms.rawValue
}
}
然后他们可能会关闭设置屏幕。所以,我在我的第一个视图控制器中将其添加到 viewDidLoad
:
override func viewDidLoad() {
super.viewDidLoad()
let preferredUnits = UserDefaultsManager.sharedInstance.preferredUnits
units.text = preferredUnits
}
那没用,所以我把它移到了 viewWillAppear()
,那也没用。我做了一些研究和一些穴居人调试,发现在视图第一次 loaded/presented 之后,这些函数都没有被调用。如果我在由 UINavigationController
管理的 UITableViewController
的层次结构中工作,似乎 viewWillAppear
将被第二次调用,但是当我关闭我的模态 [=] 时不会被调用13=] 以显示其下方的 UIViewController
。
编辑 1:
这是我正在使用的视图层次结构:
我有点卡在这一点上了,不确定接下来要尝试什么。
编辑 2:
用户可以点击导航栏中的 'Done' 按钮,当他们点击时,dismissSettings()
函数会关闭设置视图:
class SettingsViewController: UITableViewController {
let preferredUnits = UserDefaultsManager.sharedInstance.preferredUnits
// some other variables set here
override func viewDidLoad() {
super.viewDidLoad()
self.navigationController?.navigationBar.topItem?.title = "Settings"
navigationItem.rightBarButtonItem = UIBarButtonItem(title: "Done", style: .Plain, target: self, action: #selector(self.dismissSettings(_:)))
if preferredUnits == Units.pounds.rawValue {
unitsControl.selectedSegmentIndex = 0
} else {
unitsControl.selectedSegmentIndex = 1
}
}
func dismissSettings(sender: AnyObject?) {
navigationController?.dismissViewControllerAnimated(true, completion: nil)
}
}
真正的问题
您拼写错误 viewWillAppear
。你称它为:
func viewWillAppear()
就 Cocoa Touch 而言,这是一个随机的无关函数,它没有挂钩。你的意思是:
override func viewWillAppear(animated: Bool)
第一个函数的全称是:“viewWillAppear
”
第二个函数的全称是:“viewWillAppear:animated
”
一旦你习惯了这一点,Cocoa Touch 使用的极端方法 "overloading" 就会变得更容易。
这在其他语言中非常不同,您可能至少会收到警告。
大家在发题时需要学习的另一课是:Include All Related Code!
有用的日志记录功能,我用它来代替 print 或 NSLog,以帮助找到这些东西:
class Util {
static func log(message: String, sourceAbsolutePath: String = #file, line: Int = #line, function: String = #function, category: String = "General") {
let threadType = NSThread.currentThread().isMainThread ? "main" : "other"
let baseName = (NSURL(fileURLWithPath: sourceAbsolutePath).lastPathComponent! as NSString).stringByDeletingPathExtension ?? "UNKNOWN_FILE"
print("\(NSDate()) \(threadType) \(baseName) \(function)[\(line)]: \(message)")
}
}
[由于猜测不正确,删除了之前剩余的讨论]