I'm trying to create fabric method to create UIViewController with correct nib name (to fix iOS8 default initialiser issue). To do it I have added extension:
extension UIViewController {
class func create() -> Self {
if #available(iOS 9.0, *) {
return self.init()
} else {
let clsName = NSStringFromClass(self).componentsSeparatedByString(".").last!
return self.init(nibName: clsName, bundle: nil)
}
}
}
However compiler issues error: Cannot convert value of type 'Self.Type' to expected argument type 'AnyClass' (aka 'AnyObject.Type')
in NSStringFromClass(self)
.
To fix it another extension method can be added and code rewritten to:
extension UIViewController {
private class var nibNameForInitializer:String {
return NSStringFromClass(self).componentsSeparatedByString(".").last!
}
class func create_() -> Self {
if #available(iOS 9.0, *) {
return self.init()
} else {
return self.init(nibName: self.nibNameForInitializer, bundle: nil)
}
}
}
However I want to understand the problem with first variant.
As I understand, method returning Self
is a kind of generic method. Self
can be used in many contexts (e.g. class, struct, protocol, etc), however Self.Type
matches AnyClass
only for classes.
In my case, compiler should know that Self
refers to UIViewController
and all its subclasses (since it is inside UIViewController
extension), so Self.Type
must be convertible to AnyClass
.
Do I miss anything, or it is correct behaviour, since compiler doesn't perform any additional type analysis for Self
?
This looks like a bug or an (unnecessary) restriction, so you might
consider to file a bug report at Apple. It happens only
for type methods with return type Self
. As a workaround, you can write
let clsName = NSStringFromClass(self as! AnyClass).componentsSeparatedByString(".").last!
which compiles and seems to work as expected.
But there is a simpler way to get the same result:
// Swift 2:
let clsName = String(self)
// Swift 3:
let clsName = String(describing: self)