无需强制类型转换访问UIViewController类属性?优化辅助类判断逻辑
问题1:无需强制类型转换访问UIViewController的属性
其实你可以通过协议+扩展的方式优雅解决这个问题,不用每次写as! SomeVC这种生硬的强转代码。举个实际场景的例子:
假设你有多个VC都自定义了contentView属性,先定义一个协议来统一这个属性的接口:
protocol ContentDisplayable { var contentView: UIView! { get set } }
然后让你的各个UIViewController子类遵守这个协议:
class HomeVC: UIViewController, ContentDisplayable { @IBOutlet weak var contentView: UIView! // ... 其他业务代码 } class ProfileVC: UIViewController, ContentDisplayable { @IBOutlet weak var contentView: UIView! // ... 其他业务代码 }
之后不管是在辅助类还是其他工具代码里,只要拿到的是ContentDisplayable类型的对象,就能直接访问contentView,完全不需要类型转换:
class ContentHelper { static func showContent(for controller: ContentDisplayable) { controller.contentView.isHidden = false // 直接操作属性,无强转,类型安全 } }
如果是系统UIViewController自带的属性(比如navigationItem),那本来就不需要转换——只要你确定对象是UIViewController类型,直接访问即可。但自定义属性的场景下,上面的协议方案是最常用且优雅的。
另外还有一种泛型方案,适合需要同时访问VC原生属性和自定义属性的场景:
class ContentHelper { static func updateContent<T: UIViewController & ContentDisplayable>(for controller: T) { controller.contentView.isHidden = false // 同时还能直接访问UIViewController的原生属性,比如controller.navigationItem.title = "已显示" } }
问题2:用单个if语句替代多个控制器的独立判断
当然可以!核心是把重复的类型判断逻辑抽象,不用针对每个VC写单独的if controller is XXXVC。这里给你两种实用方案:
方案1:用协议标记需要处理的VC
定义一个标记协议(也可以带方法),让所有需要执行显示/隐藏逻辑的VC遵守它:
protocol ContentToggleable {} // 让需要处理的VC遵守协议 class HomeVC: UIViewController, ContentToggleable {} class ProfileVC: UIViewController, ContentToggleable {}
然后在辅助类的函数里,只需要一个判断就能覆盖所有目标VC:
class ContentHelper { static func toggleContent(for controller: UIViewController) { if let targetVC = controller as? ContentToggleable { // 统一处理显示/隐藏逻辑,结合问题1的协议还能直接访问自定义属性 if let displayableVC = targetVC as? ContentDisplayable { displayableVC.contentView.isHidden = !displayableVC.contentView.isHidden } } // 不需要处理的VC直接跳过 } }
方案2:用类型集合做判断
如果不想修改VC的代码去遵守协议,也可以把需要处理的VC类型放到一个集合里,通过类型匹配来判断:
class ContentHelper { // 定义需要处理的VC类型集合 private static let targetControllerTypes: [UIViewController.Type] = [HomeVC.self, ProfileVC.self] static func toggleContent(for controller: UIViewController) { if targetControllerTypes.contains(where: { type(of: controller) == $0 }) { // 统一执行显示/隐藏逻辑,同样可以结合问题1的协议访问属性 if let displayableVC = controller as? ContentDisplayable { displayableVC.contentView.isHidden = !displayableVC.contentView.isHidden } } } }
如果不同VC的显示/隐藏逻辑有细微差异,还可以用闭包字典来映射类型和对应逻辑,既不用写一堆if分支,还能保留个性化处理:
class ContentHelper { private static let handlerMap: [UIViewController.Type: (UIViewController) -> Void] = [ HomeVC.self: { vc in if let homeVC = vc as? HomeVC { homeVC.contentView.isHidden = !homeVC.contentView.isHidden homeVC.homeSpecificLabel.isHidden = !homeVC.homeSpecificLabel.isHidden } }, ProfileVC.self: { vc in if let profileVC = vc as? ProfileVC { profileVC.contentView.isHidden = !profileVC.contentView.isHidden profileVC.avatarImageView.isHidden = !profileVC.avatarImageView.isHidden } } ] static func toggleContent(for controller: UIViewController) { // 直接通过类型查找对应的处理逻辑,无需多个if判断 handlerMap[type(of: controller)]?(controller) } }
内容的提问来源于stack exchange,提问作者SKT
相关产品推荐
相关产品推荐

