如何在SceneDelegate中关闭ViewController?iOS离线页面无法消失排查
iOS离线页面联网后无法关闭的问题排查
我正在开发一款基于Swift 5的iOS App,想要实现离线时显示OfflineViewController,用户重新联网后关闭该页面并回到之前的界面。实际情况是离线时该页面能正常弹出,但联网后无法消失,添加刷新按钮尝试关闭也无效。以下是我的代码,请问我哪里出错了?
SceneDelegate 代码
class SceneDelegate: UIResponder, UIWindowSceneDelegate { var window: UIWindow? let reachability = try! Reachability() func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) { guard let _ = (scene as? UIWindowScene) else { return } // Send to homepage if logged in, otherwise login screen. let accessToken: String? = KeychainWrapper.standard.string(forKey: "accessToken") // If access token exists, skip login page if accessToken != nil { if let windowScene = scene as? UIWindowScene { self.window = UIWindow(windowScene: windowScene) let mainStoryboard:UIStoryboard = UIStoryboard(name: "Main", bundle: nil) let vc = mainStoryboard.instantiateViewController(withIdentifier: "homeTabController") as! TabBarController self.window!.rootViewController = vc } } reachability.whenUnreachable = { [self] _ in print("Not reachable (Scene delegate)") let storyboard = UIStoryboard(name: "Main", bundle: nil) let vc = storyboard.instantiateViewController(withIdentifier: "OfflineViewController") as! OfflineViewController vc.modalPresentationStyle = .fullScreen guard let firstScene = UIApplication.shared.connectedScenes.first as? UIWindowScene else { return } guard let firstWindow = firstScene.windows.first else { return } let rootVC = firstWindow.rootViewController rootVC?.dismiss(animated: true, completion: nil) rootVC!.present(vc, animated: true, completion: nil) } do { try reachability.startNotifier() } catch { print("Unable to start notifier") } } }
OfflineViewController 代码
import UIKit class OfflineViewController: UIViewController { let reachability = try! Reachability() override func viewDidLoad() { super.viewDidLoad() do { try reachability.startNotifier() } catch { print("Unable to start notifier") } } @IBAction func hitRefresh(_ sender: Any) { reachability.whenReachable = { reachability in self.dismiss(animated: true, completion: nil) } } }
问题分析
- 缺失联网状态监听:SceneDelegate只处理了离线事件(
whenUnreachable),完全没写联网后的处理逻辑,导致联网时没有触发关闭离线页面的操作。 - 重复创建Reachability实例:SceneDelegate和OfflineViewController各建了一个Reachability对象并启动监听,逻辑分散且容易冲突。
- 刷新按钮逻辑错误:点击刷新时才设置
whenReachable回调,只有网络状态从离线变在线才会触发;如果点击时已经联网,这个回调根本不会执行,自然无法关闭页面。
修复方案
1. 统一在SceneDelegate管理网络监听
修改SceneDelegate,补充联网状态处理,添加离线页面显示状态记录,避免重复弹出:
class SceneDelegate: UIResponder, UIWindowSceneDelegate { var window: UIWindow? let reachability = try! Reachability() private var isOfflineVCShowing = false // 标记离线页面是否显示 func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) { guard let windowScene = scene as? UIWindowScene else { return } // 初始化根视图控制器(补充未登录场景) let accessToken: String? = KeychainWrapper.standard.string(forKey: "accessToken") let mainStoryboard = UIStoryboard(name: "Main", bundle: nil) let rootVC: UIViewController if accessToken != nil { rootVC = mainStoryboard.instantiateViewController(withIdentifier: "homeTabController") as! TabBarController } else { // 替换为你的登录视图控制器ID rootVC = mainStoryboard.instantiateViewController(withIdentifier: "LoginViewController") } self.window = UIWindow(windowScene: windowScene) self.window!.rootViewController = rootVC self.window!.makeKeyAndVisible() // 离线状态处理 reachability.whenUnreachable = { [weak self] _ in guard let self = self else { return } print("Not reachable (Scene delegate)") // 避免重复弹出 guard !self.isOfflineVCShowing else { return } let offlineVC = mainStoryboard.instantiateViewController(withIdentifier: "OfflineViewController") as! OfflineViewController offlineVC.modalPresentationStyle = .fullScreen self.window?.rootViewController?.present(offlineVC, animated: true) { self.isOfflineVCShowing = true } } // 联网状态处理 reachability.whenReachable = { [weak self] _ in guard let self = self else { return } print("Reachable (Scene delegate)") // 关闭离线页面 guard self.isOfflineVCShowing else { return } self.window?.rootViewController?.dismiss(animated: true) { self.isOfflineVCShowing = false } } do { try reachability.startNotifier() } catch { print("Unable to start notifier") } } // 场景销毁时停止监听 func sceneDidDisconnect(_ scene: UIScene) { reachability.stopNotifier() } }
2. 简化OfflineViewController,移除重复监听
删除OfflineViewController中的Reachability实例,刷新按钮直接检查当前网络状态:
import UIKit import Reachability class OfflineViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() // 移除原有的Reachability监听代码 } @IBAction func hitRefresh(_ sender: Any) { let reachability = try! Reachability() if reachability.connection != .unavailable { // 当前已联网,直接关闭页面 self.dismiss(animated: true, completion: nil) } else { // 提示用户仍离线 let alert = UIAlertController(title: "提示", message: "当前仍处于离线状态,请检查网络", preferredStyle: .alert) alert.addAction(UIAlertAction(title: "确定", style: .default)) self.present(alert, animated: true) } } }
额外注意事项
- 确保已正确导入Reachability框架(CocoaPods或Swift Package Manager引入)。
- 使用
[weak self]避免循环引用,防止内存泄漏。 - 原代码中未登录场景的根视图控制器初始化缺失,需补充完整。
内容的提问来源于stack exchange,提问作者Two Chains
相关产品推荐
相关产品推荐

