2016-10-25 2 views
21

Рассмотрит класс последующего (в равной степени применим к структурам, а) в модуле:Почему открытый класс/структура в Swift требует явного публичного инициализатора?

public class Foo { 
    public func bar() { 
     // method body 
    } 
} 

Обратите внимание, что не имеет явный инициализатор; этот пример не требует специальной инициализации. Этот класс будет доступен для других модулей, поскольку он отмечен public. Однако, когда код вне модуля пытается инициализировать его, компилятор жалуется:

let foo = Foo() // 'Foo' initializer is inaccessible due to 'internal' protection level 

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

public class Foo { 
    public init() { 
     // This initializer intentionally left empty 
    } 

    public func bar() { 
     // do something useful 
    } 
} 

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

Существует связанный с этим вопрос here, относящийся к модульному тестированию, но я нахожу, что он на самом деле не лежит в основе философии дизайна того, что я считаю неожиданным.

+2

Связанный: [Как я могу опубликовать по умолчанию инициализатор-член для структур в Swift?] (Http://stackoverflow.com/questions/26224693/how-can-i-make-public-by -default-the-member-wise-initialiser-for-structs-in-swif) – Hamish

ответ

15

Маркировка класса public необязательно означает, что разработчик хочет, чтобы класс был инициализирован публично. Например, я часто пишу базовые классы, которые существуют исключительно для меня, чтобы иметь возможность подклассифицировать их. Я даю эти суперклассы internal инициализаторы, чтобы их подклассы могли получить к ним доступ, но те, которые находятся во внешнем мире, не должны использовать их напрямую. Например, Operation в Foundation не имеет доступных инициализаторов, но класс является общедоступным. Он просто предназначен для подкласса. Это рассматривается как абстрактный класс в Objective-C.

Поскольку Swift не содержит явной поддержки абстрактных классов, действие создания класса public, но без публичных инициализаторов в основном служит абстрактным классом (за исключением того, что каждая функция должна по-прежнему иметь определение по умолчанию либо в самом классе, либо в некоторое расширение протокола).

Имея это в виду, вот несколько правил Swift:

  • Если ваш класс помечен private, все переменные, inits и функции по умолчанию будет private.
  • Если ваш класс помечен internal (по умолчанию), public или open, все переменные, inits и функции будут по умолчанию равны internal.
  • Суперкласс класса должен быть как минимум доступным.
  • классы и классы, объявленные public в Objective-C, импортируются в Swift как open из-за отсутствия такого различия в Objective-C.

Это второй, на котором вы работаете. По умолчанию init выбирает значение по умолчанию internal, потому что последнее, что хочет сделать Swift, - это открыть ваш init как открытый API, если это явно не указано.

Примечание: В моих тестах (по крайней мере, на детской площадке), кажется, что с введением fileprivate:

  • Если класс объявлен private или fileprivate, кажется, что члены класса по умолчанию для fileprivate, если только явно аннотируется private.
+0

Ваши предложения по использованию этой «функции» для создания абстрактных классов очень интересны и что-то, что я не рассматривал. –

+0

Это действительно глупо (как и несколько быстрых решений), тем более, что стремительный переход от подкласса к использованию протоколов. Если классный писатель намеревается быть абстрактным, ему придется объявить инициализатор внутренним. или swift должен иметь только абстрактное ключевое слово. –

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