performSegue 自更新到 Xcode 9(和 iOS 11)后无法正常工作
performSegue not working since update to Xcode 9 (and iOS 11)
在我的应用程序中,我有一个初始屏幕,用于检查用户是否已经使用 Facebook 登录。如果他不在,则初始屏幕会将登录屏幕推送到导航堆栈。如果用户已登录,初始屏幕也会推送登录屏幕,但会在登录屏幕的 viewDidAppear 上调用推送主应用屏幕的方法。
因此,当用户登录时,我应该在我的应用程序中看到以下视图控制器堆栈:
SplashViewController > LoginViewController > MainViewController.
这个流程在 iOS 9 和 iOS 10 上没有问题。
然而,自从我升级到 iOS 11 后,此流程停止工作。
现在,如果用户登录,主视图控制器不会出现,只有登录视图控制器保持可见。我检查了确实调用了主应用程序屏幕的 performSegue 的调试器。
有两个奇怪的细节。首先是这个登录视图控制器上的按钮不再起作用(有一个按钮从 FacebookLogin SDK 调用 Facebook 登录流程)。
第二个是,如果我转到 Xcode 并单击 "Debug View Hierarchy" 按钮,而 Xcode 正在处理和创建视图层次结构,主视图控制器突然出现在我的应用
好像主视图控制器被推送了,但是它的视图没有被呈现;所以 LoginViewController 上的 segues 不再起作用了。但是,按 "Debug View Hierarchy" 似乎会触发更新视图层次结构的操作。
我正在使用 Xcode 9.0.1。这个问题在 Xcode 模拟器和我的 iPad Mini 2 上都会发生,目前是 运行 iOS 11.0.3.
谢谢。
我不知道为什么会这样,但我可以通过以下方式解决这个问题。
在 SplashViewController 上,我调用 direct segue 到登录视图控制器,这将在 viewWillAppear() 方法上调用另一个 segue,我强制执行 segue在主队列中:
// SplashViewController
struct Identifier {
static let login = "Login"
static let direct = "Direct"
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
login()
}
func login() {
// If there already exists a Facebook token we try to login directly.
if let accessToken = AccessToken.current {
bm.login(facebookToken: accessToken.authenticationToken, completion: { (error, user) in
guard error == nil else {
self.performSegue(withIdentifier: Identifier.login, sender: self)
return
}
// This call on the main queue wasn't needed on iOS 10
DispatchQueue.main.async {
self.performSegue(withIdentifier: Identifier.direct, sender: self)
}
})
} else {
performSegue(withIdentifier: Identifier.login, sender: self)
}
}
然后在 LoginViewController 上:
// LoginViewController
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
if direct {
// Without calling the previous segue on the main queue this
// segue would be called but the pushed view controller's
// view would not appear on the screen until a refresh event
// was triggered.
self.performSegue(withIdentifier: Identifier.direct, sender: nil)
}
}
在我的应用程序中,我有一个初始屏幕,用于检查用户是否已经使用 Facebook 登录。如果他不在,则初始屏幕会将登录屏幕推送到导航堆栈。如果用户已登录,初始屏幕也会推送登录屏幕,但会在登录屏幕的 viewDidAppear 上调用推送主应用屏幕的方法。
因此,当用户登录时,我应该在我的应用程序中看到以下视图控制器堆栈:
SplashViewController > LoginViewController > MainViewController.
这个流程在 iOS 9 和 iOS 10 上没有问题。
然而,自从我升级到 iOS 11 后,此流程停止工作。
现在,如果用户登录,主视图控制器不会出现,只有登录视图控制器保持可见。我检查了确实调用了主应用程序屏幕的 performSegue 的调试器。
有两个奇怪的细节。首先是这个登录视图控制器上的按钮不再起作用(有一个按钮从 FacebookLogin SDK 调用 Facebook 登录流程)。
第二个是,如果我转到 Xcode 并单击 "Debug View Hierarchy" 按钮,而 Xcode 正在处理和创建视图层次结构,主视图控制器突然出现在我的应用
好像主视图控制器被推送了,但是它的视图没有被呈现;所以 LoginViewController 上的 segues 不再起作用了。但是,按 "Debug View Hierarchy" 似乎会触发更新视图层次结构的操作。
我正在使用 Xcode 9.0.1。这个问题在 Xcode 模拟器和我的 iPad Mini 2 上都会发生,目前是 运行 iOS 11.0.3.
谢谢。
我不知道为什么会这样,但我可以通过以下方式解决这个问题。
在 SplashViewController 上,我调用 direct segue 到登录视图控制器,这将在 viewWillAppear() 方法上调用另一个 segue,我强制执行 segue在主队列中:
// SplashViewController
struct Identifier {
static let login = "Login"
static let direct = "Direct"
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
login()
}
func login() {
// If there already exists a Facebook token we try to login directly.
if let accessToken = AccessToken.current {
bm.login(facebookToken: accessToken.authenticationToken, completion: { (error, user) in
guard error == nil else {
self.performSegue(withIdentifier: Identifier.login, sender: self)
return
}
// This call on the main queue wasn't needed on iOS 10
DispatchQueue.main.async {
self.performSegue(withIdentifier: Identifier.direct, sender: self)
}
})
} else {
performSegue(withIdentifier: Identifier.login, sender: self)
}
}
然后在 LoginViewController 上:
// LoginViewController
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
if direct {
// Without calling the previous segue on the main queue this
// segue would be called but the pushed view controller's
// view would not appear on the screen until a refresh event
// was triggered.
self.performSegue(withIdentifier: Identifier.direct, sender: nil)
}
}