2

I would like to ask something about type-casting in Swift.

There are 2 classes.

  1. RootViewController
  2. MyViewController

and the class hierarchy is like below:

class RootViewController: UIViewController {

}

class MyViewController: RootViewController {

}

and, I want to simply call instance function to create an instance from xib file. so I implemented below function in RootViewController.

Objective-C

+ (instancetype)instance {
    return [[[self class] alloc] initWithNibName:NSStringFromClass([self class]) bundle:nil];
}

Swift

public class func instance<T:RootViewController>() -> T {
    let type = self as UIViewController.Type
    let name = NSStringFromClass(type).components(separatedBy: ".").last!
    let instance = type.init(nibName: name, bundle: nil)
    return instance as! T
}

and, usage is like below.

Objective-C

MyViewController *vc = [MyViewController instance];

Swift

let vc = MyViewController.instance() as! MyViewController

Question:

Do I have to always cast the type of instance using as! MyViewController in Swift? Or can anybody advise me a better approach in Swift?

Any help would be appreciated!

Joey
  • 2,912
  • 2
  • 27
  • 32
  • I don't see any problem or question here. I would personally avoid using `instance` or any other factory methods in swift, because you can't use `Self` as a return type. Use regular `init` methods instead. – kelin Jun 19 '17 at 09:48
  • 1
    It is better to use "as?" instead of "as!" for casting. – Fattaneh Talebi Jun 19 '17 at 09:51
  • And, I must add, this question is better to be asked on https://codereview.stackexchange.com/ – kelin Jun 19 '17 at 09:53
  • Compare [Return instancetype in Swift](https://stackoverflow.com/q/33200035/2976878) – you want a return type of `Self`, using a generic helper function in order to perform the cast. – Hamish Jun 19 '17 at 09:54
  • 2
    Check my answer it eliminates casting at all – Orkhan Alikhanov Jun 19 '17 at 10:10

3 Answers3

3

You can Also use like this way

let vc:MyViewController = MyViewController.instance()
hardikdevios
  • 1,779
  • 14
  • 33
2
class RootViewController: UIViewController {
    public class func instance() -> Self {
        func inner<T: RootViewController>(type: T.Type) -> T {
            let name = NSStringFromClass(type).components(separatedBy: ".").last!
            let type1 = type as UIViewController.Type
            let instance = type1.init(nibName: name, bundle: nil)
            return instance as! T
        }
        return inner(type: self)
    }
}

I would suggest creating an extension method:

extension UIViewController {
    public class func instance() -> Self {
        func inner<T: UIViewController>(type: T.Type) -> T {
            let name = NSStringFromClass(type).components(separatedBy: ".").last!
            return T(nibName: name, bundle: nil)
        }
        return inner(type: self)
    }
}
Orkhan Alikhanov
  • 9,122
  • 3
  • 39
  • 60
0

Okay you can instantiate in these three ways:

  1. Swift inference to Type:

    let myVC = RootViewController.instance()   //Swift will automatically infer the type
    
  2. Explicitly telling the Type:

    let myVC: RootViewController = RootViewController.instance()
    
  3. Casting to your Type:

    let myVC = RootViewController.instance() as! RootViewController
    

All these three are valid.

nayem
  • 7,285
  • 1
  • 33
  • 51