2017-02-04 6 views
1

Рассмотрим базовый класс UIViewController ...Возврат подкласс 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(), который, как представляется, необходимо получить «что» cоздателем экземпляров.)

Каждый подкласс знает свой раскадровки идентификатор, как использовать для 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() возвратит Dining и Bath.make() возвратит Bath?

(@Hamish отметил, что можно было бы использовать init и Self шаблон, Method that returns object of type which was called from Однако, я думаю, что это не представляется возможным из-за 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 Пример кода в ответ ниже.

+0

Вы можете использовать инициализатор 'required' вместо статического метода' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' ', см., например, [этот вопрос и ответы] (http://stackoverflow.com/q/38621563/2976878). – Hamish

+0

Хм, я понимаю @Hamish, я слишком упростил код примера - это контроллер представлений, который становится на лету. Редактирование .. – Fattie

+0

Похоже, вы в основном [просто хотите это] (http://stackoverflow.com/q/33200035/2976878) без параметров для метода 'instantiateFromStoryboard', как вы сами определяете их. – Hamish

ответ

1

Я не хотел, чтобы обеспечить свой ответ, но решение ..

Таким образом, проблема заключается в том, что во время редактора

let d = Dining.make() 

«не работает», вы должны сделать это

let d = Dining.make() as! Dining 

(Это делает работу во время компиляции, d становится Питание: он не «работает» во время редактирования .)

Таким образом, раствор

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», но это ответ на вопрос сам по себе.

2

Вы можете сделать что-то вроде этого.

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() 
+1

@JoeBlow: Я вижу вашу мысль о классе «Комнаты», который в вашем сценарии не может быть представлен как протокол. Позвольте мне немного подумать об этом. Наконец, о «абстрактных методах» я все же предлагаю избегать их, но я уважаю вашу точку зрения. –

+0

@JoeBlow Хорошая точка. Просто переместил эту часть в конце моего ответа. –

+0

@JoeBlow Я обновил свой ответ, дайте мне знать, что вы думаете –

Смежные вопросы