Swift มีตัวดัดแปลงการเข้าถึงหรือไม่


273

ใน 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?


ฉันก็ไม่เหมือนกัน. อย่างน้อย Apple ก็ควรจะแนะนำมารยาทสำหรับผู้ที่ต้องการความเป็นส่วนตัวเช่นในไพ ธ อนพวกเขาจะถูกนำหน้าด้วยเครื่องหมายขีดล่าง
Ciantic

เพิ่มคำตอบที่อัปเดตสำหรับXcode 6.1.1 รุ่นสุดท้าย
holroy

คำตอบ:


419

ตั้งแต่Swift 3.0.1มีการเข้าถึง 4 ระดับซึ่งอธิบายไว้ด้านล่างจากระดับสูงสุด (จำกัด น้อยที่สุด) ถึงต่ำสุด (จำกัด มากที่สุด)


1. openและpublic

เปิดใช้งานเอนทิตีที่จะใช้ภายนอกโมดูลที่กำหนด (เป้าหมาย) โดยทั่วไปคุณใช้openหรือpublicเข้าถึงเมื่อระบุส่วนต่อประสานสาธารณะกับกรอบงาน

อย่างไรก็ตามopenการเข้าถึงจะใช้กับคลาสและสมาชิกคลาสเท่านั้นและจะแตกต่างจากpublicการเข้าถึงดังต่อไปนี้:

  • public คลาสและสมาชิกคลาสสามารถถูก subclassed และ overridden ภายในโมดูลที่กำหนด (เป้าหมาย)
  • open คลาสและสมาชิกคลาสสามารถ subclassed และแทนที่ทั้งภายในและภายนอกโมดูลกำหนด (เป้าหมาย)

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

37
มีใครช่วยอธิบายให้ฉันฟังหน่อยได้ไหมว่าทำไมเรื่องนี้ถึงไม่เป็นเรื่องใหญ่
Zaky German

15
มีเสมอวิธีการบางอย่างหรือตัวแปรใน OOP ที่ควรจะเป็นส่วนตัวหรือการป้องกัน วิธีนี้ช่วยให้สามารถใช้การออกแบบที่เป็นของแข็งได้เนื่องจากวิธีการขนาดใหญ่แบ่งออกเป็นจำนวนเล็ก ๆ แต่ละวิธีมีความรับผิดชอบของตัวเองที่สามารถข้ามไปได้ แต่ควรใช้วิธี "หลัก" เท่านั้นสำหรับการใช้งานสาธารณะ
akashivskyy

19
ฉันโดยส่วนตัวไม่ชอบวิธีการแก้ปัญหาเช่นเดียวกับวิธีการขีดเส้นใต้ / พิเศษ-char นำวิธี "ส่วนตัว" แม้ว่าจะรับประกันได้ว่า i สำหรับตัวฉันเองจะเป็นคนเดียวที่เคยดูโค้ดนี้มันทำให้รหัสประหยัดมากขึ้น / มีแนวโน้มที่จะเกิดข้อผิดพลาดน้อยลงทำให้คอมไพเลอร์จะป้องกันคุณจากการทำสิ่งที่คุณไม่ควรทำ ดังนั้นฉันคิดว่าพวกเขาควรจะออก "กลไกการควบคุมการเข้าถึง" โดยเร็วที่สุดดังนั้นผู้คนจะไม่ชินกับนิสัยที่ไม่ดี
Jonas Eschmann

10
บันทึกย่อประจำรุ่นเบต้า Xcode 6 บอกว่า: "การควบคุมการเข้าถึง (สมาชิกสาธารณะ / ส่วนตัว) ไม่ได้เปิดใช้งานในเมล็ดพันธุ์นี้ (15747445)"
Martin Ullrich

9
@alcalde แนวคิดของส่วนต่อประสานสาธารณะมีค่าสูง หากคุณต้องการให้โค้ดทั้งหมดในคลาสต้องอยู่ภายในฟังก์ชั่นที่เป็นส่วนหนึ่งของ API สาธารณะฉันคิดว่ามันค่อนข้าง จำกัด ในทางกลับกันการมี public API ที่ระบุจะช่วยให้การใช้งานเปลี่ยนแปลง (รวมถึงการใช้วิธีการส่วนตัว) โดยไม่กระทบต่อผู้บริโภค หากใครบางคน 'ต้องการ' เพื่อใช้วิธีการเรียนภายในฉันรู้สึกว่าพวกเขาเข้าใจผิดขีด ​​จำกัด ของฟังก์ชั่นการเรียน (หรือพยายามใช้คลาสบั๊กกี้)
jinglesthula

26

Swift 4 / Swift 5

ตามที่กล่าวไว้ในเอกสารประกอบของ Swift - การควบคุมการเข้าถึง Swift มีการควบคุมการเข้าถึง 5 รายการ :

  • แบบเปิดและสาธารณะ : สามารถเข้าถึงได้จากเอนทิตีของโมดูลและเอนทิตีของโมดูลใด ๆ ที่นำเข้าโมดูลการกำหนด

  • ภายใน : สามารถเข้าถึงได้จากเอนทิตีของโมดูลเท่านั้น เป็นระดับการเข้าถึงเริ่มต้น

  • fileprivateและ private : สามารถเข้าถึงได้ในแบบ จำกัด ภายในขอบเขตที่ จำกัด ซึ่งคุณกำหนดไว้เท่านั้น



ความแตกต่างระหว่างการเปิดและสาธารณะคืออะไร?

openเป็นแบบเดียวกับ public ใน Swift เวอร์ชันก่อนหน้าพวกมันอนุญาตให้คลาสจากโมดูลอื่นสามารถใช้และสืบทอดได้เช่น: พวกมันสามารถ subclassed จากโมดูลอื่น ๆ นอกจากนี้ยังอนุญาตให้สมาชิกจากโมดูลอื่นใช้และแทนที่พวกเขา ตรรกะเดียวกันสำหรับโมดูลของพวกเขา

publicอนุญาตให้คลาสจากโมดูลอื่นใช้พวกมันได้แต่ไม่สามารถสืบทอดได้เช่น: พวกมันไม่สามารถซับคลาสจากโมดูลอื่นได้ นอกจากนี้ยังอนุญาตให้สมาชิกจากโมดูลอื่นใช้พวกเขา แต่ไม่แทนที่พวกเขา สำหรับโมดูลของพวกเขาพวกเขามีตรรกะแบบเปิดเดียวกัน (อนุญาตให้คลาสใช้และสืบทอดพวกมันอนุญาตให้สมาชิกใช้และแทนที่พวกเขา)


fileprivateและprivateแตกต่างกันอย่างไร?

fileprivateสามารถเข้าถึงได้จากไฟล์ทั้งหมด

ส่วนตัวสามารถเข้าถึงได้จากการประกาศเดียวของพวกเขาและเพื่อขยายของการประกาศที่อยู่ในไฟล์เดียวกัน; ตัวอย่างเช่น

// 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 แตกต่างกันอย่างไร

ดังที่กล่าวไว้ในข้อเสนอ 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สามารถเข้าถึงได้ทั้งไฟล์


17

เมื่อมีคนพูดถึงการสร้าง "วิธีการส่วนตัว" ใน Swift หรือ ObjC (หรือทับทิมหรือ java หรือ ... ) วิธีการเหล่านั้นไม่ได้เป็นส่วนตัวจริงๆ ไม่มีการควบคุมการเข้าถึงจริงรอบตัวพวกเขา ภาษาใดก็ตามที่มีแม้กระทั่งวิปัสสนาเล็กน้อยช่วยให้นักพัฒนาได้รับคุณค่าเหล่านั้นจากนอกห้องเรียนหากพวกเขาต้องการ

ดังนั้นสิ่งที่เรากำลังพูดถึงที่นี่จริง ๆ คือวิธีกำหนดอินเทอร์เฟซแบบสาธารณะที่นำเสนอฟังก์ชันการทำงานที่เราต้องการและ "ซ่อน" ส่วนที่เหลือที่เราพิจารณาว่าเป็น "ส่วนตัว"

กลไก 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'
}

มีบางกรณีของการกำหนดโดยตรงที่คุณต้องชัดเจนด้วยประเภทแทนที่จะใช้ Swift เพื่ออนุมาน แต่ดูเหมือนว่าแทบจะไม่เป็นตัวจัดการดีล:

var myClass:MyClass = MyClassImplementation()

การใช้โปรโตคอลด้วยวิธีนี้มีความหมายรวบรัดพอสมควรและต่อตาฉันก็ดูเหมือนจะเป็นคลาส Extentions ที่เราใช้เพื่อจุดประสงค์นี้ใน ObjC


1
หากโปรโตคอลไม่อนุญาตให้เรามีอาร์กิวเมนต์เริ่มต้นฉันจะสร้างวิธีสาธารณะด้วยพารามิเตอร์ทางเลือกที่ยังคงสอดคล้องกับโปรโตคอลได้อย่างไร
bdurao

ฉันไม่เข้าใจว่าคุณหมายถึงอะไร ต่อไปนี้สร้างวิธีสาธารณะด้วยพารามิเตอร์ที่เป็นตัวเลือก ดูเหมือนจะไม่มีปัญหา: gist.github.com/anonymous/17d8d2d25a78644046b6
jemmons

ด้วยเหตุผลบางอย่างพารามิเตอร์ทางเลือกไม่ทำงานตามที่ควรในโครงการของฉันลองสิ่งที่คล้ายกับตัวอย่าง GitHub ของคุณแล้ว เนื่องจากเราไม่สามารถตั้งค่าพารามิเตอร์เริ่มต้นในโปรโตคอลได้ฉันติดขัดและสิ้นสุดการถามคำถาม ขอบคุณที่พยายามช่วย
bdurao

เราทุกคนรู้ว่ามีอะไรที่แฮ็กได้ เราเพียงแค่ต้องการคำสั่งซื้อว่าทำไมเราจึงต้องใช้ตัวดัดแปลงการเข้าถึง
canbax

14

เท่าที่ฉันสามารถบอกได้ว่าไม่มีคำว่า 'สาธารณะ', 'ส่วนตัว' หรือ 'ป้องกัน' นี้จะแนะนำทุกอย่างเป็นสาธารณะ

อย่างไรก็ตาม Apple อาจคาดหวังให้ผู้คนใช้ " โปรโตคอล " (เรียกว่าส่วนต่อประสานกับส่วนที่เหลือของโลก) และรูปแบบการออกแบบจากโรงงานเพื่อซ่อนรายละเอียดของประเภทการนำไปใช้งาน

นี่เป็นรูปแบบการออกแบบที่ดีที่จะใช้อยู่ดี มันช่วยให้คุณสามารถเปลี่ยนลำดับชั้นการใช้งานของคุณในขณะที่ทำให้ระบบประเภทตรรกะเหมือนกัน


นี่เป็นสิ่งที่ดีเพราะช่วยลดข้อต่อและทำให้การทดสอบง่ายขึ้น
Scroog1

4
สิ่งนี้จะทำงานได้ดีขึ้นหากมีวิธีซ่อนคลาสการใช้งานของโปรโตคอล แต่ดูเหมือนจะไม่เป็นเช่นนั้น
David Moles

ทุกคนสามารถแสดงตัวอย่างของรูปแบบนี้ได้หรือไม่
bloudermilk

ดีคำตอบนี้เป็นสิ่งถูกต้องในรุ่นก่อนหน้านี้สวิฟท์ (s), ดูเหมือนว่ามันไม่ถูกต้องอีกต่อไป :) โปรดตรวจสอบคำตอบของฉัน
Ahmad F

12

ด้วยการใช้โปรโตคอลการปิดและคลาสที่ซ้อนกัน / ชั้นในเป็นไปได้ที่จะใช้บางสิ่งบางอย่างตามแนวของรูปแบบโมดูลเพื่อซ่อนข้อมูลใน 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 และลึกลับMathถูกซ่อนอยู่ที่นี่จากการใช้งานภายนอกและพยายามที่จะขุดเข้าไปในวัตถุจะส่งผลให้เกิดข้อผิดพลาด

ฉันเป็นเพียงส่วนหนึ่งของการอ่านเอกสาร Swift ของฉันดังนั้นหากมีข้อบกพร่องที่นี่โปรดชี้ให้เห็นว่าชอบที่จะรู้


ตกลงฉันคิดเกี่ยวกับการแก้ปัญหานี้ด้วย แต่อธิบายฉันทำไมฉันไม่สามารถ acces กับ h.huh.innerVal?
Sam

สวิฟต์นั้นปลอดภัยต่อสิ่งมีชีวิตและสิ่งเดียวที่โลกภายนอกรู้เกี่ยวกับ h คือมันเป็นไปตาม HuhThing HuhThing ไม่รวมข้อมูลใด ๆ เกี่ยวกับคุณสมบัติที่เรียกว่า innerVal ดังนั้นการพยายามเข้าถึงมันเป็นข้อผิดพลาด
Dave Kapp

8
ยังสามารถเข้าถึงได้: Preflect(h)[0].1.value // 19
John Estropia

2
ดีใจที่ได้พบ John - ฉันไม่ได้นึกถึงการสะท้อน ดูเหมือนว่าจะเปลี่ยนวัตถุให้เป็น Tuples - มีเอกสารอย่างเป็นทางการใด ๆ เกี่ยวกับฟังก์ชั่นดังกล่าวหรือสิ่งอื่น ๆ ฉันดูคู่มือภาษาใน iBooks แต่ฉันไม่เห็นมัน
Dave Kapp

1
@JohnEstropia ฉันไม่คิดว่าจะนับการสะท้อนกลับ ใน Java (ภาษาผู้ใหญ่มากขึ้น) มีมีการปรับเปลี่ยนการเข้าถึง แต่พวกเขาไม่ได้ป้องกันไม่ให้เทคนิคการสะท้อนอย่างใดอย่างหนึ่ง
11684

10

ตั้งแต่ Xcode 6 beta 4 Swift มีตัวดัดแปลงการเข้าถึง จากบันทึกประจำรุ่น:

การควบคุมการเข้าถึง Swift มีสามระดับการเข้าถึง:

  • เอนทิตีส่วนตัวสามารถเข้าถึงได้จากภายในไฟล์ต้นฉบับที่มีการกำหนดไว้เท่านั้น
  • สามารถเข้าถึงเอนทิตีภายในได้ทุกที่ภายในเป้าหมายที่กำหนดไว้
  • หน่วยงานสาธารณะสามารถเข้าถึงได้จากทุกที่ภายในเป้าหมายและจากบริบทอื่น ๆ ที่นำเข้าโมดูลของเป้าหมายปัจจุบัน

ค่าเริ่มต้นโดยนัยคือinternalภายในแอปพลิเคชันเป้าหมายคุณสามารถปิดตัวดัดแปลงการเข้าถึงได้ยกเว้นที่คุณต้องการเข้มงวดมากขึ้น ในเป้าหมายเฟรมเวิร์ก (เช่นหากคุณกำลังฝังเฟรมเวิร์กเพื่อแชร์รหัสระหว่างแอพและการแชร์หรือส่วนขยายมุมมองวันนี้) ใช้publicเพื่อกำหนด API ที่คุณต้องการเปิดเผยให้ลูกค้าของเฟรมเวิร์กของคุณทราบ


ดีคำตอบนี้เป็นสิ่งถูกต้องในรุ่นก่อนหน้านี้สวิฟท์ (s), ดูเหมือนว่ามันไม่ถูกต้องอีกต่อไป :) โปรดตรวจสอบคำตอบของฉัน
Ahmad F

6

Swift 3.0 มอบการควบคุมการเข้าถึงที่แตกต่างกันห้าแบบ:

  1. เปิด
  2. สาธารณะ
  3. ภายใน
  4. fileprivate
  5. เอกชน

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

การเข้าถึงภายในช่วยให้สามารถใช้เอนทิตีภายในไฟล์ต้นฉบับใด ๆ จากโมดูลการกำหนด แต่ไม่สามารถใช้ในไฟล์ต้นฉบับใด ๆ ภายนอกโมดูลนั้น โดยทั่วไปคุณใช้การเข้าถึงภายในเมื่อกำหนดโครงสร้างภายในของแอพหรือกรอบงาน

การเข้าถึงไฟล์แบบส่วนตัวจำกัด การใช้งานของเอนทิตีในการกำหนดไฟล์ต้นฉบับเอง ใช้การเข้าถึงแบบเป็นส่วนตัวของไฟล์เพื่อซ่อนรายละเอียดการใช้งานของส่วนการทำงานเฉพาะเมื่อใช้รายละเอียดเหล่านั้นภายในไฟล์ทั้งหมด

การเข้าถึงส่วนตัวจำกัด การใช้งานของนิติบุคคลในการประกาศล้อมรอบ ใช้การเข้าถึงแบบส่วนตัวเพื่อซ่อนรายละเอียดการใช้งานของส่วนการทำงานเฉพาะเมื่อใช้รายละเอียดเหล่านั้นภายในการประกาศเพียงครั้งเดียว

การเข้าถึงแบบเปิดคือระดับการเข้าถึงสูงสุด (จำกัด น้อยที่สุด) และการเข้าถึงแบบส่วนตัวเป็นระดับการเข้าถึงต่ำสุด (จำกัด มากที่สุด)

ระดับการเข้าถึงเริ่มต้น

เอนทิตีทั้งหมดในรหัสของคุณ (มีข้อยกเว้นบางประการ) มีระดับการเข้าถึงภายในเป็นค่าเริ่มต้นหากคุณไม่ได้ระบุระดับการเข้าถึงที่ชัดเจนด้วยตัวคุณเอง ดังนั้นในหลายกรณีคุณไม่จำเป็นต้องระบุระดับการเข้าถึงข้อมูลที่ชัดเจนในรหัสของคุณ

บันทึกประจำรุ่นในหัวข้อ:

คลาสที่ประกาศเป็นพับลิกไม่สามารถถูกคลาสย่อยนอกโมดูลการกำหนดได้อีกต่อไปและเมธอดที่ประกาศเป็นพับลิกไม่สามารถถูกลบล้างภายนอกโมดูลการกำหนดได้อีกต่อไป เมื่อต้องการอนุญาตให้คลาสย่อยคลาสภายนอกหรือวิธีการแทนที่ภายนอกให้ประกาศเป็นเปิดซึ่งเป็นระดับการเข้าถึงใหม่ที่เกินกว่าที่สาธารณะ คลาสและวิธีการที่นำเข้า Objective-C ขณะนี้นำเข้าทั้งหมดเป็นแบบเปิดแทนที่จะเป็นแบบสาธารณะ การทดสอบหน่วยที่นำเข้าโมดูลโดยใช้การนำเข้า @testable จะยังคงได้รับอนุญาตให้ subclass สาธารณะหรือคลาสภายในรวมทั้งแทนที่วิธีสาธารณะหรือภายใน (SE-0117)

ข้อมูลเพิ่มเติม & รายละเอียด: ภาษาโปรแกรม Swift (การควบคุมการเข้าถึง)


ดีคำตอบนี้เป็นสิ่งถูกต้องในรุ่นก่อนหน้านี้สวิฟท์ (s), ดูเหมือนว่ามันไม่ถูกต้องอีกต่อไป :) โปรดตรวจสอบคำตอบของฉัน
Ahmad F

4

ใน Beta 6 เอกสารระบุว่ามีตัวดัดแปลงการเข้าถึงที่แตกต่างกันสามตัว:

  • สาธารณะ
  • ภายใน
  • เอกชน

และทั้งสามนี้ใช้กับคลาสโปรโตคอลฟังก์ชั่นและคุณสมบัติ

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

สำหรับข้อมูลเพิ่มเติมให้ตรวจสอบการควบคุมการเข้าถึง


ควรมีตัวแก้ไขที่มีการป้องกันซึ่งช่วยให้การสร้างคลาสที่มีความปลอดภัยมากขึ้น
Kumar C

ดีคำตอบนี้เป็นสิ่งถูกต้องในรุ่นก่อนหน้านี้สวิฟท์ (s), ดูเหมือนว่ามันไม่ถูกต้องอีกต่อไป :) โปรดตรวจสอบคำตอบของฉัน
Ahmad F

2

ตอนนี้อยู่ในรุ่นเบต้า 4 พวกเขาได้เพิ่ม access modifiers ใน Swift

จากบันทึกย่อ realese Xcode 6 beta 4 :

การควบคุมการเข้าถึง Swift มีสามระดับการเข้าถึง:

  • private เอนทิตีสามารถเข้าถึงได้จากภายในแหล่งที่มาที่พวกเขาถูกกำหนดเท่านั้น
  • internal เอนทิตีสามารถเข้าถึงได้ทุกที่ภายในเป้าหมายที่พวกเขาถูกกำหนด
  • public เอนทิตีสามารถเข้าถึงได้จากทุกที่ภายในเป้าหมายและจากบริบทอื่น ๆ ที่นำเข้าโมดูลของเป้าหมายปัจจุบัน

ตามค่าเริ่มต้นเอนทิตีส่วนใหญ่ในซอร์สจะมีการเข้าถึงภายใน สิ่งนี้ช่วยให้นักพัฒนาแอปพลิเคชันละเว้นการควบคุมการเข้าถึงได้เป็นส่วนใหญ่ในขณะที่ให้นักพัฒนาเฟรมเวิร์กสามารถควบคุม API ของเฟรมเวิร์กได้อย่างสมบูรณ์


คุณสามารถโพสต์ลิงค์ไปยังสิ่งนี้ได้หรือไม่?
มนุษย์หิมะ

ดีคำตอบนี้เป็นสิ่งถูกต้องในรุ่นก่อนหน้านี้สวิฟท์ (s), ดูเหมือนว่ามันไม่ถูกต้องอีกต่อไป :) โปรดตรวจสอบคำตอบของฉัน
Ahmad F

2

กลไกการควบคุมการเข้าถึงตามที่แนะนำใน Xcode 6 :

Swift มีระดับการเข้าถึงที่แตกต่างกันสามระดับสำหรับเอนทิตีภายในรหัสของคุณ ระดับการเข้าถึงเหล่านี้สัมพันธ์กับไฟล์ต้นฉบับซึ่งมีการกำหนดเอนทิตีและสัมพันธ์กับโมดูลที่เป็นไฟล์ต้นฉบับ

  • การเข้าถึงสาธารณะช่วยให้สามารถใช้เอนทิตีภายในไฟล์ต้นฉบับใด ๆ จากโมดูลการกำหนดและในไฟล์ต้นฉบับจากโมดูลอื่นที่อิมพอร์ตโมดูลการกำหนด โดยทั่วไปคุณจะใช้การเข้าถึงสาธารณะเมื่อระบุส่วนต่อประสานสาธารณะกับกรอบงาน
  • การเข้าถึงภายในช่วยให้สามารถใช้เอนทิตีภายในไฟล์ต้นฉบับใด ๆ จากโมดูลการกำหนด แต่ไม่สามารถใช้ในไฟล์ต้นฉบับใด ๆ ภายนอกโมดูลนั้น โดยทั่วไปคุณใช้การเข้าถึงภายในเมื่อกำหนดโครงสร้างภายในของแอพหรือกรอบงาน
  • การเข้าถึงส่วนตัวจำกัด การใช้งานของเอนทิตีเพื่อกำหนดแหล่งไฟล์ของตัวเอง ใช้การเข้าถึงส่วนตัวเพื่อซ่อนรายละเอียดการใช้งานของฟังก์ชั่นการใช้งานที่เฉพาะเจาะจง

การเข้าถึงสาธารณะเป็นระดับการเข้าถึงสูงสุด (จำกัด น้อยที่สุด) และการเข้าถึงส่วนตัวเป็นระดับการเข้าถึงต่ำสุด (หรือ จำกัด มากที่สุด)

เริ่มต้น accecss ภายในและไม่จำเป็นต้องระบุ นอกจากนี้โปรดทราบว่าตัวระบุส่วนตัวไม่ทำงานในระดับชั้นเรียน แต่ในระดับไฟล์ต้นฉบับ ซึ่งหมายความว่าการรับส่วนของคลาสที่เป็นส่วนตัวจริงๆคุณต้องแยกเป็นไฟล์ของตัวเอง นอกจากนี้ยังแนะนำกรณีที่น่าสนใจเกี่ยวกับการทดสอบหน่วย ...

อีกประเด็นหนึ่งที่ฉันทำซึ่งแสดงความคิดเห็นในลิงก์ด้านบนคือคุณไม่สามารถ 'อัปเกรด' ระดับการเข้าถึงได้ หากคุณ subclass บางสิ่งคุณสามารถ จำกัด มันได้มากกว่า แต่ไม่ใช่วิธีอื่น

บิตสุดท้ายนี้ยังส่งผลกระทบต่อฟังก์ชั่นสิ่งอันดับและสิ่งอื่น ๆ อย่างแน่นอนในลักษณะที่ว่าหากฟังก์ชั่นใช้คลาสส่วนตัวแล้วมันไม่ถูกต้องที่จะมีฟังก์ชั่นภายในหรือสาธารณะเพราะอาจไม่สามารถเข้าถึงคลาสส่วนตัว ซึ่งส่งผลให้คำเตือนคอมไพเลอร์และคุณจำเป็นต้องประกาศฟังก์ชันเป็นฟังก์ชันส่วนตัวอีกครั้ง


ดีคำตอบนี้เป็นสิ่งถูกต้องในรุ่นก่อนหน้านี้สวิฟท์ (s), ดูเหมือนว่ามันไม่ถูกต้องอีกต่อไป :) โปรดตรวจสอบคำตอบของฉัน
Ahmad F

2

Swift 3 และ 4นำมาซึ่งการเปลี่ยนแปลงมากมายเช่นกันสำหรับระดับการเข้าถึงตัวแปรและวิธีการ ตอนนี้Swift 3 และ 4มีระดับการเข้าถึงที่แตกต่างกัน 4 ระดับโดยที่การเข้าถึงแบบเปิด / สาธารณะเป็นระดับการเข้าถึงสูงสุด (จำกัด น้อยที่สุด) และการเข้าถึงแบบส่วนตัวเป็นระดับการเข้าถึงต่ำสุด

  • ฟังก์ชั่นส่วนตัวและสมาชิกสามารถเข้าถึงได้จากภายในขอบเขตของเอนทิตีเอง (struct, class, …) และส่วนขยายของมัน (ใน Swift 3 และส่วนขยายถูก จำกัด ด้วย)
  • ฟังก์ชันfileprivateและสมาชิกสามารถเข้าถึงได้จากภายในไฟล์ต้นฉบับที่มีการประกาศเท่านั้น
  • ฟังก์ชั่นภายในและสมาชิก (ซึ่งเป็นค่าเริ่มต้นหากคุณไม่ได้เพิ่มคำสำคัญระดับการเข้าถึงอย่างชัดเจน) สามารถเข้าถึงได้ทุกที่ภายในเป้าหมายที่พวกเขาถูกกำหนดไว้ นั่นเป็นเหตุผลที่ TestTarget ไม่สามารถเข้าถึงแหล่งข้อมูลทั้งหมดโดยอัตโนมัติพวกเขาจะต้องทำเครื่องหมายว่าสามารถเข้าถึงได้ในตัวตรวจสอบไฟล์ของ xCode
  • ฟังก์ชั่นที่เปิดหรือสาธารณะและสมาชิกสามารถเข้าถึงได้จากทุกที่ภายในเป้าหมายและจากบริบทอื่น ๆ ที่นำเข้าโมดูลของเป้าหมายปัจจุบัน

ที่น่าสนใจ:

แทนที่จะทำเครื่องหมายทุกวิธีเดียวหรือสมาชิกเป็น "ส่วนตัว" คุณสามารถครอบคลุมบางวิธี (เช่นฟังก์ชันผู้ช่วยทั่วไป) ในส่วนขยายของคลาส / struct และทำเครื่องหมายส่วนขยายทั้งหมดเป็น "ส่วนตัว"

class foo { }

private extension foo {
    func somePrivateHelperFunction01() { }
    func somePrivateHelperFunction02() { }
    func somePrivateHelperFunction03() { }
}

นี่เป็นความคิดที่ดีเพื่อให้ได้รหัสที่สามารถบำรุงรักษาได้ดีขึ้น และคุณสามารถสลับ (เช่นสำหรับการทดสอบหน่วย) เป็นแบบไม่เป็นส่วนตัวได้อย่างง่ายดายเพียงแค่เปลี่ยนคำเดียว

เอกสารของ Apple


ดีคำตอบนี้เป็นสิ่งถูกต้องในรุ่นก่อนหน้านี้สวิฟท์ (s), ดูเหมือนว่ามันไม่ถูกต้องอีกต่อไป :) โปรดตรวจสอบคำตอบของฉัน
Ahmad F

2

สำหรับ Swift 1-3:

ไม่เป็นไปไม่ได้ ไม่มีวิธีการและตัวแปรส่วนตัว / ที่ได้รับการป้องกันเลย

ทุกอย่างเป็นสาธารณะ

อัปเดต ตั้งแต่ Swift 4 เป็นไปได้ที่จะเห็นคำตอบอื่น ๆ ในชุดข้อความนี้


1
ความคิดเห็นนี้ถูกต้องสำหรับเมล็ดปัจจุบัน
Jesper

2
สำหรับเมล็ดปัจจุบัน มันจะปรากฏขึ้นในอนาคต
Jesper

1
"สาธารณะ" / "ที่ได้รับการป้องกัน" / "ส่วนตัว" ไม่มีอยู่ในปัจจุบัน แต่คุณสามารถซ่อนสิ่งต่าง ๆ โดยใช้การปิดโพรโทคอลและคลาสภายใน - ซึ่งทำให้ค่อนข้างคล้ายกับรูปแบบโมดูลที่ใช้ใน JavaScript ทั่วไป โปรดดูตัวอย่างรหัสของฉันในการตอบกลับของฉันที่นี่สำหรับตัวอย่างของวิธีการทำเช่นนี้ หากฉันเข้าใจผิดเกี่ยวกับวิธีการทำงานและตัวอย่างของฉันไม่ถูกต้องโปรดระบุด้วยว่าฉันยังคงเรียนรู้อยู่ :)
Dave Kapp

ดูเหมือนว่ามันไม่ถูกต้องอีกต่อไป :) โปรดตรวจสอบคำตอบของฉัน
Ahmad F

1

หนึ่งในตัวเลือกที่คุณสามารถใช้คือการตัดการสร้างอินสแตนซ์เข้าไปในฟังก์ชันและจัดหาตัวรับและตัวตั้งค่าที่เหมาะสมในตัวสร้าง:

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

0

ไวยากรณ์ภาษาไม่ได้มีคำหลัก 'สาธารณะ', 'ส่วนตัว' หรือ 'การป้องกัน' สิ่งนี้จะแนะนำทุกอย่างที่เป็นสาธารณะ แน่นอนอาจมีวิธีอื่นในการระบุตัวดัดแปลงการเข้าถึงโดยไม่มีคำหลักเหล่านั้น แต่ฉันไม่พบในการอ้างอิงภาษา


0

หวังว่าจะประหยัดเวลาสำหรับผู้ที่ต้องการบางสิ่งบางอย่างคล้ายกับวิธีการป้องกัน:

ตามคำตอบอื่น ๆ ตอนนี้ swift มีตัวแก้ไข 'ส่วนตัว' - ซึ่งถูกกำหนดไว้ในไฟล์แทนที่จะเป็นคลาสที่ชาญฉลาดเช่นใน Java หรือ C # เป็นต้น ซึ่งหมายความว่าหากคุณต้องการวิธีการป้องกันคุณสามารถทำได้ด้วยวิธีการส่วนตัวที่รวดเร็วหากอยู่ในไฟล์เดียวกัน

  1. สร้างคลาสพื้นฐานเพื่อเก็บเมธอด 'protected' (ส่วนตัวจริง ๆ )
  2. ซับคลาสคลาสนี้เพื่อใช้วิธีการเดียวกัน
  3. ในไฟล์อื่นคุณไม่สามารถเข้าถึงเมธอดคลาสพื้นฐานได้แม้ว่าคุณจะคลาสย่อยด้วยก็ตาม

เช่นไฟล์ 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
    }

}



-2

จนถึง swift 2.0 มีเพียงสามระดับการเข้าถึง [สาธารณะภายในส่วนตัว] แต่ใน swift 3.0 apple เพิ่มระดับการเข้าถึงใหม่สองระดับคือ [Open, fileType] ดังนั้นตอนนี้ใน swift 3.0 มี 5 ระดับการเข้าถึงที่นี่ฉันต้องการล้างบทบาท ของระดับการเข้าถึงสองระดับ 1. เปิด: คล้ายกับสาธารณะมาก แต่มีความแตกต่างเพียงอย่างเดียวคือสาธารณะสามารถเข้าถึงคลาสย่อยและแทนที่ได้และระดับการเข้าถึงแบบเปิดไม่สามารถเข้าถึงได้ว่า ภาพนี้นำมาจากเว็บไซต์ขนาดกลางและอธิบายถึงความแตกต่าง ระหว่างการเปิดและการเข้าถึงสาธารณะ

ตอนนี้ถึงระดับการเข้าถึงใหม่ที่สอง filetype เป็นรุ่นที่ใหญ่กว่าของระดับการเข้าถึงส่วนตัวหรือน้อยกว่าภายใน fileType สามารถเข้าถึงส่วนที่ขยายของ [class, struct, enum] และส่วนตัวไม่สามารถเข้าถึงส่วนขยายของรหัสที่สามารถเข้าถึงได้เท่านั้น ขอบเขตคำศัพท์ ภาพนี้นำมาจากเว็บไซต์ขนาดกลางและอธิบายความแตกต่างระหว่างระดับการเข้าถึงไฟล์และประเภทส่วนตัว

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