2015-05-06 3 views
36

Я пытаюсь понять использование ключевого слова required в классах Swift.Зачем использовать инициализаторы в классах Swift?

class SomeClass 
{ 
    required init() { 
     // initializer implementation goes here 
    } 
} 

required не заставит меня реализовать метод в моем детском классе. Если я хочу переопределить назначенный инициализатор моего родительского класса required, мне нужно написать required, а не override. Я знаю, как это работает, но не могу понять, почему я должен это делать.

В чем преимущество required? Насколько я могу судить, такие языки, как C#, не имеют чего-то подобного и отлично работают с override.

+0

Реализация в ваших подклассах не требуется из-за наследования, что имеет смысл. Однако я также интересуюсь этой выгодой. Если подкласс (который гипотетически переопределяет 'init()', но не какой-либо требуемый инициализатор) получает init процессом, который вызвал унаследованный требуемый инициализатор, и что требуемый инициализатор впоследствии вызывает 'init()', не вызовет ли он подкласс ' переопределенный init и все хорошо? - Я думаю, что единственной хорошей причиной было бы то, что требуемый инициализатор ** не ** вызывает 'init()' на себе, поэтому переопределение «init()» никогда не будет вызвано. –

+1

Это может быть интересно в этом контексте: [Протокол func возвращает Self] (http://stackoverflow.com/questions/25645090/protocol-func-returning -self). –

ответ

57

Это на самом деле просто способ удовлетворить компилятор, чтобы убедиться, что если этот класс должен иметь какие-либо подклассы, они наследуют или реализуют этот же инициализатор. Существует сомнение по этому поводу из-за правила, что , если подкласс имеет свой собственный инициализатор, никакие инициализаторы из суперкласса не наследуются. Таким образом, суперкласс может иметь инициализатор, а подкласс - не. required преодолевает это возможность.

Одна ситуация, когда компилятор должен быть удовлетворен таким образом, включает в себя протоколы, и работает следующим образом:

protocol Flier { 
    init() 
} 
class Bird: Flier { 
    init() {} // compile error 
} 

Проблема заключается в том, что если птица была подкласс, что подкласс должен реализовать или наследовать init , и вы этого не гарантировали. Marking Bird's init как required действительно это гарантирует.

В качестве альтернативы вы можете отметить Птицу как final, что гарантирует обратное, а именно, что у нее никогда не будет подкласса.

Другой ситуация, когда у вас есть фабричный метод, который может сделать класс или его подкласс вызывая тот же инициализатор:

class Dog { 
    var name: String 
    init(name: String) { 
     self.name = name 
    } 
} 

class NoisyDog: Dog { 

} 

func dogMakerAndNamer(whattype: Dog.Type) -> Dog { 
    let d = whattype.init(name: "Fido") // compile error 
    return d 
} 

dogMakerAndNamer называют init(name:) инициализатору на собачьем или подкласс собак. Но как может компилятор убедиться, что подкласс будет иметь инициализатор init(name:)? Обозначение required успокаивает страхи компилятора.

1

Согласно documentation:

Write the required modifier before the definition of a class initializer to 
indicate that every subclass of the class must implement that initializer 

Так что да, требуется ли заставить все дочерние классы для реализации этого конструктора. Однако, это не требуется

if you can satisfy the requirement with an inherited initializer. 

Так что, если вы создали более сложные классы, которые не могут быть полностью инициализированы с родительским конструктором, вы должны реализовать требуется конструктор.

Пример из документации (с некоторым дополнительным материалом):

class SomeClass { 
    required init() { 
     // initializer implementation goes here 
    } 
} 

class SomeSubclass: SomeClass { 
    let thisNeedsToBeInitialized: String 
    required init() { 
     // subclass implementation of the required initializer goes here 
     self.thisNeedsToBeInitialized = "default value" 
    } 
} 
0

Если вы пытаетесь добавить вас есть Инициализатор в классе к югу, то вы должны следовать определенным вещам, те были объявлены в родительском классе. Поэтому убедитесь, что вы не забудете реализовать этот необходимый метод. Если вы забудете компилятор, вы получите сообщение об ошибке // fatal error, we've not included the required init() . Другая причина заключается в том, что он создает набор условий, которым должен следовать подчиненный класс, подкласс определяет его собственный инициализатор.

6

Я хочу обратить внимание на другое решение, предоставленное Required, кроме приведенного выше Мэтта.

class superClass{ 
    var name: String 
    required init(){ 
     // initializer implementation goes here 
     self.name = "Untitled" 
    } 
} 
class subClass: superClass { 
    var neakName: String = "Subclass Untitled" 

} 
let instanceSubClass = subClass() 
instanceSubClass.name  //output: "Untitled" 
instanceSubClass.neakName //output: "Subclass Untitled" 

Как вы можете проверить в приведенном выше примере, я объявил required init() на superClass, init() инициализатор суперкласса унаследовал по умолчанию subClass, Таким образом, вы в состоянии создать экземпляр Подкласс let instanceSubClass = subClass().

Но предположим, что вы хотите добавить один назначенный инициализатор на subClass, чтобы присвоить значение времени выполнения хранящемуся свойству neakName. Конечно, вы можете добавить его, но это приведет к . Никакие инициализаторы из суперкласса не будут унаследованы в subClass. Поэтому, если вы создадите экземпляр subClass, вы создадите его через свой назначенный инициализатор, как показано ниже.

class superClass{ 
    var name: String 
    init(){ 
     // initializer implementation goes here 
     self.name = "Untitled" 
    } 
} 
class subClass: superClass { 
    var neakName: String = "Subclass Untitled" 
    init(neakName: String) { 
     self.neakName = neakName 
    } 
} 
let instanceSubClass = subClass(neakName: "Bobby") 
instanceSubClass.name  //output: "Untitled" 
instanceSubClass.neakName //output: "Bobby" 

Здесь выше, вы не сможете создать экземпляр subClass, просто subClass(), Но если вы хотите, чтобы каждые подклассы суперкласса должны иметь свой собственный init() инициализатору создать прямой экземпляр с subClass(). Просто разместите ключевое слово required до init() на суперклассе, это заставит вас добавить init() инициализатор на subClass тоже - как показано ниже.

class superClass{ 
    var name: String 
    required init(){ 
     // initializer implementation goes here 
     self.name = "Untitled" 
    } 
} 
class subClass: superClass { 
    var neakName: String = "Subclass Untitled" 
    init(neakName: String) { 
     self.neakName = neakName 
    } 
} // Compiler error <------------ required `init()` must be provided by subClass. 
let instanceSubClass = subClass(neakName: "Bobby") 
instanceSubClass.name  //output: "Untitled" 
instanceSubClass.neakName //output: "Bobby" 

SO, используйте required ключевое слово, прежде чем инициализаторе на суперкласс, когда вы хотите, чтобы все подклассы должны были реализованы required initializer из суперкласса.

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