Какой хороший пример, чтобы различать fileprivate и private в Swift3

Эта статья помогла понять новые спецификаторы доступа в Swift 3. Он также дает несколько примеров использования fileprivate и private.

Мой вопрос: использование fileprivate для функции, которая будет использоваться только в этом файле, не совпадает с использованием private?


person Nikita P    schedule 18.08.2016    source источник


Ответы (10)


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

Начиная с Swift 4, частные объявления внутри типа доступны для расширений того же типа, если расширение определено в том же исходном файле.

Пример (все в одном исходном файле):

class A {
    private func foo() {}
    fileprivate func bar() {}

    func baz() {
        foo()
        bar()
    }
}

extension A {
    func test() {
        foo() // Swift 3: error: use of unresolved identifier 'foo'
              // Swift 4: no error because extension is in same source file
        bar()
    }
}

let a = A()
a.foo() // error: 'foo' is inaccessible due to 'private' protection level
a.bar()
  • Частный метод foo доступен только в рамках определения class A { ... }. Он даже недоступен из расширения типа (в Swift 3 см. второе примечание ниже об изменениях в Swift 4).

  • Файловый метод bar доступен из того же исходного файла.

Примечания:

  1. Предложение SE-0159 — Исправление Уровни частного доступа предложили вернуться к семантике Swift 2 в Swift 4. После продолжительного и спорного обсуждения в списке рассылки swift-evolution предложение было отклонено.

  2. Предложение SE-0169 — Улучшить взаимодействие между частными объявлениями и расширениями предлагает сделать private объявлений внутри типа доступными для расширений того же типа, если расширение определено в одном и том же исходном файле. Это предложение было принято и реализовано в Swift 4.

person Martin R    schedule 18.08.2016
comment
Если вы автоматически конвертируете код из Swift 2 в 3, Xcode превратит private в fileprivate. Однако, если вы можете позволить себе роскошь сделать это вручную, вы часто можете получить выгоду, оставив private как private... если он скомпилируется, все в порядке. - person Dan Rosenstark; 14.03.2017
comment
@DanielLarsson: Ваши предложения по редактированию: Оба комментария относятся к вызову foo(). - person Martin R; 04.11.2018
comment
Лучший пример Спасибо!! - person Manish; 11.02.2021

Я просто нарисовал схему для private, fileprivate, open и public.

Надеюсь, это поможет вам быстро, текстовое описание см. в ответе Martin R.

[Обновить Swift 4, 5]

введите здесь описание изображения

person Stephen Chen    schedule 21.12.2016
comment
будьте осторожны, fileprivate связано не с расширением, а с файлом (запись расширения класса A в другом файле не позволит использовать fileprivate члены) - person Vince; 09.01.2017
comment
Это кажется неправильным. Вы упускаете ключевой момент. Вы должны различать классы, находящиеся внутри одного и того же модуля, и классы, находящиеся в разных модулях. Если они находятся в разных модулях, то public не позволит вам наследовать, поэтому 3-е изображение неверно. Кроме того, вы всегда можете добавить расширение к любому классу, если вы его видите. Тогда объяснять видимость расширений не очень хорошая идея. - person Sulthan; 04.04.2017
comment
Действительно, я должен отметить, что моя диаграмма работает только с одним и тем же модулем, поэтому 3-е изображение я просто хочу, чтобы пользователь быстро понял, что fileprivate работает только с одним и тем же файлом. - person Stephen Chen; 04.04.2017

Обновлено для Swift 5

Private и FilePrivate

Для большей ясности вставьте фрагмент кода в Playground

class Sum1 {
    let a: Int!
    let b: Int!
    private var result: Int?
    fileprivate var resultt: Int?

    init(a : Int, b: Int) {
        self.a = a
        self.b = b
    }

    func sum(){
        result = a + b
        print(result as! Int)
    }
}

let aObj = Sum1.init(a: 10, b: 20)
aObj.sum()
aObj.resultt //File Private Accessible as inside same swift file
aObj.result //Private varaible will not be accessible outside its definition except extensions

extension Sum1{

    func testing() {

        // Both private and fileprivate accessible in extensions
        print(result)
        print(resultt)
    }
}

//If SUM2 class is created in same file as Sum1 ---
class Sum2{

    func test(){

        let aSum1 = Sum1.init(a: 2, b: 2)
        // Only file private accessible
        aSum1.resultt

    }
}

Примечание. За пределами Swift файлы private и fileprivate недоступны.

person Arpit Jain    schedule 30.04.2019

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

    class ViewController: UIViewController {
        @IBOutlet var tableView: UITableView!
        //This is not used outside of class Viewcontroller
        private var titleText = "Demo"
        //This gets used in the extension
        fileprivate var list = [String]()
        override func viewDidLoad() {
            navigationItem.title = titleText
        }
    }

    extension ViewController: UITableViewDataSource {
        func numberOfSections(in tableView: UITableView) -> Int {
            return list.count
        }
    }
person Josh Homann    schedule 29.10.2016

В Swift 4.0 Private теперь доступен в расширении, но в том же файле. Если вы объявляете/определяете расширение в другом файле, то ваша приватная переменная не будет доступна для вашего расширения**

Частный файл
Доступ к файлу ограничивает использование объекта его собственным определяющим исходным файлом. Используйте файловый доступ, чтобы скрыть детали реализации определенной части функциональности, когда эти детали используются во всем файле.
Синтаксис: fileprivate <var type> <variable name>
Пример: fileprivate class SomeFilePrivateClass {}


Частный
Частный доступ ограничивает использование объекта прилагаемой декларацией и расширениями этой декларации, которые находятся в том же файле. Используйте закрытый доступ, чтобы скрыть детали реализации определенной части функциональности, когда эти детали используются только в одном объявлении.
Синтаксис: private <var type> <variable name>
Пример: private class SomePrivateClass {}


Подробнее обо всех уровнях доступа: Swift. - Уровни доступа

Посмотрите на эти изображения:
Файл: ViewController.swift
Здесь расширение и контроллер представления находятся в одном файле, поэтому частная переменная testPrivateAccessLevel доступна в расширении

введите здесь описание изображения


Файл: TestFile.swift
Здесь расширение и контроллер представления находятся в разных файлах, поэтому закрытая переменная testPrivateAccessLevel недоступна в расширении.

введите здесь описание изображения

введите здесь описание изображения


Здесь класс ViewController2 является подклассом ViewController, и оба находятся в одном файле. Здесь частная переменная testPrivateAccessLevel недоступна в подклассе, но fileprivate доступен в подклассе.

введите здесь описание изображения

person Krunal    schedule 06.10.2017

Хотя ответы @MartinR и @StephenChen идеальны, Swift 4 немного меняет ситуацию.

Private теперь считается закрытым для класса, в котором он объявлен, а также для его расширений.

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

person Nikita P    schedule 13.06.2017

filePrivate — уровень контроля доступа находится внутри файла.

случай 1: если мы создаем расширение с файлом того же класса и пытаемся получить доступ к функции fileprivate или свойству fileprivate в его расширении - доступ разрешен
случай 2: если мы создаем расширение класса в новом файле - А теперь попробуйте получить доступ к функции fileprivate или свойству fileprivate - доступ запрещен

private – уровень контроля доступа находится в лексической области видимости.

Случай 1: если свойство или функция объявлены как закрытые в классе, тогда областью по умолчанию является класс. случай 2: если частный экземпляр объявлен в теле функции, то область действия экземпляра ограничена телом функции.

person Ashish Chhabra    schedule 29.11.2017

Это объяснение для Swift 4. Для Swift 3 разница заключается в частном. Доступ к Swift 3 private невозможен по его расширению, доступ может получить только сам класс A.

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

person Weidian Huang    schedule 22.09.2018

В следующем примере языковые конструкции, модифицированные private и fileprivate, ведут себя одинаково:

fileprivate func fact(_ n: Int) -> Int {
    if (n == 0) {
        return 1
    } else {
        return n * fact(n - 1)
    }
}

private func gauss(_ n: Int) -> Int {
    if (n == 0) {
        return 0
    } else {
        return n + gauss(n - 1)
    }
}

print(fact(0))
print(fact(5))
print(fact(3))

print(gauss(10))
print(gauss(9))

Это по интуиции, я думаю. Но есть ли исключения?

С наилучшими пожеланиями.

person Tomas Balderas    schedule 21.01.2017

class Privacy {

    fileprivate(set) var pu:Int {
        get {
            return self.pr
        }
        set {
            self.pr = newValue
        }
    }
    private var pr:Int = 0
    fileprivate var fp:Int = 0


    func ex() {
        print("\(self.pu) == \(self.pr) and not \(self.fp)")
    }
}


extension Privacy {

    func ex2() {
        self.pu = 5
        self.ex()
    }

}

Мне это нравится, потому что это очень просто для иваров.

Попробуйте изменить fileprivate на private (и наоборот) и посмотрите, что произойдет при компиляции...

person CPD    schedule 20.09.2016