إنشاء Swift : استخدامInitialization و Initializer
قمنا في دروس سابقة بإنشاء تطبيق مهام to-do . في هذا الدرس سنقوم بإعادة هيكلة نموذج البيانات وذلك من خلال إنشاء صنف نموذجي تقليدي.
1. نموذج البيانات
يحتوي نموذج البيانات الذي سنقوم بالتحدث عنه على صنفين وهما Task
class و ToDo
class
والذي تم توريثه من صنف المهام. وبينما نقوم بإنشاء وإنجاز أصناف النماذج، سنتابع
شرح موضوع البرمجية كائنة التوجه object-oriented
programming مع Swift .
صنف المهام
سنبدأ أولاً بإنجاز صنف المهام وذلك بإنشاء ملف سويفت جديد
من خلال New > File ثم إختيار ملف سويفت Swift File من خلال iOS
> Source قم
بتسمية الملف الجديد Task.swift ثم اضغط على Create .
إنشاء Swift استخدام Initialization و Initializer |
import
Foundation
class
Task: NSObject {
var
name: String
convenience override init() {
self.init(name: "New Task")
}
init(name: String) {
self.name = name
}
}
ولأن
الطريقة init أيضاً تم تعريفها من خلال الصنف
NSObject
، سنحتاج إلى البادئة
initialize مع الكلمة الدلالية وقد قمنا بشرح هذه الأمور في دروس سابقة.
باستخدام الطريقة init سنقوم باستخدام الطريقةinit (name:)
وتمرير "مهمة جديدة" كقيمة لاسم المعاملة.
تعتبر
الطريقة
init (name:)
نوع آخر من
initialize كما أنها توافق على اسم معاملة واحد في النوع String .
ستكون
قيمة اسم المعاملة في
initialize محددة من خلال اسم الخاصية وهذا كافي للفهم صحيح؟
التعيين
والملائمة للعنصر Initializers
ما هي
البادئة الملائمة في طريقة
init
؟ يوجد نوعان من الأصناف في
initializers وهي التعيين والملائمة. لكن لماذا نستخدم ذلك؟ وما هو الإختلاف بين
هذين النوعين من الأصناف؟
تعيين initializers: بداية
الصنف بشكل تام وذلك يعني بأن كل خاصية لديها قيمة أولية وإذا نظرنا إلى صنف
المهمة على سبيل المثال سنشاهد بأن اسم الخاصية تم تعيينه كقيمة في
init (name:)
كما أن النتيجة بعد
التخصيص هي مهمة أولية بشكل تام.
ملائمة
initializers: وهي تعتمد على النوع السابق وتقوم بإنشاء صنف كامل أولي ولهذا
فإن init
في صنف المهام تزيل
init (name:)
.
البروتوكول
NSCoding
على
الرغم من أن تنفيذ طبقة المهمة ليست كاملة. وفي وقت لاحق في هذه المقالة، سوف نكتب مجموعة من الحالات todo
إلى القرص. هذا ممكن فقط إذا مثيلات الفئة تودو
يمكن ترميز وفك الشفرة.
لا تقلق على الرغم من أن هذه ليست علم الصواريخ. نحن بحاجة فقط لجعل طبقات العمل وتودو مطابقة للبروتوكولNSCoding هذا هو السبب يرث طبقة العمل وتشكل الطبقةNSObject منذ بروتوكولNSCoding لا يمكن تنفيذها من قبل الطبقات وراثة مباشرة أو بشكل غير مباشر منNSObject مثل الطبقة NSObject ، يتم تعريف بروتوكولNSCoding في إطار المؤسسة.
إعتماد بروتوكول شيء غطيناه بالفعل في هذه السلسلة، ولكن هناك عدد قليل منgotchas التي أريد أن أشير إليها. دعونا نبدأ نقول للمترجم أن طبقة العمل تتفق مع بروتوكول NSCoding
لا تقلق على الرغم من أن هذه ليست علم الصواريخ. نحن بحاجة فقط لجعل طبقات العمل وتودو مطابقة للبروتوكولNSCoding هذا هو السبب يرث طبقة العمل وتشكل الطبقةNSObject منذ بروتوكولNSCoding لا يمكن تنفيذها من قبل الطبقات وراثة مباشرة أو بشكل غير مباشر منNSObject مثل الطبقة NSObject ، يتم تعريف بروتوكولNSCoding في إطار المؤسسة.
إعتماد بروتوكول شيء غطيناه بالفعل في هذه السلسلة، ولكن هناك عدد قليل منgotchas التي أريد أن أشير إليها. دعونا نبدأ نقول للمترجم أن طبقة العمل تتفق مع بروتوكول NSCoding
class
Task: NSObject, NSCoding {
var
name: String
...
}
تالياً
سنحتاج إلى استخدام طريقتين لإعلان عن بروتوكول
NSCoding
و
init (coder:)
و
encodeWithCoder (_:)
import
Foundation
class
Task: NSObject, NSCoding {
var
name: String
@objc required init(coder aDecoder: NSCoder) {
name = aDecoder.decodeObjectForKey("name") as! String
}
@objc func encodeWithCoder(aCoder: NSCoder) {
aCoder.encodeObject(name, forKey: "name")
}
convenience override init() {
self.init(name: "New Task")
}
init(name: String) {
self.name = name
}
}
الصنف
ToDo
عند
الإستعداد لإنشاء المهام حان الوقت لإنجاز صنف
ToDo
وذلك بإنشاء ملف سويفت جديد ثم سنقوم بتسميته
ToDo.swift . يمكنك مشاهدة كيف يبدو الكود لهذا
الصنف. import
Foundation
class
ToDo: Task {
var
done: Bool
@objc required init(coder aDecoder: NSCoder) {
self.done = aDecoder.decodeObjectForKey("done") as! Bool
super.init(coder: aDecoder)
}
@objc override func encodeWithCoder(aCoder: NSCoder) {
aCoder.encodeObject(done, forKey: "done")
super.encodeWithCoder(aCoder)
}
init(name: String, done: Bool) {
self.done = done
super.init(name: name)
}
}
تقوم
ToDo
باستلام صنف المهام وتقوم على إعلان خاصية متغير من نوع
Bool
. وأيضاً الطريقتين المطلوبتين وهمت بروتوكول
NSCoding
المستخدم مع قائمة المهام وأيضاً تقوم على إنشاء
init (name:done:)
.
وكما في
لغة Objective-C تعيد الكلمات الدلالية إلى superclass . والمهمة المطلوبة في هذا المثال وقبل أن تقوم بإلغاء
init (name:)
في السوبر كلاس كما أن لكل خاصية يتم إعلانها من
خلال صنف
ToDo
كما أنه يحتاج إلى أن يكون مبدئي.
ونفس
الشيء ينطبق على الطريقة
init (coder:)
حيث نقوم أولاً بتحديد الطريقة المنتهية قبل إلغاء
init (coder:)
في السوبركلاس. أيضاً لاحظ بأننا قمنا بتخفيض وبالتفاف النص
الإجباري لـنتيجة
decodeObjectForKey(_:)
.
Initializers و Inheritance
عند التعامل مع Initializers و Inheritanceهناك عدة قوانين يجب تذكرها. تعتبر تلك القوانين سهلة جداً :
· يجب استدعاءInitializer من superclass . في صنف ToDo ، على سبيل المثال، طريقة init (coder:) تستدعي طريقة init (coder:) Superclass. وهذا ما يعرف أيضاً بـ: delegating up .
تعد قوانينconvenience Initializers أكثر تعقيداً بقليل. هنالك قاعدتان يجب تذكرهما:
· يحتاج convenience Initializers إلى استدعاء Initializer آخر من نفس الصنف المعرف بها. في task class ، مثلاً، تعتبر طريقة init إنها convenience initializer وينوب initialization
عن initializer آخر، init (name:) في
المثال. و هذا ما يعرف بـ: delegating across .
· على الرغم من أنه لا يجب على convenience
initializer أن ينوب عن initialization لـ: designated initializer ، إلا أنه يتوجب عليه أن يستدعي designated
initializer في مرحلة ما. يعتبر هذا
ضروري لبدأ النموذج الذي تتم معالجته بشكل كامل.
بعد الإنتهاء من
تطبيق الأصناف النموذجية، يحين الوقت لإعادة إنشاء أصناف ViewController و AddItemViewController . دعونا نبدأ بالصنف اللاحق.
2. إعادة إنشاء AddItemViewController
الخطوة 1: تحديث بروتوكول AddItemViewControllerDelegate
ترتبط
التغيرات الوحيدة التي تطرأ على صنف AddItemViewController بـبروتوكول AddItemViewControllerDelegate . في تصريح البروتوكول، يجب تغيير نوع didAddItem من String إلى ToDo ، الصنف النوذجي الذي أنجزناه مسبقاً.
protocol {AddItemViewControllerDelegatecontroller func (controller: (AddItemViewController, didAddItem: ToDo}
الخطوة 2: تحديث create Action
هذا يعني أنه يتوجب علينا أيضاً تحديث create Action الذي من خلاله نستدعي طريقة delegate . في التطبيق المحدث، نقوم بإبتكار نموذج ToDo ، ونقله إلى طريقة delegate .
3. إعادة إنشاء ViewController الخطوة 1: تحديث مواد Property
يتطلب صنف
ViewController عملاً أكثر. نحتاج أولاً إلى تغيير نوع مواد property إلى [ToDo]، نظام نماذج ToDo .
|
|
الخطوة 2: Table View Data Source Methods
و هذا
يعني أيضاً أنه علينا إعادة إنشاء بعض الطرق الأخرى، مثل طريقة cellForRowAtIndexPath (_:) الموضحة في الأسفل. بإعتبار نظام المواد يحتوي الآن على نماذج ToDo ، فإنه من الأسهل التحقق فيما إذا تم وضع إشارة على المادة التي أنجزت. نستخدم معالج Swift
الثلاثي المشروط لتحديث نوع table view cell's
accessory .
accessory .
|
عندما يحذف
المستخدم مادة ما، فإننا نحتاج فقط إلى تحديث مواد property من خلال إزالة نماذج ToDo المطابقة. هذا ما هو موضح بتطبيق بطريقة tableView (_:commitEditingStyle:forRowAtIndexPath:) الموضحة أسفلاً:
|
الخطوة 3: جدولة طرق Delegate
طريقة tableView (_:didSelectRowAtIndexPath تعالج موضوع تحديث حالة المادة عندما ينقر المستخدم
على صف ما. يعتبر تطبيق هذه الطريقة UITableViewDelegate أسهل بكثير ويعود هذا الفضل لصنف ToDo .
|
يتم تحديث نموذج ToDo وهذا التغيير موضح بـ: table view . من أجل حفظ الحالة، نقوم باستدعاء saveItems بدلاً من saveCheckedItems .
الخطوة 4: إضافة طرق مواد View Controller Delegate
لأننا
نقوم بتحديث بروتوكول
AddItemViewControllerDelegate، فإننا نحتاج أيضاً لتحديث تطبيق ViewController's التابع لهذا البرتوكول. ومع ذلك يعتبر التغيير
سهل جداً. نحتاج فقط إلى تحديث شارة الطريقة.
|
الخطو 5: حفظ المواد
pathForItems
بدلاً من
تخزين المواد في قاعدة بيانات المستخدم النموذجية، فإننا سنقوم بتخزينها بدليل
التطبيقات. قبل أن نقوم بتحديث طرق loadItems و saveItems ، فإننا سنقوم بتطبيق طريقة مساعدة تدعى pathForItems . تعد هذه الطريقة خاصة وترجع بطريق، موقع المواد في دليل
التطبيقات.
|
نقوم أولاً بإحضار الطريق لدليل التطبيقات من خلال استدعاء NSSearchPathForDirectoriesInDomains (_:_:_:) . لأن هذه الطريقة ترجع بنظام من الخيوط، فإننا نمسك المادة الأولى، و ننشرها بقوة، ثم نحولها إلى String . تتألف القيمة التي نعيدها من pathForItems من الطريق إلى دليل التطبيقات مرتبطة بخيط "المواد".
loadItems
تتغير
طريقة loadItems بعض الشيء. نقوم أولاً بتخزين نتيجة pathForItems بطريق ذات تسمية دائمة. ثم نقوم باستخراج المادة المتضمنة بسجلات ذلك
الطريق وتحويلها إلى نظام إختياري من نماذج ToDo . نقوم باستخدام الربط الإختياري للنشر الإختياري ونسبة إلى مواد ذات
تسمية دائمة. في جملة إذا نقوم بنسب القيمة المخزنة في المواد لمواد property .
|
saveItems
تعد طريقة
saveItems سهلة وقصيرة. نقوم بتخزين نتيجة pathForItems بطريق ذات تسمية دائمة ونستدعي archiveRootObject (_:toFile:) على NSKeyedArchiver ، مع تمرير مواد الطريق و property . نقوم بطباعة نتيجة العملية على لوحة المراقبة.
|
الخطوة 6: التنظيف
دعونا
ننهي مرحلة اللعب، حذف الكود. ابدأ بإزالة property checkedItems في الأعلى علماً بأننا لم نعد بحاجة لها. وكنتيجة لذلك، فإنه
يمكننا أيضاً إزالة طرق loadCheckedItems و saveCheckedItems ، وكذلك كل مرجع إلى هذه الطرق في صنف ViewController .
قم ببناء
وإدارة التطبيق لكي ترى فيما إذا كان كل شيء ما زال يعمل. يقوم نموذج البيانات بجعل
كود التطبيقات أسهل و أكثر ثقة.
أصبحت إدارة المواد في لائحتنا أسهل بكثير الآن وأقل عرضة للخطأ وذلك بفضل صنف ToDo .
الخاتمة
أصبحت إدارة المواد في لائحتنا أسهل بكثير الآن وأقل عرضة للخطأ وذلك بفضل صنف ToDo .
الخاتمة
في هذا
الدرس، قمنا بإعادة إنشاء نموذج البيانات التابع لتطبيقاتنا. لقد تعلمت
أكثر عن البرمجة و inheritance . يعد
Instance
initialization أساسياً في مفهوم
Swift لذا أحرص على فهم ما أخذته في هذا الدرس.
ليست هناك تعليقات: