Reputation: 8503
If I have a class BaseViewController:UIViewController
, and I want a way to instantiate this viewController from a Xib, I could do it like this:
class func initFromXib()->BaseViewController?{
let nibName = String(NSStringFromClass(self).split(separator: ".").last ?? "")
let nib = UINib(nibName: nibName, bundle: nil)
return nib.instantiate(withOwner: nil, options: nil).first as? BaseViewController
}
Whenever I need the ViewController initialized from xib, I could then just say let vc = BaseViewController.initFromXib()
.
But let's say I have a subclass of this viewController, named HomeViewController:BaseViewController
.
If I say let home = HomeViewController.initFromXib()
, this would indeed successfully return an instance of HomeViewController
(as long as there's a Xib named as such), but as a BaseViewController
. There's nothing wrong with this, all I have to do is
let vc = HomeViewController.initFromXib() as? HomeViewController
and everything is coolioo. But is there a way to make the return type of the initFromXib
a "generic" type of the class it stems from, so that initFromXib
always returns the type of the correct class?
Upvotes: 0
Views: 115
Reputation: 448
Please use the below solution, You don't need to even use the Generics and TypeCasting as well.
extension UIViewController {
static func initWithNibName() -> Self {
return self.init(nibName: "\(self)", bundle: nil)
}
}
How to use in code?
let homeVC = HomeViewController.initWithNibName()
print(homeVC) // type is HomeViewController
Upvotes: 1
Reputation: 285290
A solution is a protocol extension with associated type, just adopt the protocol in the appropriate classes
protocol XibInitializable {
associatedtype ControllerType : UIViewController = Self
static func initFromXib() -> ControllerType?
}
extension XibInitializable where Self : UIViewController {
static func initFromXib() -> ControllerType? {
let nibName = String(describing: Self.self)
let nib = UINib(nibName: nibName, bundle: nil)
return nib.instantiate(withOwner: nil, options: nil).first as? ControllerType
}
}
Now you can write
let vc = HomeViewController.initFromXib()
Upvotes: 2
Reputation: 52108
Use generics
class func initFromXib<T: BaseViewController>()-> T?{
let nibName = String(NSStringFromClass(self).split(separator: ".").last ?? "")
let nib = UINib(nibName: nibName, bundle: nil)
return nib.instantiate(withOwner: nil, options: nil).first as? T
}
Upvotes: 1