I would like to traverse the view controller hierarchy in Swift and find a particular class. Here is the code:
extension UIViewController{
func traverseAndFindClass<T : UIViewController>() -> UIViewController?{
var parentController = self.parentViewController as? T?
^
|
|
// Error: Could not find a user-defined conversion from type 'UIViewController?' to type 'UIViewController'
while(parentController != nil){
parentController = parentController!.parentViewController
}
return parentController
}
}
Now, I know that the parentViewController property returns an optional UIViewController, but I do not know how in the name of God I can make the Generic an optional type. Maybe use a where clause of some kind ?
Your method should return T?
instead of UIViewController?
, so that the generic type
can be inferred from the context. Checking for the wanted class has also to
be done inside the loop, not only once before the loop.
This should work:
extension UIViewController {
func traverseAndFindClass<T : UIViewController>() -> T? {
var currentVC = self
while let parentVC = currentVC.parentViewController {
if let result = parentVC as? T {
return result
}
currentVC = parentVC
}
return nil
}
}
Example usage:
if let vc = self.traverseAndFindClass() as SpecialViewController? {
// ....
}
Update: The above method does not work as expected (at least not in the Debug configuration) and I have posted the problem as a separate question: Optional binding succeeds if it shouldn't. One possible workaround (from an answer to that question) seems to be to replace
if let result = parentVC as? T { ...
with
if let result = parentVC as Any as? T { ...
or to remove the type constraint in the method definition:
func traverseAndFindClass<T>() -> T? {
Update 2: The problem has been fixed with Xcode 7, the
traverseAndFindClass()
method now works correctly.
Swift 4 update:
extension UIViewController {
func traverseAndFindClass<T : UIViewController>() -> T? {
var currentVC = self
while let parentVC = currentVC.parent {
if let result = parentVC as? T {
return result
}
currentVC = parentVC
}
return nil
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With