Một ví dụ điển hình để phân biệt giữa fileprivate và private trong Swift3


142

Bài viết này rất hữu ích trong việc tìm hiểu các chỉ định truy cập mới trong Swift 3. Nó cũng đưa ra một số ví dụ về các cách sử dụng khác nhau fileprivateprivate.

Câu hỏi của tôi là - không sử dụng fileprivatetrên một chức năng sẽ chỉ được sử dụng trong tệp này giống như sử dụng private?

Câu trả lời:


282

fileprivatebây giờ là những gì đã privatetừng có trong các bản phát hành Swift trước đó: có thể truy cập từ cùng một tệp nguồn. Một khai báo được đánh dấu là privatechỉ có thể được truy cập trong phạm vi từ vựng mà nó được khai báo. Vì vậy, privatehạn chế hơn fileprivate.

Kể từ Swift 4, các khai báo riêng bên trong một loại có thể truy cập được đối với các tiện ích mở rộng cùng loại nếu tiện ích mở rộng được xác định trong cùng một tệp nguồn.

Ví dụ (tất cả trong một tệp nguồn):

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()
  • fooPhương thức riêng tư chỉ có thể truy cập trong phạm vi class A { ... }định nghĩa. Nó thậm chí không thể truy cập được từ một phần mở rộng cho loại (trong Swift 3, xem ghi chú thứ hai bên dưới để biết những thay đổi trong Swift 4).

  • barPhương thức riêng tư của tệp có thể truy cập được từ cùng một tệp nguồn.

Ghi chú:

  1. Đề xuất SE-0159 - Khắc phục các cấp truy cập riêng được đề xuất để hoàn nguyên về ngữ nghĩa Swift 2 trong Swift 4. Sau một cuộc thảo luận dài và gây tranh cãi về danh sách gửi thư tiến hóa nhanh, đề xuất đã bị từ chối .

  2. Đề xuất SE-0169 - Cải thiện tương tác giữa các Tuyên bố và Tiện ích mở rộng riêng tư đề nghị thực hiện các private khai báo bên trong một loại có thể truy cập được đối với các tiện ích mở rộng cùng loại nếu tiện ích mở rộng được xác định trong cùng một tệp nguồn. Đề xuất này đã được chấp nhận và thực hiện trong Swift 4.


2
Nếu bạn tự động chuyển đổi mã từ Swift 2 sang 3, Xcode sẽ biến privatethành fileprivate. Tuy nhiên, nếu bạn có sự sang trọng khi làm nó bằng tay, bạn thường có thể hưởng lợi từ việc rời đi privateprivate... nếu nó được biên dịch, tất cả đều tốt.
Dan Rosenstark

@DanielLarsson: Re gợi ý chỉnh sửa của bạn: Cả hai bình luận đều áp dụng cho foo()cuộc gọi.
Martin R

82

Tôi chỉ vẽ một sơ đồ về riêng tư , fileprivate , mởcông khai

Hy vọng nó có thể nhanh chóng giúp bạn, để mô tả văn bản, vui lòng tham khảo câu trả lời của Martin R

[Cập nhật Swift 4]

nhập mô tả hình ảnh ở đây


9
xem ra, fileprivatekhông được liên kết với phần mở rộng nhưng với tệp (viết phần mở rộng của lớp A trong một tệp khác sẽ không cho phép sử dụng fileprivatethành viên)
Vince

1
Điều này có vẻ không chính xác. Bạn đang thiếu điểm quan trọng. Bạn phải phân biệt giữa các lớp bên trong cùng một mô-đun và trong các mô-đun khác nhau. Nếu chúng ở các mô-đun khác nhau thì publicsẽ không cho phép bạn kế thừa, do đó hình ảnh thứ 3 không chính xác. Ngoài ra, bạn luôn có thể đặt một phần mở rộng cho bất kỳ lớp nào nếu bạn có thể nhìn thấy nó. Giải thích khả năng hiển thị trên các tiện ích mở rộng không phải là một ý tưởng hay.
Sulthan

Thật vậy, tôi nên đề cập đến sơ đồ của tôi chỉ hoạt động trên cùng một mô-đun, do đó hình ảnh thứ 3 tôi chỉ muốn người dùng nhanh chóng hiểu fileprivate chỉ hoạt động trên cùng một tệp.
Stephen Chen

6

Một nguyên tắc thực tế là bạn sử dụng private cho các biến, hằng, cấu trúc bên trong và các lớp chỉ được sử dụng bên trong khai báo của lớp / struct của bạn. Bạn sử dụng fileprivate cho những thứ được sử dụng bên trong các tiện ích mở rộng của bạn trong cùng một tệp với lớp / struct của bạn nhưng bên ngoài các dấu ngoặc nhọn xác định của chúng (ví dụ: phạm vi từ vựng của chúng).

    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

Trong Swift 4.0, Private hiện có thể truy cập được trong phần mở rộng nhưng trong cùng một tệp. Nếu bạn khai báo / xác định tiện ích mở rộng trong tệp khác, thì biến riêng tư của bạn sẽ không thể truy cập được vào tiện ích mở rộng của bạn **

Tệp riêng
tư Truy cập tệp riêng tư hạn chế việc sử dụng thực thể đối với tệp nguồn xác định của chính nó. Sử dụng quyền truy cập riêng tư vào tệp để ẩn chi tiết triển khai của một phần chức năng cụ thể khi các chi tiết đó được sử dụng trong toàn bộ tệp.
Cú pháp: fileprivate <var type> <variable name>
Ví dụ: fileprivate class SomeFilePrivateClass {}


Tin
truy cập tin hạn chế sử dụng của một thực thể để tuyên bố kèm theo, và phần mở rộng đó tuyên bố rằng đang ở trong cùng một tập tin . Sử dụng quyền truy cập riêng để ẩn chi tiết triển khai của một chức năng cụ thể khi các chi tiết đó chỉ được sử dụng trong một khai báo.
Cú pháp: private <var type> <variable name>
Ví dụ: private class SomePrivateClass {}


Dưới đây là chi tiết hơn về tất cả các cấp truy cập: Swift - Cấp độ truy cập

Nhìn vào hình ảnh này:
Tệp: ViewControll.swift
Ở đây cả phần mở rộng và trình điều khiển xem đều nằm trong cùng một tệp, do đó biến riêng tư testPrivateAccessLevelcó thể truy cập được trong phần mở rộng

nhập mô tả hình ảnh ở đây


Tệp: TestFile.swift
Ở đây cả phần mở rộng và trình điều khiển xem đều nằm trong các tệp khác nhau, do đó biến riêng tư testPrivateAccessLevelkhông thể truy cập được trong phần mở rộng.

nhập mô tả hình ảnh ở đây

nhập mô tả hình ảnh ở đây


Ở đây lớp ViewController2là một lớp con của ViewControllervà cả hai đều trong cùng một tệp. Ở đây biến riêng tư testPrivateAccessLevelkhông thể truy cập được trong Lớp con nhưng fileprivate có thể truy cập được trong lớp con.

nhập mô tả hình ảnh ở đây


5

Mặc dù câu trả lời của @ MartinR và @ StephenChen là hoàn hảo, Swift 4 thay đổi mọi thứ một chút.

Riêng tư hiện được coi là riêng tư đối với một lớp trong đó nó được khai báo và cả các phần mở rộng của nó.

FilePrivate được coi là riêng tư trong tệp đó có thể là một lớp trong đó biến được định nghĩa, đó là phần mở rộng hoặc bất kỳ lớp nào khác được định nghĩa trong cùng tệp đó.


5

Đã cập nhật cho Swift 5

Riêng tư vs FilePrivate

Để rõ ràng hơn, dán đoạn mã trong Sân chơi

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

    }
}

Lưu ý : Không thể truy cập bên ngoài tệp Swift cả riêng tư và fileprivate.


4

filePrivate - cấp độ kiểm soát truy cập nằm trong tệp.

trường hợp 1 : Nếu chúng ta tạo tiện ích mở rộng với cùng một tệp lớp và cố gắng truy cập chức năng fileprivate hoặc thuộc tính fileprivate trong tiện ích mở rộng của nó - truy cập cho phép
trường hợp 2 : Nếu chúng ta tạo tiện ích mở rộng của lớp trong tệp mới - Và bây giờ hãy thử truy cập chức năng fileprivate hoặc fileprivate tài sản - truy cập không được phép

riêng tư - cấp độ kiểm soát truy cập là trong phạm vi từ vựng

trường hợp 1 : Nếu thuộc tính hoặc hàm được khai báo là riêng tư trong lớp - thì mặc định phạm vi là lớp. trường hợp 2 : nếu cá thể riêng được khai báo với thân hàm - thì phạm vi của thể hiện được giới hạn ở thân hàm.


3

Trong ví dụ sau, các cấu trúc ngôn ngữ được sửa đổi bởi privatefileprivatedường như hành xử giống hệt nhau:

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

Đây là theo trực giác, tôi đoán. Nhưng, có ngoại lệ nào không?

Lòng biết ơn chân thành.


3

Đây là lời giải thích cho swift 4. Đối với swift 3, sự khác biệt là riêng tư. swift 3 private không thể được truy cập bởi phần mở rộng của nó, chỉ bản thân Class A mới có thể truy cập.

nhập mô tả hình ảnh ở đây Sau swift 4, fileprivate trở nên hơi dư thừa, vì người thường sẽ không xác định lớp con trong cùng một tệp. Riêng tư là đủ cho hầu hết các trường hợp.


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()
    }

}

Tôi thích điều này vì nó siêu đơn giản cho ngà voi.

Hãy thử thay đổi fileprivate thành private (và ngược lại) và xem điều gì xảy ra khi biên dịch ...

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.