Каков хороший пример различия между частным и частным файлом в Swift3

144

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

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

Никита П
источник

Ответы:

284

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).

  • Метод file-private barдоступен из того же исходного файла.

Примечания:

  1. В предложении SE-0159 - Fix Private Access Levels предлагалось вернуться к семантике Swift 2 в Swift 4. После долгого и противоречивого обсуждения списка рассылки быстрой эволюции предложение было отклонено .

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

Мартин Р
источник
2
Если вы автоматически конвертируете код из Swift 2 в 3, Xcode превратится privateв fileprivate. Однако, если у вас есть возможность сделать это вручную, вы часто можете получить выгоду, оставив privateas private... если он компилируется, все хорошо.
Дэн Розенстарк
@DanielLarsson: Повторите свои предложения по редактированию: оба комментария относятся к foo()звонку.
Martin R
84

Я просто рисую диаграмму о частных , файловых , открытых и общедоступных

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

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

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

Стивен Чен
источник
9
fileprivatefileprivate
Винс
1
Это кажется неправильным. Вы упускаете ключевой момент. Вы должны различать классы, которые находятся внутри одного модуля, и классы, которые находятся в разных модулях. Если они находятся в разных модулях, publicвы не сможете наследовать, поэтому третье изображение неверно. Кроме того, вы всегда можете добавить расширение к любому классу, если видите его. Объяснять видимость расширений - не очень хорошая идея.
Sulthan
Действительно, я должен упомянуть, что моя диаграмма работает только с одним и тем же модулем, поэтому 3-е изображение, которое я просто хочу, чтобы пользователь быстро понял, что fileprivate работает только с одним и тем же файлом.
Стивен Чен
6

Практическое эмпирическое правило заключается в том, что вы используете 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
        }
    }
Джош Хоманн
источник
6

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

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


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


Вот более подробная информация обо всех уровнях доступа: Swift - Уровни доступа

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

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


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

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

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


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

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

Крунал
источник
6

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

Частный против 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 недоступны как частные, так и частные файлы.

Арпит Джайн
источник
5

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

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

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

Никита П
источник
4

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

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

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

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

Ашиш Чхабра
источник
4

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

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

Вейдиан Хуанг
источник
3

В следующем примере языковые конструкции, измененные 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))

Полагаю, это интуитивно. Но есть ли исключения?

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

Томас Бальдерас
источник
1
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()
    }

}

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

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

CPD
источник