0Pricing
Swift Academy · درس

مسارات المفاتيح القابلة للكتابة والمرجعية

اقرأ واكتب عبر مسارات المفاتيح.

مسارات المفاتيح القابلة للكتابة والمرجعية درس مجاني في Swift Academy على CoddyKit. هذا هو الدرس 3 من أصل 4. يمكنك قراءة الدرس كاملاً أدناه مجاناً — ثم تمرن عليه مباشرة في المتصفح باستخدام محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7. هذا الدرس جزء من مسار التعلم في Swift Academy، وتقدمك يتزامن عبر الويب وتطبيق CoddyKit. تتضمن دورة Swift Academy 4 دروس في المجموع.

مسارات المفاتيح للقراءة فقط مقابل مسارات المفاتيح القابلة للكتابة

لا يستطيع KeyPath العادي سوى قراءة قيمة. وللكتابة من خلال مسار مفتاح، تحتاجون إلى نوع قابل للكتابة. توفر Swift نوعين منه، أحدهما لأنواع القيم والآخر للأنواع المرجعية.

يتناول هذا الدرس WritableKeyPath مع البنى وReferenceWritableKeyPath مع الأصناف، وكيف تصبح الصيغة الفرعية [keyPath:] قابلة للتعيين.

struct Person {
    var name: String
    var age: Int
}

let writable: WritableKeyPath<Person, Int> = \Person.age
print(type(of: writable))

WritableKeyPath لأنواع القيم

يستهدف WritableKeyPath خاصية مخزنة قابلة للتغيير في نوع قيمة. وللتعيين من خلاله، يجب أن يكون المثيل نفسه من النوع var، لأن تغيير خاصية بنية يغيّر القيمة بأكملها.

استخدموا الصيغة الفرعية [keyPath:] في الجانب الأيسر من عملية إسناد للكتابة.

struct Person {
    var name: String
    var age: Int
}

var alice = Person(name: "Alice", age: 30)
let agePath = \Person.age
alice[keyPath: agePath] = 31
print(alice.age)

لماذا يجب أن يكون المثيل من النوع var

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

تحاكي هذه القاعدة تغيير الخاصية المعتاد: لا يمكنكم تعيين خاصية مخزنة في بنية إلا عندما تكون البنية محتفظًا بها في متغير.

struct Point {
    var x: Int
    var y: Int
}

var p = Point(x: 1, y: 2)
p[keyPath: \Point.x] = 10
p[keyPath: \Point.y] = 20
print(p)

مساعد تعيين عام

بما أن مسار المفتاح القابل للكتابة يحدد الخاصية التي يجب تغييرها، يمكنكم كتابة دالة عامة تحدّث أي خاصية في أي نوع قيمة. مرّروا المثيل باستخدام inout حتى تُعاد كتابة التغيير في المصدر.

يشكل هذا أساس أدوات التحديث الوظيفي الصغيرة.

func update<Root, Value>(_ root: inout Root, _ path: WritableKeyPath<Root, Value>, to value: Value) {
    root[keyPath: path] = value
}

struct Person { var name: String; var age: Int }
var bob = Person(name: "Bob", age: 40)
update(&bob, \.age, to: 41)
print(bob.age)

ReferenceWritableKeyPath للأصناف

توفر Swift للأصناف النوع ReferenceWritableKeyPath. وبما أن مثيل الصنف مرجع، يمكنكم الكتابة من خلاله حتى عندما يكون المثيل محفوظًا في ثابت let؛ فالمرجع نفسه لا يتغير، وإنما يتغير الكائن الذي يشير إليه.

هذا هو الفرق الأساسي عن مسارات المفاتيح القابلة للكتابة لأنواع القيم.

class Counter {
    var value: Int = 0
}

let counter = Counter()
let path: ReferenceWritableKeyPath<Counter, Int> = \Counter.value
counter[keyPath: path] = 5
print(counter.value)

مرجع let وكائن قابل للتغيير

لاحظوا أن مثيل الصنف أدناه من النوع let، ومع ذلك يمكننا تعيين خاصيته من خلال مسار المفتاح. أما مع بنية، فسيؤدي ذلك إلى خطأ في الترجمة.

ذلك لأن تغيير خاصية في صنف لا يتطلب أن يكون المرجع قابلًا للتغيير، بل يتطلب أن تكون الخاصية نفسها قابلة للتغيير فقط.

class Profile {
    var nickname: String = ""
}

let profile = Profile()
let nickPath = \Profile.nickname
profile[keyPath: nickPath] = "Ace"
print(profile.nickname)

التسلسل الهرمي لأنواع مسارات المفاتيح

تشكل أنواع مسارات المفاتيح القابلة للكتابة تسلسلًا هرميًا. إذ إن ReferenceWritableKeyPath نوع فرعي من WritableKeyPath، وهو بدوره نوع فرعي من KeyPath. لذلك يمكن استخدام مسار مفتاح أكثر تخصيصًا في أي موضع يُتوقَّع فيه مسار أكثر عمومية.

وهذا يعني أن بإمكانكم تمرير ReferenceWritableKeyPath إلى دالة لا تحتاج إلا إلى القراءة من خلال KeyPath.

class Box { var size: Int = 1 }

func readSize(_ box: Box, _ path: KeyPath<Box, Int>) -> Int {
    box[keyPath: path]
}

let writable: ReferenceWritableKeyPath<Box, Int> = \Box.size
print(readSize(Box(), writable))

تحديث أنواع القيم المتداخلة

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

نغيّر هنا المدينة داخل عنوان متداخل.

struct Address { var city: String }
struct Person { var name: String; var address: Address }

var carol = Person(name: "Carol", address: Address(city: "Oslo"))
carol[keyPath: \Person.address.city] = "Bergen"
print(carol.address.city)

تطبيق تحديثات متعددة

بما أن مسارات المفاتيح القابلة للكتابة قيم، يمكنكم تخزين قائمة من التحديثات على شكل أزواج من مسارات المفاتيح والقيم وتطبيقها في حلقة. هذا نظام تصحيحات صغير.

نطبّق هنا تغييرين على بنية إعدادات.

struct Settings { var volume: Int; var brightness: Int }

var settings = Settings(volume: 5, brightness: 5)
func apply(_ s: inout Settings, _ path: WritableKeyPath<Settings, Int>, _ v: Int) {
    s[keyPath: path] = v
}
apply(&settings, \.volume, 8)
apply(&settings, \.brightness, 3)
print(settings)

تهيئة بأسلوب الربط

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

نعيّن هنا نص تسمية من خلال مسار مفتاح مرجعي قابل للكتابة.

class Label { var text: String = "" }

func configure<T: AnyObject, V>(_ object: T, _ path: ReferenceWritableKeyPath<T, V>, _ value: V) -> T {
    object[keyPath: path] = value
    return object
}

let label = configure(Label(), \.text, "Hello")
print(label.text)

اختيار نوع مسار المفتاح المناسب

استخدموا KeyPath عند القراءة فقط، وWritableKeyPath لتعيين خاصية في نوع قيمة مخزّن في var، وReferenceWritableKeyPath لتعيين خاصية في صنف حتى من خلال let.

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

struct S { var n: Int }
class C { var n: Int = 0 }

let read: KeyPath<S, Int> = \S.n
let writeStruct: WritableKeyPath<S, Int> = \S.n
let writeClass: ReferenceWritableKeyPath<C, Int> = \C.n
print(type(of: read), type(of: writeStruct), type(of: writeClass))

تحقق سريع: مسارات المفاتيح القابلة للكتابة

تذكّروا نوع مسار المفتاح الذي يتيح لكم تعيين خاصية في صنف حتى عندما يكون المثيل ثابتًا من النوع let.

مراجعة: مسارات المفاتيح القابلة للكتابة والمرجعية

تعلمتم كيفية الكتابة من خلال مسارات المفاتيح:

  • يعيّن WritableKeyPath خاصية مخزنة في نوع قيمة، ويتطلب وجود مثيل من النوع var.
  • يعيّن ReferenceWritableKeyPath خاصية في صنف، ويعمل حتى من خلال let.
  • تظهر الصيغة الفرعية [keyPath:] في الجانب الأيسر من عملية إسناد للكتابة.
  • تشكل الأنواع تسلسلًا هرميًا، لذلك يمكن أن يحل مسار مفتاح قابل للكتابة محل مسار للقراءة فقط.
  • تعتمد أدوات التعيين العامة باستخدام inout ومساعدات التهيئة على هذه الأنواع.

سترون بعد ذلك @dynamicMemberLookup، الذي يستخدم مسارات المفاتيح لإتاحة الوصول إلى البيانات الديناميكية باستخدام الصيغة النقطية.

struct Person { var name: String; var age: Int }

var dave = Person(name: "Dave", age: 27)
dave[keyPath: \Person.age] = 28
print("Updated age: \(dave.age)")

الأسئلة الشائعة

هل درس «مسارات المفاتيح القابلة للكتابة والمرجعية» مجاني؟

نعم — نص درس «مسارات المفاتيح القابلة للكتابة والمرجعية» كامل متاح مجاناً هنا على الويب. لتمرينه بشكل تفاعلي (محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7) وفتح باقي دورة Swift Academy، انتقل إلى CoddyKit PRO. تتضمن دورة Swift Academy 4 دروس في المجموع.

ماذا ستتعلم في «مسارات المفاتيح القابلة للكتابة والمرجعية»؟

اقرأ واكتب عبر مسارات المفاتيح. تتمرن على Swift Academy مع أكواد عملية تشغلها مباشرة في المتصفح، ومدرس ذكاء اصطناعي متاح 24/7 يجيب على أسئلتك أثناء عملك.

هل أحتاج إلى خبرة سابقة لأبدأ Swift Academy؟

لا تُشترط خبرة سابقة. Swift Academy على CoddyKit منظم للمبتدئين حتى المتقدمين، لذا يمكنك البدء من هنا أو من البداية والتقدم بسرعتك الخاصة. هذا هو الدرس 3 من أصل 4.

كم من الوقت يستغرق درس «مسارات المفاتيح القابلة للكتابة والمرجعية»؟

معظم دروس CoddyKit تستغرق حوالي 5–10 دقائق. كل منها موجز وتفاعلي، لذا تحرز تقدماً مستمراً وتستأنف من حيث توقفت عبر الويب والتطبيق.

هل يمكنني كتابة وتشغيل أكواد في درس Swift Academy هذا؟

نعم. كل درس في Swift Academy يتضمن محرر أكواد مدمج، لذا تكتب وتشغل أكواداً حقيقية مباشرة في متصفحك وتحصل على تعليقات فورية من الذكاء الاصطناعي — بدون إعداد محلي.

جميع الدروس في هذه الدورة

  1. أساسيات KeyPath
  2. استخدام KeyPaths في المجموعات
  3. مسارات المفاتيح القابلة للكتابة والمرجعية
  4. ‏@dynamicMemberLookup
← العودة إلى Swift Academy