iOS: كيفية إنشاء طريقة عرض جدول مع أنواع خلايا متعددة

الجزء 1. كيف لا تضيع في رمز السباغيتي

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

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

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

تخيل التطبيق ، حيث يتعين عليك إنشاء هذه الشاشة:

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

أولاً ، دعونا نحدد المشكلة.

هذا هو النهج الذي أراه كثيرًا في مشاريع مختلفة: تكوين الخلية استنادًا إلى فهرسها في UITableView.

تجاوز جدول func viewView (_ tableView: UITableView ، cellForRowAt indexPath: IndexPath) -> UITableViewCell {
   إذا indexPath.row == 0 {
        // تكوين نوع الخلية 1
   } آخر إذا indexPath.row == 1 {
        // تكوين نوع الخلية 2
   }
   ....
}

يتم استخدام نفس الرمز تقريبًا لطريقة المفوض didSelectRowAt:

تجاوز func tableView (_ tableView: UITableView ، didSelectRowAt indexPath: IndexPath) {
إذا indexPath.row == 0 {
        // تكوين الإجراء عند النقر فوق الخلية 1
   } آخر إذا indexPath.row == 1 {
        // تكوين الإجراء عند النقر فوق الخلية 1
   }
   ....
}

سوف يعمل هذا كما هو متوقع حتى اللحظة التي تريد فيها إعادة ترتيب الخلايا أو إزالة / إضافة خلايا جديدة إلى tableView. إذا قمت بتغيير فهرس واحد ، فسيتم كسر بنية عرض الجدول بالكامل وستحتاج إلى تحديث جميع الفهارس يدويًا في cellForRowAt وطرق didSelectRowAt.

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

ما هي الطريقة الأفضل؟

في هذا المشروع ، سوف نستخدم نمط MVVM. يرمز MVVM إلى "Model-View-ViewModel" ، وهذا النمط مفيد للغاية عندما تحتاج إلى طبقة إضافية بين النموذج والعرض الخاص بك. يمكنك قراءة المزيد حول جميع أنماط تصميم iOS الرئيسية هنا.

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

في البرنامج التعليمي التالي ، سنرتقي بمستوى واحد إلى مستوى أعلى: جعل القسم قابلًا للطي من خلال بضعة أسطر من التعليمات البرمجية.

الجزء 1: نموذج

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

ستبدو فئة ViewController كما يلي:

الطبقة ViewController: UIViewController {
   تضمين التغريدة ردًا علىIBOutlet
 
   تجاوز func viewDidLoad () {
      super.viewDidLoad ()
   }
}

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

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

نحتاج إلى إنشاء نموذج يحتفظ بجميع البيانات التي نقرأها من JSON.

ملف تعريف الفصل
   فار fullName: سلسلة؟
   فار pictureUrl: سلسلة؟
   فار البريد الإلكتروني: سلسلة؟
   فار حول: سلسلة؟
   فار الأصدقاء = [صديق] ()
   var profileAttributes = [Attribute] ()
}
صديق الصف
   اسم فار: سلسلة؟
   فار pictureUrl: سلسلة؟
}
سمة فئة {
   فار الرئيسية: سلسلة؟
   فار القيمة: سلسلة؟
}

سنضيف مُهيئًا باستخدام كائن JSON ، بحيث يمكنك بسهولة تعيين JSON إلى الطراز. أولاً ، نحتاج إلى طريقة لاستخراج المحتوى من ملف .json ، وتمثيله على أنه بيانات:

func dataFromFile (_ اسم الملف: سلسلة) -> البيانات؟ {
   objc class TestClass: NSObject {}
   اسمحوا حزمة = حزمة (من أجل: TestClass.self)
   إذا سمحت path = bundle.path (forResource: filename ، ofType: "json") {
      إرجاع (جرب؟ البيانات (contentOf: URL (fileURLWithPath: path)))
   }
   عودة لا شيء
}

باستخدام البيانات ، يمكننا تهيئة ملف التعريف. هناك العديد من الطرق المختلفة لتحليل JSON بشكل سريع باستخدام كل من متسلسلات الأطراف الأصلية أو الثالثة ، بحيث يمكنك استخدام الطريقة التي تريدها. سألتزم بـ Swift JSONSerialization القياسية للحفاظ على المشروع بسيطًا وليس تحميله بأية مكتبات خارجية:

ملف تعريف الفصل
   فار fullName: سلسلة؟
   فار pictureUrl: سلسلة؟
   فار البريد الإلكتروني: سلسلة؟
   فار حول: سلسلة؟
   فار الأصدقاء = [صديق] ()
   var profileAttributes = [Attribute] ()
   الحرف الأول (البيانات: البيانات) {
      فعل {
         إذا سمحت json = بتجربة JSONSerialization.jsonObject (مع: بيانات) كما؟ [سلسلة: أي] ، دع الجسم = json ["البيانات"] كما؟ [السلسلة: أي] {
            self.fullName = body ["fullName"] as؟ خيط
            self.pictureUrl = body ["pictureUrl"] as؟ خيط
            self.about = body ["about"] as؟ خيط
            self.email = body ["email"] as؟ خيط
            إذا ترك الأصدقاء = الجسم ["الأصدقاء"] كما؟ [[السلسلة: Any]] {
               self.friends = friends.map {Friend (json: $ 0)}
            }
            إذا سمحت profileAttributes = body ["profileAttributes"] كما؟ [[السلسلة: Any]] {
               self.profileAttributes = profileAttributes.map {Attribute (json: $ 0)}
            }
         }
      } قبض على {
         طباعة ("خطأ في إلغاء تسلسل JSON: \ (خطأ)")
         عودة لا شيء
      }
   }
}
صديق الصف
   اسم فار: سلسلة؟
   فار pictureUrl: سلسلة؟
   init (json: [String: Any]) {
      self.name = json ["name"] باسم؟ خيط
      self.pictureUrl = json ["pictureUrl"] كما؟ خيط
   }
}
سمة فئة {
   فار الرئيسية: سلسلة؟
   فار القيمة: سلسلة؟
  
   init (json: [String: Any]) {
      self.key = json ["key"] كما؟ خيط
      self.value = json ["value"] as؟ خيط
   }
}

الجزء 2: عرض النموذج

نموذجنا جاهز ، لذلك نحتاج إلى إنشاء ViewModel. ستكون مسؤولة عن توفير البيانات إلى TableView لدينا.

سنقوم بإنشاء 5 أقسام جدول مختلفة:

  • الاسم الكامل وصورة الملف الشخصي
  • حول
  • البريد الإلكتروني
  • سمات
  • اصحاب

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

نظرًا لأن بياناتنا ديناميكية ، فإن عدد الخلايا ليس ثابتًا ، ونحن نستخدم tableViewCells مختلفًا لكل نوع من البيانات ، نحتاج إلى الوصول إلى بنية ViewModel المناسبة.

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

التعداد ProfileViewModelItemType {
   اسم القضية و الصورة
   القضية حول
   حالة البريد الإلكتروني
   صديق القضية
   سمة القضية
}

تمثل كل حالة التعداد نوع البيانات التي تتطلب TableViewCell مختلفة. ولكن نظرًا لأننا نرغب في استخدام بياناتنا داخل نفس الجدول ، يجب أن يكون لديك DataModelItem واحد ، والذي سيحدد جميع الخصائص. يمكننا تحقيق ذلك باستخدام البروتوكول ، الذي سيوفر خصائص محسوبة لعناصرنا:

ProfileViewModelItem بروتوكول {

}

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

ProfileViewModelItem بروتوكول {
   var type: ProfileViewModelItemType {get}
}

الخاصية التالية التي نحتاجها هي rowCount. سيخبرك بعدد الصفوف التي سيحتويها كل قسم. قم بتوفير النوع و getter لهذه الخاصية:

ProfileViewModelItem بروتوكول {
   var type: ProfileViewModelItemType {get}
   var rowCount: Int {get}
}

آخر شيء جيد في هذا البروتوكول هو عنوان القسم. في الأساس ، عنوان القسم هو أيضا بيانات عن tableView. كما تتذكر ، باستخدام بنية MVVM لا نريد إنشاء البيانات أو أي نوع في أي مكان آخر ، ولكن في طريقة العرض:

ProfileViewModelItem بروتوكول {
   var type: ProfileViewModelItemType {get}
   var rowCount: Int {get}
   var sectionTitle: String {get}
}

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

ملحق ProfileViewModelItem {
   var rowCount: Int {
      عودة 1
   }
}

الآن لا يتعين علينا توفير عدد الصفوف لعناصرنا إذا كان عدد الصفوف واحدًا ، لذلك سيوفر لك بضعة أسطر إضافية من الشفرة الزائدة.

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

إنشاء أول ViewModeItem لخلية الاسم والصورة.

الفئة ProfileViewModelNameItem: ProfileViewModelItem {
   var type: ProfileViewModelItemType {
      إرجاع .nameAndPicture
   }
   var sectionTitle: String {
      إرجاع "المعلومات الرئيسية"
   }
}

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

نضيف الآن خصائص أخرى ، ستكون فريدة لهذا العنصر: pictureUrl و userName. كلاهما سيكونان الخصائص المخزنة بدون قيمة مبدئية ، لذلك نحتاج أيضًا إلى تقديم الحرف الأول لهذه الفئة:

الفئة ProfileViewModelNameAndPictureItem: ProfileViewModelItem {
   var type: ProfileViewModelItemType {
      إرجاع .nameAndPicture
   }
   var sectionTitle: String {
      إرجاع "المعلومات الرئيسية"
   }
   فار pictureUrl: سلسلة
   فار اسم المستخدم: سلسلة
   init (pictureUrl: String ، اسم المستخدم: String) {
      self.pictureUrl = pictureUrl
      self.userName = اسم المستخدم
   }
}

الآن يمكننا إنشاء عناصر النموذج الأربعة المتبقية:

ProfileViewModelAboutItem: ProfileViewModelItem {
   var type: ProfileViewModelItemType {
      العودة
   }
   var sectionTitle: String {
      إرجاع "حول"
   }
   فار حول: سلسلة
  
   الحرف الأول (حول: السلسلة) {
      self.about = about
   }
}
ProfileViewModelEmailItem: ProfileViewModelItem {
   var type: ProfileViewModelItemType {
      العودة
   }
   var sectionTitle: String {
      إرجاع "البريد الإلكتروني"
   }
   فار البريد الإلكتروني: سلسلة
   الحرف الأول (البريد الإلكتروني: السلسلة) {
      self.email = البريد الإلكتروني
   }
}
الفئة ProfileViewModelAttributeItem: ProfileViewModelItem {
   var type: ProfileViewModelItemType {
      العودة
   }
   var sectionTitle: String {
      إرجاع "السمات"
   }
 
   var rowCount: Int {
      العودة سمات
   }
   سمات var: [سمة]
   الحرف الأول (السمات: [السمة]) {
      self.attributes = سمات
   }
}
الفئة ProfileViewModeFriendsItem: ProfileViewModelItem {
   var type: ProfileViewModelItemType {
      عودة. صديق
   }
   var sectionTitle: String {
      عودة "الأصدقاء"
   }
   var rowCount: Int {
      عودة الأصدقاء
   }
   أصدقاء فار: [صديق]
   الحرف الأول (الأصدقاء: [صديق]) {
      self.friends = أصدقاء
   }
}

بالنسبة إلى ProfileViewModeAttributeItem و ProfileViewModeFriendsItem ، يمكن أن يكون لدينا خلايا متعددة ، بحيث يكون RowCount هو عدد السمات وعدد الأصدقاء بشكل متزامن.

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

الخاصية الوحيدة التي ستحصل عليها ViewModel هي مجموعة العناصر ، التي ستمثل صفيف المقاطع لـ UITableView:

ملف تعريف الفئة: نموذج NSObject {
   عناصر var = [ProfileViewModelItem] ()
}

لتهيئة ViewModel ، سنستخدم نموذج ملف التعريف. أولاً ، نحاول تحليل ملف .json إلى البيانات:

ملف تعريف الفئة: نموذج NSObject {
   عناصر var = [ProfileViewModelItem] ()
   
   over init (ملف التعريف: الملف الشخصي) {
      super.init ()
      حراسة السماح للبيانات = dataFromFile ("ServerData") ، واسمحوا الملف الشخصي = الملف الشخصي (البيانات: البيانات) آخر {
         إرجاع
      }
      // رمز التهيئة سوف يذهب هنا
   }
}

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

ملف تعريف الفئة: نموذج NSObject {
   عناصر var = [ProfileViewModelItem] ()
   تجاوز الحرف () {
      super.init ()
      حراسة السماح للبيانات = dataFromFile ("ServerData") ، واسمحوا الملف الشخصي = الملف الشخصي (البيانات: البيانات) آخر {
         إرجاع
      }
 
      إذا سمحت name = profile.fullName ، فدع pictureUrl = profile.pictureUrl {
         اسمحوا nameAndPictureItem = ProfileViewModelNamePictureItem (الاسم: الاسم ، pictureUrl: pictureUrl)
         items.append (nameAndPictureItem)
      }
      إذا سمح لها = profile.about {
         دع aboutItem = ProfileViewModelAboutItem (حول: حول)
         items.append (aboutItem)
      }
      إذا سمحت بالبريد الإلكتروني = profile.email {
         اسمحوا dobItem = ProfileViewModelEmailItem (البريد الإلكتروني: البريد الإلكتروني)
         items.append (dobItem)
      }
      دع السمات = profile.profileAttributes
      // نحتاج فقط إلى عنصر سمات إذا كانت السمات غير فارغة
      if! attributes.isEmpty {
         دع attributesItem = ProfileViewModeAttributeItem (السمات: سمات)
         items.append (attributesItem)
      }
      دع الأصدقاء = profile.friends
      / / نحن بحاجة فقط أصدقاء البند إذا أصدقاء ليس فارغا
      if! profile.friends.isEmpty {
         اسمحوا friendsItem = ProfileViewModeFriendsItem (الأصدقاء: الأصدقاء)
         items.append (friendsItem)
      }
   }
}

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

بعد ذلك ، سنضيف UITableViewDataSource إلى ModelView لدينا:

ملحق ViewModel: UITableViewDataSource {
   رقم funf مقاطع (في عرض الجدول: UITableView) -> Int {
      البنود العودة
   }
   جدول func عرض (_ جدول عرض: UITableView ، numberOfRowsInSection قسم: Int) -> Int {
      إرجاع العناصر [المقطع] .rowCount
   }
   جدول func عرض (_ tableView: UITableView ، cellForRowAt indexPath: IndexPath) -> UITableViewCell {
   / / سنقوم بتكوين الخلايا هنا
   }
}

الجزء 3: عرض

العودة إلى ViewController وتحضير TableView.

أولاً ، نقوم بإنشاء الخاصية المخزنة ProfileViewModel وتهيئتها. في مشروع حقيقي ، يجب عليك طلب البيانات أولاً ، وإطعام تلك البيانات إلى ViewModel ، ثم إعادة تحميل TableView على تحديث البيانات (تحقق من طرق تمرير البيانات في تطبيق iOS هنا).

بعد ذلك ، نقوم بتكوين الجدول ViewDataSource:

تجاوز func viewDidLoad () {
   super.viewDidLoad ()
   
   tableView؟ .dataSource = viewModel
}

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

NameAndPictureCell و FriendCell مثالEmailCell و AboutCell مثالمثال AttributeCell

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

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

/ / يفترض هذا أن لديك بالفعل جميع المقاطع الفرعية للخلية: التسميات ، و imagesViews ، إلخ
class NameAndPictureCell: UITableViewCell {
    فار البند: ProfileViewModelItem؟ {
      didSet {
         // يلقي ProfileViewModelItem إلى نوع العنصر المناسب
         الحرس اسمحوا البند = البند كما؟ ProfileViewModelNamePictureItem else {
            إرجاع
         }
         nameLabel؟ .text = item.name
         pictureImageView؟ .image = UIImage (اسمه: item.pictureUrl)
      }
   }
}
فئة AboutCell: UITableViewCell {
   فار البند: ProfileViewModelItem؟ {
      didSet {
         الحرس اسمحوا البند = البند كما؟ ProfileViewModelAboutItem else {
            إرجاع
         }
         aboutLabel؟ .text = item.about
      }
   }
}
الطبقة EmailCell: UITableViewCell {
    فار البند: ProfileViewModelItem؟ {
      didSet {
         الحرس اسمحوا البند = البند كما؟ ProfileViewModelEmailItem else {
            إرجاع
         }
         emailLabel؟ .text = item.email
      }
   }
}
class FriendCell: UITableViewCell {
    فار البند: صديق؟ {
      didSet {
         اسمح للحماية بترك العنصر = عنصر آخر {
            إرجاع
         }
         إذا سمحت pictureUrl = item.pictureUrl {
            pictureImageView؟ .image = UIImage (اسمه: pictureUrl)
         }
         nameLabel؟ .text = item.name
      }
   }
}
فار البند: السمة؟ {
   didSet {
      titleLabel؟ .text = item؟ .key
      valueLabel؟ .text = item؟ .value
   }
}

يمكن لبعضكم طرح سؤال معقول: لماذا لا نستخدم نفس الخلية لـ ProfileViewModelAboutItem و ProfileViewModelEmailItem ، نظرًا لأن كلاهما لديه تسمية نصية واحدة؟ الجواب نعم ، يمكننا استخدام نفس الخلية. لكن الغرض من هذا البرنامج التعليمي هو عرض طريقة استخدام أنواع مختلفة من الخلايا.

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

حان الوقت الآن لاستخدام الخلايا في TableView لدينا. مرة أخرى ، سيتعامل ViewModel مع هذا بطريقة بسيطة للغاية:

تجاوز جدول func viewView (_ tableView: UITableView ، cellForRowAt indexPath: IndexPath) -> UITableViewCell {
   دع العنصر = العناصر [indexPath.section]
   تبديل العنصر. النوع {
   case .nameAndPicture:
      إذا تركت cell = tableView.dequeueReusableCell (withIdentifier: NamePictureCell.identifier ، لـ: indexPath) as؟ NamePictureCell {
         cell.item = عنصر
         خلية العودة
      }
   القضية.
      إذا تركت cell = tableView.dequeueReusableCell (withIdentifier: AboutCell.identifier ، من أجل: indexPath) كـ؟ AboutCell {
         cell.item = عنصر
         خلية العودة
      }
   القضية.
      إذا تركت cell = tableView.dequeueReusableCell (withIdentifier: EmailCell.identifier، for: indexPath) as؟ EmailCell {
         cell.item = عنصر
         خلية العودة
      }
   القضية.
      إذا تركت cell = tableView.dequeueReusableCell (withIdentifier: FriendCell.identifier ، من أجل: indexPath) كـ؟ FriendCell {
         cell.item = أصدقاء [indexPath.row]
         خلية العودة
      }
   القضية.
      إذا تركت cell = tableView.dequeueReusableCell (withIdentifier: AttributeCell.identifier ، من أجل: indexPath) كـ؟ AttributeCell {
         cell.item = السمات [indexPath.row]
         خلية العودة
      }
   }
   / / إرجاع الخلية الافتراضية إذا لم ينجح أي من أعلاه
   إرجاع UITableViewCell ()
}
يمكنك استخدام نفس البنية لإعداد طريقة المفوض didSelectRowAt:
تجاوز func tableView (_ tableView: UITableView ، didSelectRowAt indexPath: IndexPath) {
      تبديل العناصر [indexPath.section] .type {
          / / القيام بالإجراء المناسب لكل نوع
      }
}

أخيرًا ، قم بتكوين headerView:

تجاوز func tableView (_ tableView: UITableView ، titleForHeaderInSection section: Int) -> String؟ {
   إرجاع العناصر [المقطع]
}

بناء وتشغيل مشروعك والتمتع عرض الجدول الديناميكي!

نتيجة الصورة

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

يمكنك التحقق من المشروع الكامل هنا:

شكرا للقراءة! إذا كان لديك أي أسئلة أو اقتراحات - لا تتردد في طرح!

في المقالة التالية ، سنقوم بترقية المشروع الحالي لإضافة تأثير طي / توسيع لطيف للأقسام.

تحديث: تحقق هنا لمعرفة كيفية تحديث هذا الجدول بطريقة ديناميكية دون استخدام أسلوب ReloadData.

أنا أكتب أيضًا لمدونة American Express Engineering. تحقق من أعمالي الأخرى وأعمال زملائي الموهوبين في AmericanExpress.io.