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

В 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?

Ответ 1

По сравнению с 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

Ответ 2

Свифт 4/Свифт 5

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

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

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

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



В чем разница между открытым и публичным?

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

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


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

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

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

// 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, чтобы быть доступным во всем файле.

Ответ 3

Когда вы говорите о создании "частного метода" в 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.

Ответ 4

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

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

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

Ответ 5

Используя комбинацию протоколов, закрытий и вложенных/внутренних классов, можно использовать что-то по строкам шаблона модуля, чтобы скрыть информацию в 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, поэтому, если есть недостаток, пожалуйста, укажите это, хотелось бы знать.

Ответ 6

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

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

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

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

Ответ 7

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

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

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

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

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

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

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

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

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

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

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

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

Ответ 8

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

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

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

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

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

Ответ 9

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

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

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

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

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

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

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

Ответ 10

Для Свифта 1-3:

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

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

Обновление Начиная с Swift 4, возможно увидеть другие ответы в этой теме

Ответ 11

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

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

Ответ 12

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

from Xcode 6 beta 4 realese notes:

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

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

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

Ответ 13

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

Ответ 14

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

Ответ 15

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

В соответствии с другими ответами, 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
    }

}

Ответ 17

enter image description here

В порядке от самых открытых до самых ограниченных:

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

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

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

  • fileprivate позволяет использовать только в пределах определения исходного файла.

  • private позволяет использовать только из прилагаемой декларации и новой в Swift 4 любые расширения этого объявления в том же исходном файле.

Узнайте больше здесь

Ответ 18

до 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 и частным уровнем доступа