English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية

تحكم في الوصول Swift

يمكن تحديد مستوى الوصول للكود في ملفات المصدر أو الملتقيات الأخرى إلى الكود الخاص بك.

يمكن تعيين مستوى الوصول للنوع الخاص (فئة، بنية، جرد) بشكل واضح، وكذلك للخصائص والوظائف والمتغيرات الأساسية والمؤشرات الأساسية للنوع.

يمكن تحديد نطاق استخدام الاتفاقيات أيضًا، بما في ذلك الكيانات العالمية في الاتفاقية مثل الكيانات الثابتة والغير محددة.

يتم التحكم في الوصول بناءً على الملتقى وملف المصدر.

الملتقى هو وحدة مستقلة يتم بناؤها ونشرها كـ Framework أو تطبيق. يمكن استخدام كلمة المفتاح import لاستيراد ملتقى آخر في Swift.

ملف المصدر هو ملف المصدر الواحد، وهو عادة ما ينتمي إلى ملتقى، يمكن أن يحتوي ملف المصدر على تعريفات فئات ووظائف متعددة.

يقدم Swift أربعة مستويات مختلفة من الوصول للكيانات في الكود: public، internal، fileprivate، private.

مستوى الوصولتعريف
publicيمكن الوصول إلى أي كيان في ملفات المصدر الخاصة بالملتقى، يمكن للآخرين أيضًا الوصول إلى جميع الكيانات في ملفات المصدر الخاصة بالملتقى من خلال استيراد هذا الملتقى.
internalيمكن الوصول إلى أي كيان في ملفات المصدر الخاصة بالملتقى، ولكن لا يمكن للآخرين الوصول إلى هذه الكيانات في ملفات المصدر الخاصة بالملتقى.
fileprivateخاص بالملف، يمكن استخدامه فقط داخل ملف المصدر الحالي.
privateيمكن الوصول إليه داخل الفئة فقط، لا يمكن الوصول إليه خارج نطاق الفئة أو بنية المخطط.

public هو مستوى الوصول الأعلى، private هو مستوى الوصول الأدنى.

النحو

يتم تعريف مستوى الوصول للكيانات من خلال التعديلات public، internal، fileprivate، private:

مثال تفاعلي

public class SomePublicClass {}
internal class SomeInternalClass {}
fileprivate class SomeFilePrivateClass {}
private class SomePrivateClass {}
 
public var somePublicVariable = 0
internal let someInternalConstant = 0
fileprivate func someFilePrivateFunction() {}
private func somePrivateFunction() {}

إلا إذا كان هناك توجيه خاص، فإن جميع الكيانات تستخدم مستوى الوصول الافتراضي internal.

未指定访问级别默认为 internal

class SomeInternalClass {}              // 访问级别为 internal
let someInternalConstant = 0            // 访问级别为 internal

函数类型访问权限

函数的访问级别需要根据该函数的参数类型和返回类型的访问级别得出。

下面的实例定义了一个名为someFunction全局函数,并且没有明确地申明其访问级别。

func someFunction() -> (SomeInternalClass, SomePrivateClass) {
    // 函数实现
{}

函数中其中一个类 SomeInternalClass 的访问级别是 internal,另一个 SomePrivateClass 的访问级别是 private。所以根据元组访问级别的原则,该元组的访问级别是 private(元组的访问级别与元组中访问级别最低的类型一致)。

因为该函数返回类型的访问级别是 private,所以你必须使用 private 修饰符,明确的声明该函数:

private func someFunction() -> (SomeInternalClass, SomePrivateClass) {
    // 函数实现
{}

将该函数申明为 public 或 internal,或者使用默认的访问级别 internal 都是错误的,因为如果这样你就无法访问 private 级别的返回值。

枚举类型访问权限

枚举中成员的访问级别继承自该枚举,你不能为枚举中的成员单独申明不同的访问级别。

مثال تفاعلي

比如下面的实例,枚举 Student 被明确的申明为 public 级别,那么它的成员 Name,Mark 的访问级别同样也是 public:

مثال تفاعلي

public enum Student {
    case Name(String)
    case Mark(Int,Int,Int)
{}
 
var studDetails = Student.Name("Swift")
var studMarks = Student.Mark(98,97,95)
 
switch studMarks {
case .Name(let studName):
    print("学生名: \(studName).")
case .Mark(let Mark1, let Mark2, let Mark3):
    اطبع("نسبة النجاح: (Mark1),(Mark2),(Mark3)")
{}

نتيجة تنفيذ البرنامج أعلاه هي:

نسبة النجاح: 98,97,95

مستوى الوصول للفرع

لا يمكن أن يكون مستوى الوصول للفرع أعلى من مستوى الأب. على سبيل المثال، إذا كان مستوى الوصول للأب هو internal، فإن مستوى الوصول للفرع لا يمكن أن يتم تعريفه كpublic.

مثال تفاعلي

 public class SuperClass {
    fileprivate func show() {
        اطبع("مستوى أعلى")
    {}
{}
 
// مستوى الوصول لا يمكن أن يكون أعلى من مستوى الأب internal > public
internal class SubClass: SuperClass {
    override internal func show() {
        اطبع("فرع")
    {}
{}
 
let sup = SuperClass()
sup.show()
 
let sub = SubClass()
sub.show()

نتيجة تنفيذ البرنامج أعلاه هي:

مستوى أعلى
فرع

مستوى الوصول للثوابت والمتغيرات والخصائص وأسماء المفاتيح

لا يمكن أن يكون مستوى الوصول للثوابت والمتغيرات والخصائص أعلى من نوعها.

على سبيل المثال، إذا قمت بتعريف خاصية مستوى الوصول public، ولكن نوعها هو private، فإن هذا غير مسموح به من قبل محرر الكود.

على نفس المنوال، لا يمكن أن يكون مستوى الوصول للسحابة أعلى من نوع نوعها أو نوع العائد.

على سبيل المثال، إذا كان نوع تعريف الثابت أو المتغير أو الخاصية أو اسم المفتاح هو مستوى الوصول private، فإنه يجب التأكيد على إعلان مستوى الوصول كprivate:

private var privateInstance = SomePrivateClass()

مستوى الوصول للمدخلات والخروجات

مستوى الوصول للمدخلات والخروجات للثوابت والمتغيرات والخصائص وأسماء المفاتيح يرث من مستوى الوصول للمكونات التي تنتمي إليها.

مستوى الوصول للمدخلات يمكن أن يكون أقل من مستوى الوصول للخروجات، مما يتيح التحكم في حقوق الوصول للقراءة والكتابة على المتغيرات والخصائص أو أسماء المفاتيح.

مثال تفاعلي

class Samplepgm {
    fileprivate var counter: Int = 0{
        willSet(newTotal){
            اطبع("مستوى العداد: (newTotal)")
        {}
        didSet{
            إذا كان (counter > oldValue) {
                اطبع("إضافة كمية جديدة (counter - oldValue)")
            {}
        {}
    {}
{}
 
let NewCounter = Samplepgm()
NewCounter.counter = 100
NewCounter.counter = 800

مستوى الوصول لـ counter هو fileprivate، يمكن الوصول إليه داخل الملف.

نتيجة تنفيذ البرنامج أعلاه هي:

حساب التكرار: 100
زيادة الكمية 100
حساب التكرار: 800
زيادة الكمية 700

تصريح الوصول للبناء والبناء الافتراضي

التحميل

يمكننا تحديد مستوى الوصول للطريقة الافتراضية للتحميل المحدد، ولكن لا يمكن أن يكون أعلى من مستوى الوصول للنوع الذي ينتمي إليه. لكن هذا استثناء للحافز المطلوب، الذي يجب أن يكون مستوى الوصول نفسه لمستوى الوصول للنوع.

مستوى الوصول لمعاملات الطريقة الافتراضية للتحميل لا يمكن أن يكون أقل من مستوى الوصول للطريقة الافتراضية للتحميل.

الطريقة الافتراضية للتحميل

يقدم Swift بنية واجهة للتحميل المحدد، وهي تستخدم لتقديم عمليات الافتراضية لجميع الخصائص، ولكن لا تقدم قيمًا محددة.

مستوى الوصول للطريقة الافتراضية للتحميل معين مع مستوى الوصول للنوع.

مثال تفاعلي

استخدم كلمة المفتاح required قبل طريقة init() في كل فرع قبلها.

مثال تفاعلي

class classA {
    required init() {
        var a = 10
        print(a)
    {}
{}
 
class classB: classA {
    required init() {
        var b = 30
        print(b)
    {}
{}
 
let res = classA()
let show = classB()

نتيجة تنفيذ البرنامج أعلاه هي:

10
30
10

تصريح الوصول للبروتوكول

إذا كنت ترغب في تحديد مستوى الوصول لبروتوكول بوضوح، فإنه يجب عليك التأكد من أن البروتوكول يستخدم فقط في نطاق الوصول الذي قمت بتحديده.

إذا قمت بتعريف بروتوكول متاح عام، فإن الدوال الضرورية التي يقدمها هذا البروتوكول ستكون متاحة عامًا أيضًا. هذا يختلف عن أنواع أخرى مثل أنواع متاحة عامًا أخرى، أعضاؤها متاحة للوصول الداخلي.

مثال تفاعلي

public protocol TcpProtocol {
    init(no1: Int)
{}
 
public class MainClass {
    var no1: Int // local storage
    init(no1: Int) {
        self.no1 = no1 // initialization
    {}
{}
 
class SubClass: MainClass, TcpProtocol {
    var no2: Int
    init(no1: Int, no2: Int) {
        self.no2 = no2
        super.init(no1:no1)
    {}
    
    // يتطلب فقط معاملًا واحدًا للطريقة المريحة
    required override convenience init(no1: Int) {
        self.init(no1:no1, no2:0)
    {}
{}
 
let res = MainClass(no1: 20)
let show = SubClass(no1: 30, no2: 50)
 
print("res is: \(res.no1)")
print("res is: \(show.no1)")
print("res is: \(show.no2)")

نتيجة تنفيذ البرنامج أعلاه هي:

res is: 20
res is: 30
res is: 50

مستوى الوصول للتوسيع

يمكنك في حالة السماح بتمديد أنواع مثل الفئات أو الأشكال أو المجموعات. يجب أن يكون عضو التمديد متوافقًا مع مستوى الوصول للعضو الأصلي. على سبيل المثال، إذا تم تمديد نوع عام، فإن العضو الجديد يجب أن يكون له نفس مستوى الوصول الافتراضي للعضو.

أو، يمكنك تحديد بوضوح مستوى الوصول للتمديد (مثل استخدام private extension) للجميع في التمديد هذا جديد مستوى الوصول الافتراضي للعضو. يمكن أن تغطي هذه المستوى الوصول الافتراضي المستوى الوصول المحدد لكل عضو.

مستوى الوصول الجماعي

يأخذ مستوى الوصول للنوع الجماعي أو الدالة الجماعية مستوى الوصول الأدنى بين النوع الجماعي نفسه والدالة الجماعية والمعدلات الجماعية.

مثال تفاعلي

public struct TOS<T> {
    var items = [T]()
    private mutating func push(item: T) {
        items.append(item)
    {}
    
    mutating func pop() -> T {
        return items.removeLast()
    {}
{}
 
var tos = TOS<String>()
tos.push("Swift")
print(tos.items)
 
tos.push("الأنواع المجردة")
print(tos.items)
 
tos.push("معدل نوع")
print(tos.items)
 
tos.push("اسم معدل نوع")
print(tos.items)
let deletetos = tos.pop()

نتيجة تنفيذ البرنامج أعلاه هي:

["Swift"]
["Swift", "الأنواع المجردة"]
["Swift", "أجسام", "معدلات نوع"]
["Swift", "أجسام", "معدلات نوع", "اسم معدل نوع"]

اسم نوع

أي نوع اسم نوع تعده سيتم اعتباره نوعًا مختلفًا، مما يسهل التحكم في الوصول. لا يمكن أن تكون دقة اسم النوع أعلى من دقة النوع الأصلي.

على سبيل المثال، يمكن تعيين اسم نوع مستوى خصوصية عالي إلى نوع يمكنه أن يكون عامًا أو داخليًا أو خاصًا، ولكن يمكن تعيين اسم نوع مستوى عام فقط إلى نوع مستوى عام، وليس إلى نوع داخلي أو خاص.

ملاحظة: تنطبق هذه القاعدة أيضًا على تسمية أسماء别名 للأنواع لضمان تطابق البروتوكول.

مثال تفاعلي

public protocol Container {
    typealias ItemType
    mutating func append(item: ItemType)
    var count: Int { get }
    subscript(i: Int) -> ItemType { get }
{}
 
struct Stack<T>: Container {
    //تنفيذ Stack<T> الأصلي
    var items = [T]()
    mutating func push(item: T) {
        items.append(item)
    {}
    
    mutating func pop() -> T {
        return items.removeLast()
    {}
    
    //التزام البروتوكول الحاوي
    mutating func append(item: T) {
        self.push(item)
    {}
    
    var count: Int {
        return items.count
    {}
    
    subscript(i: Int) -> T {
        return items[i]
    {}
{}
 
func allItemsMatch<
    C1: Container, C2: Container
    حيث C1.ItemType == C2.ItemType, C1.ItemType: Equatable>
    (someContainer: C1, anotherContainer: C2) -> Bool {
        //تحقق من أن كلا الحاويتين تحتوي على نفس عدد العناصر
        إذا كان someContainer.count != anotherContainer.count {
            return false
        {}
        
        //تحقق من كل زوج من العناصر لمعرفة ما إذا كانت متطابقة
        for i in 0..<someContainer.count {
            if someContainer[i] != anotherContainer[i] {
                return false
            {}
        {}
        
        // جميع العناصر تطابق، لذا قم بإرجاع true
        return true
{}
 
var tos = Stack<String>()
tos.push("Swift")
print(tos.items)
 
tos.push("الأنواع المجردة")
print(tos.items)
 
tos.push("جملة Where")
print(tos.items)
 
var eos = ["Swift", "الأنواع المجردة", "جملة Where"]
print(eos)

نتيجة تنفيذ البرنامج أعلاه هي:

["Swift"]
["Swift", "الأنواع المجردة"]
["Swift", "الأنواع المجردة", "جملة Where"]
["Swift", "الأنواع المجردة", "جملة Where"]