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!

5
  • 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. Commented Jun 19, 2017 at 9:48
  • 1
    It is better to use "as?" instead of "as!" for casting. Commented Jun 19, 2017 at 9:51
  • And, I must add, this question is better to be asked on codereview.stackexchange.com Commented Jun 19, 2017 at 9:53
  • Compare Return instancetype in Swift – you want a return type of Self, using a generic helper function in order to perform the cast. Commented Jun 19, 2017 at 9:54
  • 2
    Check my answer it eliminates casting at all Commented Jun 19, 2017 at 10:10

3 Answers 3

3

You can Also use like this way

let vc:MyViewController = MyViewController.instance()
Sign up to request clarification or add additional context in comments.

Comments

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)
    }
}

7 Comments

This wouldn't even compile.
@kelin As if OP's does.
@kelin check now.
@OrkhanAlikhanov, now I'm getting the following error: "Cannot convert value of type 'Self.Type' to expected argument type 'RootViewController.Type'"
@kelin I run it and it failed to cast, fixed. Now working.
|
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.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.