เป็นตัวอย่างที่ดีในการแยกความแตกต่างระหว่าง fileprivate และ private ใน Swift3


142

นี้บทความได้รับประโยชน์ในการทำความเข้าใจ specifiers Swift 3เข้าถึงใหม่ใน นอกจากนี้ยังให้ตัวอย่างบางส่วนของการใช้งานที่แตกต่างกันและfileprivateprivate

คำถามของฉันคือ - ไม่ได้ใช้fileprivateกับฟังก์ชั่นที่จะใช้เฉพาะในไฟล์นี้เหมือนกับที่ใช้privateหรือไม่

คำตอบ:


282

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 - แก้ไขระดับการเข้าถึงข้อมูลส่วนตัวแนะนำให้กลับไปสวิฟท์ 2 ความหมายในสวิฟท์ 4. หลังจากการอภิปรายที่มีความยาวและความขัดแย้งในที่รวดเร็ววิวัฒนาการรายชื่อที่ส่งข้อเสนอที่ถูกปฏิเสธ

  2. ข้อเสนอSE-0169 - ปรับปรุงการโต้ตอบระหว่างการประกาศส่วนบุคคลและส่วนขยายแนะนำให้ทำการprivate ประกาศภายในประเภทที่สามารถเข้าถึงได้สำหรับส่วนขยายประเภทเดียวกันหากมีการกำหนดส่วนขยายในไฟล์ต้นฉบับเดียวกัน ข้อเสนอนี้ได้รับการยอมรับและนำไปใช้ใน Swift 4


2
ถ้าคุณต้องการแปลงรหัสโดยอัตโนมัติจากสวิฟท์ 2-3, Xcode จะเปิดเข้าไปprivate fileprivateอย่างไรก็ตามหากคุณมีความหรูหราในการทำด้วยมือคุณมักจะได้รับประโยชน์จากการออกจากprivateที่private... ถ้ามันรวบรวมทั้งหมดที่ดี
Dan Rosenstark

@DanielLarsson: แนะนำการแก้ไขของคุณอีกครั้ง: ความคิดเห็นทั้งสองนี้มีผลกับการfoo()โทร
Martin R

82

ฉันเพียงแค่วาดแผนภาพเกี่ยวกับส่วนตัว , fileprivate , เปิดและประชาชน

หวังว่าจะสามารถช่วยคุณได้อย่างรวดเร็วสำหรับคำอธิบายข้อความโปรดอ้างอิงถึงคำตอบของMartin R

[อัพเดต Swift 4]

ป้อนคำอธิบายรูปภาพที่นี่


9
ระวังfileprivateไม่ได้เชื่อมโยงกับส่วนขยาย แต่ไปที่ไฟล์ (การเขียนส่วนขยายของคลาส A ในไฟล์อื่นจะไม่อนุญาตให้ใช้fileprivateสมาชิก)
Vince

1
ดูเหมือนว่าไม่ถูกต้อง คุณพลาดจุดสำคัญ คุณต้องแยกความแตกต่างระหว่างคลาสที่อยู่ภายในโมดูลเดียวกันและอยู่ในโมดูลที่แตกต่างกัน หากพวกเขาอยู่ในโมดูลที่แตกต่างกันแล้วpublicจะไม่อนุญาตให้คุณสืบทอดดังนั้นภาพที่ 3 ไม่ถูกต้อง นอกจากนี้คุณยังสามารถใส่ส่วนขยายให้กับคลาสใดก็ได้หากคุณเห็น การอธิบายการเปิดเผยส่วนขยายไม่ใช่ความคิดที่ดีมาก
Sulthan

อันที่จริงฉันควรพูดถึงแผนภาพของฉันใช้งานได้เฉพาะในโมดูลเดียวกันดังนั้นภาพที่ 3 ฉันต้องการให้ผู้ใช้เข้าใจได้อย่างรวดเร็วว่าfileprivateนั้นใช้งานได้กับไฟล์เดียวกันเท่านั้น
สตีเฟ่นเฉิน

6

กฎง่ายๆคือคุณใช้ส่วนตัวสำหรับตัวแปรค่าคงที่โครงสร้างภายในและคลาสที่ใช้ภายในการประกาศคลาส / โครงสร้างของคุณเท่านั้น คุณใช้ fileprivate สำหรับสิ่งต่าง ๆ ที่ใช้ภายในส่วนขยายของคุณภายในไฟล์เดียวกับ class / struct ของคุณ แต่อยู่นอกการจัดฟันหยิกที่กำหนด (เช่นขอบเขตการใช้คำศัพท์)

    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 ขณะนี้สามารถเข้าถึงส่วนขยายได้แบบส่วนตัว แต่อยู่ในไฟล์เดียวกัน หากคุณประกาศ / กำหนดนามสกุลในไฟล์อื่น ๆ แล้วตัวแปรส่วนตัวของคุณจะไม่สามารถเข้าถึงได้ในส่วนขยายของคุณ **

การเข้าถึงไฟล์ส่วนตัว
- ไฟล์ จำกัด การใช้งานของเอนทิตีเพื่อกำหนดแหล่งไฟล์ของตัวเอง ใช้การเข้าถึงแบบเป็นส่วนตัวของไฟล์เพื่อซ่อนรายละเอียดการใช้งานของส่วนการใช้งานเฉพาะเมื่อใช้รายละเอียดเหล่านั้นภายในไฟล์ทั้งหมด
ไวยากรณ์: fileprivate <var type> <variable name>
ตัวอย่าง: fileprivate class SomeFilePrivateClass {}


เอกชน
เข้าถึงเอกชน จำกัด การใช้ของกิจการที่จะประกาศการปิดล้อมและเพื่อขยายว่าประกาศที่อยู่ในไฟล์เดียวกัน ใช้การเข้าถึงแบบส่วนตัวเพื่อซ่อนรายละเอียดการใช้งานของส่วนการทำงานเฉพาะเมื่อใช้รายละเอียดเหล่านั้นภายในการประกาศเพียงครั้งเดียว
ไวยากรณ์: private <var type> <variable name>
ตัวอย่าง: private class SomePrivateClass {}


นี่คือรายละเอียดเพิ่มเติมเกี่ยวกับทุกระดับการเข้าถึง: Swift - Access Level

ดูที่ภาพนี้:
ไฟล์: ViewController.swift ที่
นี่ส่วนขยายและตัวควบคุมมุมมองทั้งสองอยู่ในไฟล์เดียวกันดังนั้นตัวแปรส่วนตัวจึงtestPrivateAccessLevelสามารถเข้าถึงได้ในส่วนขยาย

ป้อนคำอธิบายรูปภาพที่นี่


ไฟล์: TestFile.swift ที่
นี่ส่วนขยายและตัวควบคุมมุมมองทั้งสองอยู่ในไฟล์ที่แตกต่างกันดังนั้นตัวแปรส่วนตัวจึงtestPrivateAccessLevelไม่สามารถเข้าถึงได้ในส่วนขยาย

ป้อนคำอธิบายรูปภาพที่นี่

ป้อนคำอธิบายรูปภาพที่นี่


นี่คลาสViewController2เป็นคลาสย่อยของViewControllerและทั้งคู่อยู่ในไฟล์เดียวกัน ตัวแปรส่วนตัวที่นี่testPrivateAccessLevelไม่สามารถเข้าถึงได้ในคลาสย่อย แต่ fileprivate นั้นสามารถเข้าถึงได้ในคลาสย่อย

ป้อนคำอธิบายรูปภาพที่นี่


5

แม้ว่าคำตอบของ @ MartinR's และ @ StephenChen นั้นสมบูรณ์แบบSwift 4จะเปลี่ยนแปลงสิ่งต่าง ๆ เล็กน้อย

ส่วนตัวตอนนี้ถือว่าเป็นส่วนตัวถึงระดับในการที่จะมีการประกาศและยังส่วนขยายของมัน

FilePrivateถูกพิจารณาว่าเป็นแบบส่วนตัวในไฟล์นั้นไม่ว่าจะเป็นคลาสที่ตัวแปรถูกกำหนดเป็นส่วนขยายหรือคลาสอื่น ๆ ที่กำหนดไว้ในไฟล์เดียวกัน


5

อัปเดตสำหรับ Swift 5

ส่วนตัวเทียบกับFilePrivate

เพื่อความชัดเจนยิ่งขึ้นให้วางโค้ดขนาดสั้นลงในสนามเด็กเล่น

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 ไม่สามารถเข้าถึงได้ทั้งแบบส่วนตัวและแบบส่วนตัว


4

filePrivate - ระดับการควบคุมการเข้าถึงอยู่ในไฟล์

กรณีที่ 1 : ถ้าเราสร้างนามสกุลด้วยไฟล์ class เดียวกันและพยายามเข้าถึงฟังก์ชั่น fileprivate หรือคุณสมบัติ fileprivate ในส่วนขยายของมัน - อนุญาตการเข้าถึง
กรณีที่ 2 : ถ้าเราสร้างนามสกุลของคลาสในไฟล์ใหม่ - และตอนนี้ลองเข้าถึงฟังก์ชั่นส่วนตัวหรือ fileprivate คุณสมบัติ - ไม่อนุญาตให้เข้าถึง

ส่วนตัว - ระดับการควบคุมการเข้าถึงอยู่ในขอบเขตศัพท์

กรณีที่ 1 : ถ้ามีการประกาศคุณสมบัติหรือฟังก์ชั่นเป็นส่วนตัวในคลาส - ขอบเขตจะเป็นค่าเริ่มต้นของคลาส กรณีที่ 2 : หากมีการประกาศอินสแตนซ์ส่วนตัวด้วยฟังก์ชั่นเนื้อความ - ขอบเขตของอินสแตนซ์จะถูก จำกัด เฉพาะเนื้อหาของฟังก์ชัน


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

ผมคิดว่านี่เป็นไปตามสัญชาตญาณ แต่มีข้อยกเว้นอะไรบ้าง?

ด้วยความเคารพอย่างสูง.


3

นี่คือคำอธิบายสำหรับ swift 4 สำหรับ swift 3 ความแตกต่างเป็นเรื่องส่วนตัว swift 3 private ไม่สามารถเข้าถึงได้โดยส่วนขยายเท่านั้น Class A เท่านั้นที่สามารถเข้าถึงได้

ป้อนคำอธิบายรูปภาพที่นี่ หลังจาก swift 4 fileprivate จะกลายเป็นบิตซ้ำซ้อนเนื่องจากบุคคลทั่วไปจะไม่กำหนดคลาสย่อยในไฟล์เดียวกัน ส่วนตัวควรจะเพียงพอสำหรับกรณีส่วนใหญ่


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 (และในทางกลับกัน) และดูว่าเกิดอะไรขึ้นกับคอมไพล์ ...

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.