Есть ли у Swift модификаторы доступа?

257

В Objective-C данные экземпляра могут быть public, protected или private. Например:

@interface Foo : NSObject
{
  @public
    int x;
  @protected:
    int y;
  @private:
    int z;
  }
-(int) apple;
-(int) pear;
-(int) banana;
@end

Я не нашел упоминания о модификаторах доступа в ссылке Swift. Возможно ли ограничить видимость данных в Swift?

  • 0
    И я нет. Apple должна, по крайней мере, ввести этикет для рядовых, как в питоне, с префиксом подчеркивания.
  • 0
    Добавлен обновленный ответ для финальной версии Xcode 6.1.1
Показать ещё 1 комментарий
Теги:
access-modifiers

17 ответов

357
Лучший ответ

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


1. open и public

Включить сущность, которая будет использоваться вне определяющего модуля (цели). Обычно вы используете доступ к open или public при указании открытого интерфейса на фреймворк.

Однако доступ open применяется только к классам и членам класса, и он отличается от доступа public следующим образом:

  • public классы и члены класса могут быть только подклассифицированы и переопределены в определяющем модуле (цели).
  • open классы и члены класса могут быть подклассифицированы и переопределены как внутри, так и вне определяющего модуля (цели).

// First.framework – A.swift

open class A {}

// First.framework – B.swift

public class B: A {} // ok

// Second.framework – C.swift

import First

internal class C: A {} // ok

// Second.framework – D.swift

import First

internal class D: B {} // error: B cannot be subclassed

2. internal

Позволяет использовать объект в определяющем модуле (цели). Обычно вы используете доступ internal при определении приложений или внутренней структуры фреймворка.

// First.framework – A.swift

internal struct A {}

// First.framework – B.swift

A() // ok

// Second.framework – C.swift

import First

A() // error: A is unavailable

3. fileprivate

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

// First.framework – A.swift

internal struct A {

    fileprivate static let x: Int

}

A.x // ok

// First.framework – B.swift

A.x // error: x is not available

4. private

Ограничивает использование объекта в его объявлении. Обычно вы используете private доступ, чтобы скрыть детали реализации определенной части функциональности, когда эти данные используются только в пределах одного объявления.

// First.framework – A.swift

internal struct A {

    private static let x: Int

    internal static func doSomethingWithX() {
        x // ok
    }

}

A.x // error: x is unavailable
  • 37
    Может ли кто-нибудь объяснить мне, почему это не имеет большого значения?
  • 1
    Я не знаю, хорошие ли это новости, поскольку «протоколы» с фабриками приводят к более чистому дизайну.
Показать ещё 23 комментария
18

Когда вы говорите о создании "частного метода" в Swift или ObjC (или ruby ​​или java или...), эти методы не являются частными. Там нет фактического контроля доступа вокруг них. Любой язык, который предлагает даже небольшую интроспекцию, позволяет разработчикам получать эти значения извне класса, если они действительно хотят.

Итак, о чем мы сейчас говорим, это способ определить открытый интерфейс, который просто представляет функциональность, которую мы хотим, и "скрывает" остальное, что мы рассматриваем "private".

Механизм Swift для декларирования интерфейсов - это protocol, и он может быть использован для этой цели.

protocol MyClass {
  var publicProperty:Int {get set}
  func publicMethod(foo:String)->String
}

class MyClassImplementation : MyClass {
  var publicProperty:Int = 5
  var privateProperty:Int = 8

  func publicMethod(foo:String)->String{
    return privateMethod(foo)
  }

  func privateMethod(foo:String)->String{
    return "Hello \(foo)"
  }
}

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

Таким образом, до тех пор, пока вы используете MyClass вместо MyClassImplementation в своих типах параметров и т.д., все должно работать:

func breakingAndEntering(foo:MyClass)->String{
  return foo.privateMethod()
  //ERROR: 'MyClass' does not have a member named 'privateMethod'
}

Есть некоторые случаи прямого назначения, где вы должны быть явным с типом вместо того, чтобы полагаться на Свифт, чтобы сделать вывод, но это вряд ли кажется нарушителем сделки:

var myClass:MyClass = MyClassImplementation()

Использование протоколов таким образом семантично, достаточно кратким, и для моих глаз очень похоже на расширенные классы, которые мы использовали для этой цели в ObjC.

  • 0
    Если протоколы не позволяют нам иметь аргумент по умолчанию, как я могу создать открытый метод с необязательными параметрами, который по-прежнему соответствует протоколу?
  • 0
    Я не понимаю, что вы имеете в виду. Следующее создает открытый метод с необязательным параметром. Похоже, проблем нет: gist.github.com/anonymous/17d8d2d25a78644046b6
Показать ещё 2 комментария
16

Насколько я могу судить, нет ключевых слов "public", 'private' или "protected". Это предполагает, что все общедоступно.

Однако Apple может ожидать, что люди будут использовать "protocols" (называемые интерфейсами остальным миром) и factory шаблон дизайна, чтобы скрыть сведения о типе реализации.

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

  • 0
    Это хорошо, так как это также уменьшает сцепление и может облегчить тестирование.
  • 4
    Это сработало бы лучше, если бы был способ скрыть класс реализации протокола, но, похоже, его нет.
Показать ещё 2 комментария
13

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

Пример:

protocol HuhThing {
  var huh: Int { get set }
}

func HuhMaker() -> HuhThing {
   class InnerHuh: HuhThing {
    var innerVal: Int = 0
    var huh: Int {
      get {
        return mysteriousMath(innerVal)
      }

      set {
       innerVal = newValue / 2
      }
    }

    func mysteriousMath(number: Int) -> Int {
      return number * 3 + 2
    }
  }

  return InnerHuh()
}

HuhMaker()
var h = HuhMaker()

h.huh      // 2
h.huh = 32 
h.huh      // 50
h.huh = 39
h.huh      // 59

innerVal и mysteriousMath скрыты здесь извне, а попытка проникнуть в объект должна привести к ошибке.

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

  • 0
    хорошо, я тоже думал об этом решении, но объясните мне, почему я не могу получить доступ к h.huh.innerVal?
  • 0
    Swift безопасен от типов, и единственное, что внешний мир знает о h, - это то, что он соответствует HuhThing. HuhThing не содержит никакой информации о свойстве, называемом innerVal, и поэтому попытка доступа к нему является ошибкой.
Показать ещё 8 комментариев
11

Swift 4

Как указано в Swift Documentation - Контроль доступа, Swift 4 имеет 5 элементов управления доступом:

  • открыть и общедоступный: можно получить доступ из своих модулей и любых модулей, импортирующих определяющий модуль.

  • внутренний: доступ к ним возможен только из их модулей. Это уровень доступа по умолчанию.

  • fileprivate и private: доступ к ним возможен только в ограниченном объеме, где вы их определяете.



В чем разница между open и public?

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

public позволяют использовать классы из другого модуля, но не наследовать их, т.е. они не могут быть подклассифицированы из других модулей. Кроме того, они позволяют членам из других модулей использовать их, но НЕ переопределять их. Для своих модулей они имеют одинаковую открытую логику (они позволяют классам использовать и наследовать их, они позволяют членам использовать и переопределять их).


В чем разница между fileprivate и private?

fileprivate можно получить из всех своих файлов.

закрытый доступен только из их единого объявления и расширений этого объявления, которые находятся в одном файле; Например:

// Declaring "A" class that has the two types of "private" and "fileprivate":
class A {
    private var aPrivate: String?
    fileprivate var aFileprivate: String?

    func accessMySelf() {
        // this works fine
        self.aPrivate = ""
        self.aFileprivate = ""
    }
}

// Declaring "B" for checking the abiltiy of accessing "A" class:
class B {
    func accessA() {
        // create an instance of "A" class
        let aObject = A()

        // Error! this is NOT accessable...
        aObject.aPrivate = "I CANNOT set a value for it!"

        // this works fine
        aObject.aFileprivate = "I CAN set a value for it!"
    }
}


В чем разница между Swift 3 и Swift 4 Access Control?

Как упоминалось в предложении SE-0169, единственное уточнение было добавлено в Swift 4, так это то, что область управления частным доступом расширение доступно для доступа из расширений этой декларации в том же файле; Например:

struct MyStruct {
    private let myMessage = "Hello World"
}

extension MyStruct {
    func printMyMessage() {
        print(myMessage)
        // In Swift 3, you will get a compile time error:
        // error: 'myMessage' is inaccessible due to 'private' protection level

        // In Swift 4 it should works fine!
    }
}

Таким образом, нет необходимости объявлять myMessage как fileprivate для доступа во весь файл.

Заметка боковой панели: если вы столкнулись с проблемами, связанными с некомпилированием Swift 4 с перенесенным старым проектом Swift 3, вы можете проверить этот Q & A.к югу >

10

Как и Xcode 6 beta 4, Swift имеет модификаторы доступа. Из примечаний к выпуску:

Управление доступом Swift имеет три уровня доступа:

  • частные объекты могут быть доступны только из исходного файла, где они определены.
  • внутренние объекты могут быть доступны в любом месте объекта, где они определены.
  • публичные объекты могут быть доступны из любого места в пределах целевого объекта и из любого другого контекста, который импортирует текущий целевой модуль.

Неявное значение по умолчанию - internal, поэтому в пределах целевого приложения вы можете оставить модификаторы доступа, кроме случаев, когда вы хотите быть более ограничительными. В целевой среде (например, если вы внедряете фреймворк для совместного использования кода между приложением и расширением для общего доступа или "Сегодня" ), используйте public для обозначения API, который вы хотите предоставить клиентам вашей инфраструктуры.

  • 0
    Ну, этот ответ был действителен в предыдущих версиях Swift, похоже, он больше не действителен :), пожалуйста, проверьте мой ответ .
7

Swift 3.0 предоставляет пять различных элементов управления доступом:

  • открыть
  • общественности
  • внутренний
  • fileprivate
  • частным

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

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

Доступ к файлам ограничивает использование объекта в собственном определяющем исходном файле. Использовать доступ к файлам, чтобы скрыть детали реализации конкретной функциональности, когда эти детали используются во всем файле.

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

Открытый доступ - это наивысший (наименее ограничительный) уровень доступа, а закрытый доступ - это самый низкий (самый ограничительный) уровень доступа.

Уровни доступа по умолчанию

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

Заметка о выпуске по теме:

Классы, объявленные как public, больше не могут быть подклассифицированы вне их определяющий модуль и методы, объявленные как публичные, больше не могут быть переопределены вне их определяющего модуля. Чтобы позволить классу быть внешне подклассифицированный или метод, который должен быть переопределен извне, объявите они являются открытыми, что является новым уровнем доступа, недоступным для общественности. импортный Objective-C классы и методы теперь импортируются как открытые, а чем общественность. Модульные тесты, которые импортируют модуль с помощью импорта @testable все равно будет разрешено подкласс как открытых, так и внутренних классов как переопределение общедоступных или внутренних методов. (SE-0117)

Дополнительная информация и информация: Быстрый язык программирования (контроль доступа)

  • 0
    Ну, этот ответ был действителен в предыдущих версиях Swift, похоже, он больше не действителен :), пожалуйста, проверьте мой ответ .
5

В бета-версии 6 в документации указано, что существуют три разных модификатора доступа:

  • Public
  • Внутренний
  • Частный

И эти три применяются к классам, протоколам, функциям и свойствам.

public var somePublicVariable = 0
internal let someInternalConstant = 0
private func somePrivateFunction() {}

Подробнее см. Контроль доступа.

  • 0
    Должен быть защищенный модификатор, который облегчает создание классов с большей безопасностью.
  • 0
    Ну, этот ответ был действителен в предыдущих версиях Swift, похоже, он больше не действителен :), пожалуйста, проверьте мой ответ .
4

Механизмы контроля доступа как введены в Xcode 6:

Swift предоставляет три разных уровня доступа для объектов внутри вашего кода. Эти уровни доступа относятся к исходному файлу, в котором сущность определена, а также относительно модуля, к которому принадлежит исходный файл.

  • Открытый доступ позволяет сущности использоваться в любом исходном файле из их определяющего модуля, а также в исходном файле из другого модуля, который импортирует определяющий модуль. Обычно вы используете открытый доступ при указании открытого интерфейса на фреймворк.
  • Внутренний доступ позволяет сущности использоваться в любом исходном файле из своего определяющего модуля, но не в каком-либо исходном файле вне этого модуля. Обычно вы используете внутренний доступ при определении приложений или внутренней структуры фреймворка.
  • Частный доступ ограничивает использование объекта в собственном определяющем исходном файле. Используйте частный доступ, чтобы скрыть детали реализации определенной функциональности.

Общий доступ - это наивысший (наименее ограничительный) уровень доступа, а закрытый доступ - самый низкий (или самый ограничивающий) уровень доступа.

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

Еще один момент для меня, о котором говорится в ссылке выше, заключается в том, что вы не можете "обновить" уровень доступа. Если вы подклассируете что-то, вы можете ограничить его больше, но не наоборот.

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

  • 0
    Ну, этот ответ был действителен в предыдущих версиях Swift, похоже, он больше не действителен :), пожалуйста, проверьте мой ответ .
4

Нет, это невозможно. Нет никаких частных/защищенных методов и переменных вообще.

Все публично.

  • 1
    Каков твой источник?
  • 1
    Этот комментарий является точным для текущего семени.
Показать ещё 4 комментария
3

Теперь в бета-версии 4 они добавили модификаторы доступа в Swift.

from Xcode 6 beta 4 realese notes:

Управление доступом Swift имеет три уровня доступа:

  • private объекты могут быть доступны только из исходного файла, где они определены.
  • internal объекты могут быть доступны в любом месте объекта, где они определены.
  • public объекты могут быть доступны из любой точки цели и из любого другого контекста который импортирует текущий модуль целей.

По умолчанию большинство объектов в исходном файле имеют внутренний доступ. Это позволяет разработчикам приложений чтобы в значительной степени игнорировать контроль доступа, позволяя разработчикам инфраструктуры полностью контролировать API рамки.

  • 0
    Можете ли вы опубликовать ссылку на это?
  • 0
    Ну, этот ответ был действителен в предыдущих версиях Swift, похоже, он больше не действителен :), пожалуйста, проверьте мой ответ .
3

Один из вариантов, который вы можете использовать, - это превратить создание экземпляра в функцию и предоставить соответствующие конструкторы и конструкторы в конструкторе:

class Counter {
    let inc: () -> Int
    let dec: () -> Int

    init(start: Int) {
        var n = start

        inc = { ++n }
        dec = { --n }
    }
}


let c = Counter(start: 10)

c.inc()  // 11
c.inc()  // 12
c.dec()  // 11
2

Swift 3 и 4 привели к большим изменениям и для уровней доступа к переменным и методам. У Swift 3 и 4 теперь есть 4 разных уровня доступа, где открытый/общедоступный доступ - это самый высокий (наименее ограничительный) уровень доступа и закрытый доступ самый низкий (самый ограничительный) уровень доступа:

  • частные функции и члены могут быть доступны только из области самой сущности (struct, class,...) и ее расширений (в Swift 3 также были ограничены расширения)
  • fileprivate, и члены могут быть доступны только из исходного файла, где они объявлены.
  • внутренние функции и члены (которые по умолчанию, если вы явно не добавляете ключевое слово уровня доступа) могут быть доступны в любом месте цели, где они определены. Вот почему TestTarget не имеет автоматического доступа ко всем источникам, они должны быть помечены как доступные в инспекторе файлов xCode.
  • открытые или общедоступные функции и члены могут быть доступны из любого места в пределах целевого объекта и из любого другого контекста, который импортирует текущий целевой модуль.

Интересный:

Вместо того, чтобы отмечать каждый отдельный метод или член как "private", вы можете покрыть некоторые методы (например, обычно вспомогательные функции) в расширении класса/структуры и пометить все расширение как "Private".

class foo { }

private extension foo {
    func somePrivateHelperFunction01() { }
    func somePrivateHelperFunction02() { }
    func somePrivateHelperFunction03() { }
}

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

Документация Apple

  • 0
    Ну, этот ответ был действителен в предыдущих версиях Swift, похоже, он больше не действителен :), пожалуйста, проверьте мой ответ .
  • 0
    обновлено для Swift 4: Спасибо @Ahmad F
1

https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/AccessControl.html#//apple_ref/doc/uid/TP40014097-CH41-ID3

ЗАПУСК SWIFT 2.2;)

  • Публичный
  • Внутренний
  • Частный

По умолчанию Внутренний

1

Надеемся сэкономить время для тех, кто хочет что-то вроде защищенных методов:

В соответствии с другими ответами, swift теперь предоставляет модификатор 'private', который определен скорее как файл, а не как класс, например, в Java или С#. Это означает, что если вы хотите защищенные методы, вы можете сделать это с помощью быстрых частных методов, если они находятся в одном файле

  • Создайте базовый класс для хранения защищенных методов (фактически частных)
  • Подкласс этого класса для использования тех же методов
  • В других файлах вы не можете обращаться к методам базового класса, даже если вы подклассифицируете

например. Файл 1:

class BaseClass {
    private func protectedMethod() {

    }
}

class SubClass : BaseClass {
    func publicMethod() {
        self.protectedMethod()  //this is ok as they are in same file
    }
}

Файл 2:

func test() {
    var a = BaseClass()
    a.protectedMethod() //ERROR


    var b = SubClass()
    b.protectedMethod() //ERROR
}

class SubClass2 : BaseClass {
    func publicMethod() {
        self.protectedMethod() //ERROR
    }

}

1

языковая грамматика не содержит ключевых слов "public", 'private' или "protected". Это предполагает, что все будет общедоступным. Конечно, может быть какой-то альтернативный метод указания модификаторов доступа без этих ключевых слов, но я не мог найти его в справочной системе.

-2

до swift 2.0 было всего три уровня доступа [Public, internal, private] но в swift 3.0 apple добавлен два новых уровня доступа, которые являются [Open, fileType], поэтому теперь в swift 3.0 имеется 5 уровней доступа Здесь я хочу очистить роль этих двух уровней доступа 1. Открыть: это очень похоже на Public, но единственное отличие состоит в том, что Public  может получить доступ к подклассу и переопределить, а уровень открытого доступа не сможет получить доступ к этому этот снимок взят с веб-сайта Medium, и это описывает разницу между открытым и общедоступным доступом

Теперь на второй уровень доступа 2. filetype - это более крупная версия частного или меньшего уровня доступа, чем внутренняя  FileType может получить доступ к расширенной части [class, struct, enum]  и private не может получить доступ к расширенной части кода, он может получить доступ только к  лексический охват  это изображение взято с сайта Medium, и это описывает разницу между fileType и частным уровнем доступа

Ещё вопросы

Сообщество Overcoder
Наверх
Меню