1

考虑一个基本的 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

有没有办法修改 staticmake以便确实Dining.make()返回 aDiningBath.make()返回 a Bath

(@Hamish 指出可以使用一个initandSelf模式,方法返回被调用的类型的对象但是,我认为这是不可能的,因为instantiateViewController.)


所以。假设您有类似的代码

let d = Dining.make(blah blah)

实际上。 在运行时, d 确实变成了“餐厅”,而不是“房间”

这太妙了。

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

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

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

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

let d = Dining.make(blah blah) as! Dining

这很糟糕。怎么修?


请注意TBC 解决方案是使静态成为通用的,而不是 MartinR 在此处的答案https://stackoverflow.com/a/33200426/294884 示例代码在下面的答案中。

4

2 回答 2

3

你可以做这样的事情。

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

您可以放入RoomBase您希望其他房间继承的所有东西。

接下来,将该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()
于 2017-02-04T14:30:29.410 回答
2

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

所以问题是,在编辑时

let d = Dining.make()

“不起作用”,你必须这样做

let d = Dining.make() as! Dining

(它确实在编译时工作, d 变成了 Dining:它在编辑时不起作用。)

所以解决方案是

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的解决方案有效和/或作为通用“UIViewController 自动实例化器”更好,但这本身就是问题的答案。

于 2017-02-05T15:14:23.777 回答