تطبيقات الهاتف المتحرك مع الجيل التلقائي النموذج: قضيتنا

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



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

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

من أجل حل أنيق للمشكلة ، استخدمنا آلية إنشاء الكائنات - ViewModels ، والتي تُستخدم لإنشاء نماذج مخصصة باستخدام الجداول.



في العمل العادي ، لكل جدول فردي يرغب المطور في رؤيته على الشاشة ، يجب إنشاء فئة ViewModel منفصلة. يحدد المكون المرئي للجدول. قررنا الانتقال بمستوى أعلى واحد وإنشاء ViewModels و Models أنفسنا بشكل حيوي ، وذلك باستخدام وصف بسيط للهيكل من خلال حقول التعداد.

كيف يعمل؟


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

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

  • فحص العرض: يجب إخفاء بعض الخلايا ،
  • قائمة الخلايا "الأصل": الخلايا التي تعتمد عليها قيمة أو التحقق من صحة أو عرض هذه الخلية ،
  • نوع الخلية: خلايا بسيطة ذات قيم ، وخلايا قيد التبديل ، وخلايا لها وظيفة إضافة عناصر ، إلخ.

نحن نشترك في جميع الأقسام في بروتوكول QuestionnaireSectionCellType العام من أجل استبعاد الربط إلى قسم معين ، وسنفعل الشيء نفسه مع جميع خلايا الجدول (QuestionnaireCellType).

protocol QuestionnaireSectionCellType { var title: String { get } var sectionCellTypes: [QuestionnaireCellType] { get } } protocol QuestionnaireCellType { var title: String { get } var initialValue: Any? { get } var isHidden: Bool { get } var parentFields: [QuestionnaireCellType] { get } … } 

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

في مثال شاشة حامل الوثيقة (التعداد مع الأقسام - InsurantSectionType):

 final class InsurantModel: BaseModel<QuestionnaireCellType> { override init() { super.init() initParameters() } private func initParameters() { InsurantSectionType.allCases.forEach { type in type.sectionCellTypes.forEach { if let valueModel = ValueModel(type: $0, parentFields: $0.parentFields, value: $0.initialValue) { valueModels.append(valueModel) } } } } } 

القيام به! الآن لدينا جدول مع القيم الأولية. أضف طرقًا لقراءة القيمة باستخدام مفتاح QuestionnaireCellType وحفظها في عنصر الصفيف المطلوب.

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

علاوة على ذلك ، للراحة ، جميع القيم في ValueModel التي نشترك بها في بروتوكول StringRepresentable للبروتوكول المشترك للحد من قائمة القيم الممكنة وإضافة طريقة لعرض القيمة في الخلية.

 protocol StringRepresentable { var stringValue: String? { get } } 

نمت الوظيفة ، وظهرت العديد من الخصائص والطرق الأخرى في النماذج: تنظيف النموذج (يجب تعيين القيم الأولية في بعض النماذج) ، ودعم مجموعة ديناميكية من القيم (القيمة: Array) ، إلخ.

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

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

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

اعتمادا على


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



لقد قمنا بتحديث قيم الاستبيان بمسح جميع الحقول التابعة (على سبيل المثال ، حذف أو تغيير نوع المستند ، نقوم بمسح الحقل "رقم المستند"):

 func updateValueModel(value: StringRepresentable?, for type: QuestionnaireCellType) { guard let model = valueModels.first(where: { $0.type.equal(to: type) }) else { return } model.value = value clearRelativeValues(type: type) } func clearRelativeValues(type: QuestionnaireCellType) { _ = valueModels.filter { $0.parentFields.contains(where: { $0.equal(to: type) }) } .compactMap { $0.type } .compactMap { updateValueModel(value: nil, for: $0) } } 

مطبات التي كان علينا حلها أثناء التطوير ، وكيف تمكنا


من الواضح أن هذه الطريقة ملائمة للشاشات التي لها نفس الوظيفة (ملء الحقول) ، ولكنها ليست مريحة إذا ظهرت عناصر أو وظائف فريدة على شاشة منفصلة واحدة ليست على شاشات أخرى. في طلبنا ، كانت هذه:

  • شاشة مع قوة المحرك ، والتي كان لابد من إنشاؤها بشكل منفصل ، وهذا هو السبب في أنها تختلف في وظائفها. في هذه الشاشة ، يجب أن يختفي الطلب ويتم استبدال القيمة من الخادم تلقائيًا. اضطررت لإنشاء فصل بشكل منفصل يكون مسؤولاً عن عرض الخادم والتحميل والتحقق منه والتحميل من الخادم واستبدال قيمة في حقل فارغ ، دون إزعاج المستخدم إذا قرر الأخير إدخال قيمته الخاصة.
  • شاشة رقم التسجيل ، والتي يكون فيها المفتاح الوحيد هو المفتاح الذي يؤثر على عرض أو إخفاء حقل النص. في هذه الحالة ، كان لا بد من عمل شرط إضافي ، والذي يحدد برمجياً الحالات التي يكون فيها موضع التبديل كقيمة فارغة.
  • القوائم الديناميكية ، مثل قائمة برامج التشغيل التي يجب تخزينها وربطها بنموذج ، والتي خرجت أيضًا عن المفهوم.
  • أنواع فريدة من التحقق من صحة البيانات. يمكن أن يكون الكثير من الأقنعة مختلطة مع regex'ami. والتحقق من صحة التاريخ لمختلف المجالات ، حيث اختلف التحقق بشكل كبير (قيود على الحد الأدنى / الحد الأقصى للقيم) ، إلخ.
  • تصنع شاشات إدخال البيانات كخلاياعرض المجموعة. (كان هذا مطلوبًا في التصميم!) وبسبب هذا ، يتطلب عرض الإطارات المشروطة تحكمًا دقيقًا في الفهرس المحدد. اضطررت إلى التحقق من الحقول المتاحة لملءها ، واستبعاد تلك القائمة التي لا يجب على المستخدم رؤيتها من القائمة.
  • لعرض البيانات في الجدول بشكل صحيح ، كان من الضروري إجراء تغييرات على أساليب نموذج بعض الشاشات. يتم عرض خلايا مثل الاسم والعنوان في الجدول كعنصر واحد ، ولكنها تتطلب ملء العديد من الشاشات المنبثقة بالكامل.

استنتاج


سمحت لنا هذه التجربة في شركة True Engineering بتنفيذ تطبيق محمول يسهل صيانته بسرعة. يتيح لك التنوع استخدام الجداول بسرعة مع أنواع مختلفة من بيانات الإدخال: لقد أنشأنا 20 نافذة في أسبوع واحد فقط. هذا النهج يسرع أيضا عملية اختبار التطبيق. في المستقبل القريب ، سنقوم بإعادة استخدام المصنع النهائي لإنشاء جداول جديدة ووظائف جديدة بسرعة.

Source: https://habr.com/ru/post/ar459430/


All Articles