返回UIViewController静态中的子类

时间:2017-02-04 13:50:18

标签: generics casting swift3 protocols associated-types

考虑基础UIViewController类......

class Rooms: UIViewController {
    class func instantiate()->Rooms {
    }

    static func make()->Rooms {
        let emplacedAndSetup = self.instantiate()
        // various kodes here
        // very likely put s.view somewhere
        return emplacedAndSetup
    }

    sundryOtherFunctionality()
}

(注意self.之前的instantiate(),这似乎是获得""实例化的必要条件。)

每个子类都知道自己的故事板ID如何用于instantiateViewController

class Dining: Rooms {
    override class func instantiate()->Dining { // returns a "Dining"
        let d = stbd.instantiateViewController(
            withIdentifier: "Some Specific Scene") as! Dining
        return d
    }
}
class Bath: Rooms {
    override class func instantiate()->Bath { // returns a "Bath"
        let b = stbd.instantiateViewController(
            withIdentifier: "Some Other Scene") as! Bath
        return b
    }
}

你可以这样做,

let d  = Dining.make()
let r  = Bath.make()

唯一的小问题是,它返回基类。 但见下文。 所以在练习中你必须

let d  = Dining.make() as! Dining
let r  = Bath.make() as! Bath

有没有办法修改静态make,以便确实Dining.make()会返回DiningBath.make()会返回Bath

(@Hamish指出可以使用initSelf模式,Method that returns object of type which was called from但是,我认为由于{{1}而无法实现}。)

因此。假设你有像

这样的代码
instantiateViewController
事实上。 在运行时,d确实成为" Dining"而不是" Room"

太棒了。

但是。如果您在IDE中执行此操作

let d = Dining.make(blah blah)

它失败了 - 它认为d将成为一个房间, 不是餐饮

因此,您的所有代码都必须如下所示:

let d:Dining = Dining.make(blah blah)

哪个很糟糕。怎么解决?

注意只是TBC的解决方案是使静态变为通用,而不是像MartinR在这里的回答https://stackoverflow.com/a/33200426/294884以下答案中的示例代码。

2 个答案:

答案 0 :(得分:3)

你可以这样做。

class RoomBase: RoomProtocol {
    // things common to every room go here
    required init() {}
}
  

您可以将RoomBase所有想要其他房间继承的内容放入。{/ p>

接下来,将make()方法放入协议扩展名中。

protocol RoomProtocol: class {
    init()
}

extension RoomProtocol where Self: RoomBase {
    static func make() -> Self {
        let room = Self()
        // set up
        return room
    }
}

现在你可以写

class Dining: RoomBase {}
class Bath: RoomBase { }

此代码可以使用

let dining: Dining = Dining.make()
let bath: Bath = Bath.make()

答案 1 :(得分:2)

我不想提供我自己的答案,但解决方案是..

所以问题是,在编辑时

let d = Dining.make()

"没有工作",你必须这样做

let d = Dining.make() as! Dining

在编译时工作 ,d成为餐饮:在编辑时它没有&#34;工作&#34;)< / p>

所以解决方案是

static func make()->Rooms {
    let emplacedAndSetup = self.instantiate()
    return emplacedAndSetup
}

变为

static func make<T: Rooms>()->T {
    let emplacedAndSetup = self.instantiate() as! T
    return emplacedAndSetup
}

这就是它。

注意 - 它完全可能AppzForLife的解决方案有效和/或更好作为通用&#34; UIViewController自动实例化器&#34;,但这个是问题本身的答案。