String(describing: self)

I’m trying to create a static method for instantiating a UIViewController and getting some compile errors. I think it hinges on the inability to get the class name. This works in Xcode 9, not sure why it isn’t working in Fire (Version 10.0.0.2321).

Xcode version:

class MainViewController: UIViewController {
	static func instantiate() -> MainViewController {
		let fullName = String(describing: self)
		let className = fullName.components(separatedBy: ".").last!
		let storyboard = UIStoryboard(name: "Storyboard", bundle: Bundle.main)
		let controller = storyboard.instantiateViewController(withIdentifier: className) as! MainViewController
		
		return controller
	}
}

Fire version:

@IBObject public class MainViewController: UIViewController {
    static func instantiate() -> MainViewController {
        let fullName = String(describing: self)
        let className = fullName.components(separatedBy: ".").last!
        let storyboard = UIStoryboard(name: "Storyboard", bundle: Bundle.mainBundle)
        let controller = storyboard.instantiateViewController(withIdentifier: className) as! MainViewController

        return controller
    }
}

it looks like this was renamed from

    public convenience init(reflecting subject: Object) {

to

    public convenience init(describing subject: Object) {

because what would be there fun, if Apple didn’t change the Swift APIs every three weeks ;). I’ll adjust ours to match, for the next build; I see components(separatedBy:) is also missing (or rather, got renamed from func split(_ separator: String) -> [String], so I’ll adjust that one, as well.

For now, this version compiles:

@IBObject public class MainViewController: UIViewController {
    static func instantiate() -> MainViewController {
        let fullName = String(reflecting: self)
        let className = fullName.componentsSeparated(by: ".").lastObject!
        let storyboard = UIStoryboard(name: "Storyboard", bundle: Bundle.mainBundle)
        let controller = storyboard.instantiateViewController(withIdentifier: className) as! MainViewController

        return controller
    }
}

Wow, then mind boggles. turns out there’s BOTH

init<Subject>(describing: Subject)
init<Subject>(reflecting: Subject)

and (according to specs/docs) they only differ in the order in which they check for what interfaces the object implements… I’ve adjusted accordingly.

On an unrelated note, relying on this does seem the wring way to determine the class name, as String(reflecting: self) will return the result of one of three methods self might implement to an undefined value determined by the swift runtime, if neither is implemented. It may well be that that happens to be the class name, in current Apple Swift, but that’d not seem like something you should rely on. you’ll want to use self.class.description on Cocoa, or `dynamicType(self).ToString, on cross-platform Elements code.

The final goal is to make a protocol extension for UIViewController where I can instantiate a class in this manner. Obviously, the references to MainViewController will become Self

I’ll look at the dynamicType(self).ToString option you presented.

I didn’t even know Fire could support UIViewControllers/storyboards etc…what can you actually do with this?

Full product development. Storyboard edits are done with Xcode. As usual, I’m testing the limits of Fire trying to make it a full replacement of Xcode and Android Studio.

Fwiw, Fire/Elements fully supports using Storyboards. You will edit them in Xcode, but the build chain and Elements code fully supports and interacts with them, same as Apple Swift or Obhjective-C code would,

1 Like

@mh, I think the Fire product is fantastic. I think it will be better once Swift 5 comes out with ABI stability and I can feel confident in sharing my logic .swift files between Fire and Xcode projects.

1 Like

Hmm interesting, but TBH I’m not really a fan of Storyboards, prefer the Android way of building activities/layouts etc. (esp. with kotlin). But I’m not primarily an app developer.