iOS / Swift / قيم Swift وملكية SwiftUI / الدرس 2
نماذج القيم والمجموعات والأخطاء
استخدم البنى والتعدادات لحفظ الثوابت وافهم متى لا يكفي نسخ المجموعة لحماية المراجع المشتركة.
في هذه الصفحة
أهداف الدرس
- اختر القيم للقطات المستقلة
- اجعل الانتقالات المعيبة صعبة التعبير
- وضّح استقلال اللقطة
اختر القيم للقطات المستقلة
للبنية struct دلالات قيمة؛ فإسنادها أو تمريرها ينتج مفاهيميا قيمة مستقلة. ويمكن لـ Swift تحسين التخزين بالنسخ عند الكتابة للمجموعات دون تغيير العقد المرصود. وللصنف class دلالات مرجع، فقد يشير متغيران إلى الكائن نفسه. اختر بحسب الهوية والملكية لا بقاعدة تفوق أحدهما في السرعة. تفيد السجلات الثابتة الصغيرة كمدخلات للواجهات لسهولة فهم اللقطة. لكن البنية التي تحوي مرجعا إلى صنف متغير تشارك الكائن المشار إليه ما لم تنسخه أو تعزله عمدا.
اجعل الانتقالات المعيبة صعبة التعبير
ينبغي للنموذج تسمية المقادير وإثبات الثوابت التي يعتمد عليها المستدعي. يعرّف المقتطف الأول ورشة بعدد مقاعد غير سالب وعملية قد تفشل عند نقص السعة. تُظهر mutating صراحة أن الدالة تغير القيمة. يوضح خطأ المجال الفشل دون اختراع سجل ناجح جزئيا. لا يفرض النموذج تفويض الخادم أو السعة المتزامنة بين العملاء؛ بل يصف قاعدة محلية مصطنعة. تحتاج الأوامر البعيدة إلى خدمة معتمدة حتى لو كان نموذج القيمة المحلي صحيحا تماما.
enum SeatError: Error { case invalidCount, insufficientCapacity }
struct Workshop {
let id: String
private(set) var seats: Int
init(id: String, seats: Int) throws {
guard !id.isEmpty, seats >= 0 else { throw SeatError.invalidCount }
self.id = id; self.seats = seats
}
mutating func reserve(_ count: Int) throws {
guard count > 0 else { throw SeatError.invalidCount }
guard count <= seats else { throw SeatError.insufficientCapacity }
seats -= count
}
}
Accepted models have nonempty identity and nonnegative seats; invalid reservations throw before mutation.
تسمح private(set) بالقراءة وتقيد الكتابة المباشرة. المثال نموذج محلي وليس خدمة حجز حقيقية.
وضّح استقلال اللقطة
ينسخ المقتطف الثاني قيمة ورشة ويحجز في النسخة ويطبع العددين. تبقى الأصلية دون تغيير. يفيد هذا عند إنشاء مسودة قابلة للتحرير من بيانات محفوظة؛ إذ يلغي المستخدم المسودة بدلا من إعادة بناء الحالة القديمة. حدّد حدث الحفظ كي لا تصبح المسودة معتمدة بصمت. تنتمي معالجة الخطأ إلى موضع قادر على التعافي، وينبغي لفشل الحجز إبقاء القيمة متسقة. لا تستعمل try! لتقصير المثال إذا كان الفشل جزءا من عقد المجال.
do {
let original = try Workshop(id: "w-7", seats: 5)
var draft = original
try draft.reserve(2)
print(original.seats)
print(draft.seats)
} catch {
print("Reservation rejected")
}
5
3
يعتمد المقتطف على Workshop في المثال الأول. لا تتغير سعة بعيدة أو معاملة حقيقية.
استخدم عمليات المجموعات بقاعدة ترتيب مستقرة
تحفظ Array ترتيب العناصر، وتوفر Dictionary وصولا بالمفتاح لكنها ليست بديلا لسياسة فرز مرئية صريحة. وتمثل Set العضوية دون تكرار وتفيد لمعرّفات الاختيار. اختر المجموعة الموافقة للعملية بدلا من تحويلها في كل صف. يحفظ الترشيح ترتيب المصفوفة النسبي، بينما يحتاج الفرز إلى مقارنة متسقة. وإذا تساوت تسميتان فقرّر هل يحدد المعرّف المستقر الترتيب الثانوي كي لا تبدو البيانات المتجددة متقلبة عشوائيا.
استخدم التعدادات للبدائل ذات المعنى
يمكن للتعداد تمثيل التحميل والنجاح والفشل أوضح من قيم منطقية متعددة تنتج تراكيب متناقضة. وتحمل القيم المرتبطة بيانات الحالة أو سياق الخطأ. ويلزم switch العرض بمراعاة البدائل التي يعلنها النوع. تجنب جمع شواغل غير مرتبطة في تعداد ضخم؛ نمذج الحالات المستقلة منفصلة إذا كانت تراكيبها صحيحة فعلا. فقد ينشط التحديث مع بقاء نتائج سابقة، لذا ينبغي للعقد بيان هل تحمل حالة التحميل بيانات قديمة بدلا من افتراض شاشة فارغة دائما.
اختبر الثوابت عند كل حد تعديل
تشمل الفحوص إنشاء صفر مقاعد ورفض السالب وحجز السعة كاملة ورفض الطلب الزائد والتأكد من حفظ القيمة السابقة عند الفشل. اختبر نسخة المسودة أيضا لإثبات استقلالها المقصود. وإذا احتوى النموذج لاحقا كائنات مرجعية متغيرة فأضف فحص ملكية داخلية بدلا من افتراض أن struct تضمن النسخ العميق. أبق الاختبارات نقية ومصطنعة. يثبت نجاحها الثوابت المحلية، بينما تبقى التعارضات الموزعة وصلاحيات الخادم والحفظ الدائم شواغل تكامل مستقلة.
الأخطاء الشائعة وإصلاحها
تغيّر البنية المنسوخة بيانات داخلية مشتركة
- لماذا يحدث؟
- يشير حقل إلى كائن الصنف المتغير نفسه.
- كيف تصلحه؟
- استخدم قيما داخلية ثابتة أو سياسة ملكية ونسخ صريحة.
- كيف تتجنب تكراره؟
- اختبر التعديل الداخلي لا الإسناد الأعلى فقط.
يتحول الفشل إلى نجاح مختلق
- لماذا يحدث؟
- أزال try? أو البديل الفرق بين الخطأ والنجاح.
- كيف تصلحه؟
- أتح نتيجة اختيارية أو خطأ مفهوما يناسب التعافي.
- كيف تتجنب تكراره؟
- راجع كل تحويل يفقد معلومات الخطأ.
يغير التحديث ترتيب الصفوف المرئي اعتباطيا
- لماذا يحدث؟
- لم تُحدّد سياسة ترتيب صريحة للمجموعة.
- كيف تصلحه؟
- افرز بحقول موثقة ومعيار ثانوي مستقر عند الحاجة.
- كيف تتجنب تكراره؟
- اختبر التسميات المتساوية وعينات المدخل المعاد ترتيبها.
اختبر فهمك
1. لماذا تفحص reserve العدد قبل الطرح؟
اعرض الحل المشروح
يجب أن تنتج العملية قيمة صحيحة جديدة أو تفشل دون تغيير الحالة المقبولة. يحفظ فحص الإيجابية والسعة أولا عدم السلبية ويمنع إصلاح قيمة عدلت جزئيا داخل catch. ينتمي الثابت إلى عملية النموذج نفسها.
2. متى تُفضّل Set على Array لمعرّفات الورش المختارة؟
اعرض الحل المشروح
حين يمثل الاختيار عضوية فريدة ولا يخزن ترتيب العرض. تمنع Set التكرار وتدعم فحص العضوية. اشتق ترتيب العرض من مصفوفة الورش المرتبة؛ وإذا كان ترتيب الاختيار مهما فاختر تمثيلا يسجله صراحة.
أهم ما تعلمته
- اختر القيم للقطات المستقلة
- اختبر الثوابت عند كل حد تعديل