بعد از مقاله اول که میتونید از اینجا بخونیدش (اگر مقاله قبلی رو هنوز نخوندید اول پیشنهاد میکنم که به طور کامل بخونیدش تا با پیاده سازی عادی و ساده TableView به روش Rx آشنا بشید و بعد شروع به خوندن این مقاله کنید)، توی این مقاله میخوام کمی بیشتر در مورد نحوه پیاده سازی حالتهای مختلف UITableView توسط RxSwift براتون توضیح بدم، مثل اینکه اگر چند نوع cell متفاوت داشتیم چی؟ و یا اینکه اصلا چند تا section داشتیم، این جور وقتها باید چی کار کنیم؟ چون توی روش قبل مییومدیم آرایه DataSource امون رو به tableView مون bind میکردیم و اونجا هم items رو به کلاس cell مورد نظرمون! و جایی برای تعیین section های مختلف و یا هندل کردن سطرهای متفاوت نبودش! خوب اینجا همون جایی هستش که مفهومی به نام RxDataSource به کمکمون میادش، اما RxDataSource چی هستش؟
به طور کلی از لایبرری RxDataSource برای section بندی tableview انیمیشن های موقع update شدن tableview، حذف سطرهای tableView و ... استفاده میشه، حتی زمانهایی که میخوایید tableView تون multi cell هم باشه این RxDataSource هستش که به کمکمون میادش! خوب حالا چه طوری میشه از این RxDataSource استفاده کردش؟ اول باید اون رو به پروژه مون اضافه کنیم که این کار رو میتونیم از طریق pod انجام بدیم کافی هستش که pod 'RxDataSources' رو به فایل pod مون اضافه کنیم و pod رو install کنیم.
برای اینکه دوباره نخواییم همه چیز رو از اول بنویسیم از همون پروژه قبلی استفاده میکنیم و تکمیلش میکنیم و تغییرش میدیم جاهاییش رو که نیاز هست.
اول از همه باید RxDataSources رو توی لایه viewModel مون اضافه کنیم، حالا باید یه typealias تعریف کنیم از نوع structure ای به نام SectionModel که از structure ها داخلی خود RxDataSource هستش، که اونم خودش به SectionModelType کانفرم (confirm) شده که نوع section هامون رو معلوم میکنه، البته راه های دیگهای هم هست اما به شخصه فکر میکنم این طوری کدها تمیزتر و خواناتر هستن تا حالتای دیگه (در اصل همه شون یکی هستن)، پس داریم:
همون طوری که میبینید SectionModel مون از دو تا enum تشکیل شده یکی TableViewSection و اون یکی tableViewItem، متاسفانه یا خوشبختانه به روش Rx ما فقط میتونیم یه text ساده رو برای هدر سکشنهامون set کنیم و اگر بخواییم یه custom view براش تعیین کنیم باید از همون delegate های قدیمی خود tableView استفاده کنیم یعنی:
tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView?
ولی در collectionView این طوری نیست و توسط rx میشه برای header و footer هم custom view تعیین کردش؛ برای همین توی enum ای که برای section ها هستش فقط یه case تعریف کردیم از نوع string یا اگر هر section مون یه مدل خاصی از data رو نشون میده میتونیم به ازای هر مدلش یه case تعریف کنیم، اینش بستگی به سلیقه خودمون داره.
تو مدل سمت چپ متن عنوان رو میتونیم موقع تعریف کردن وارد کنیم که هرچی دادیم به عنوان title داخل section هم همون رو قرار بدیم یا اینکه بیایم type سکشن tableView رو مثل مدل سمت راست تعریف کنیم و بعد خودمون هندل کنیم متنی رو که داخل section نمایش میدیم.
بعد از تعریف TableViewSection نوبت به تعریف TableViewItem هستش که در واقع نوع cell هایی هستش که قرار هستش داخل tableView نمایش بدیم، که هم میتونیم یه مدل داخل enum case مون قرار بدیم و یا اینکه همون جا تعریف کنیم مدل case چه جوری میتونه باشه.
حالا تنها کاری که توی لایه viewModel مون مونده این هستش که ارایه datasource که باری tableView مون هستش رو بسازیم و به view پاسش بدیم!
اگر مقاله قبلی رو هنوز یادتون باشه پر کردن ارایه tableSections که حکم dataSource مون رو داره و tableView مون رو بهش bind کردیم رو میدونید دیگه:
اومدیم TableViewItem هایی که لازم داشتیم رو ساختیم و بعدش داخل TableViewSectionModel ستشون کردیم و بعد این کار رو به تعداد section های مورد نیازمون تکرار کردیم و در اخری onNext متغییر tableSections مون رو call کردیم تا tableView مون که بهش bind شده خودش رو آپدیت کنه
حالا تنها کاری که باید بکنیم این هستش که dataSource ای رو که توی لایه viewModel ساختیم رو اینور مدیریت کنیم، پس اول از همه میایم یه متغییر به اسم dataSource از جنس RxTableViewSectionedReloadDataSource تعریف میکنیم :
حالا باید بیایم دو تا متغییر configureCell و titleForHeaderInSection رو که توی عکس سوم برای dataSource تعریف کردیم رو پیاده سازی کنیم، هر دوی این متغییرها رو از نوع lazy تعریف کردیم تا اپمون پرفورمنس و مدیریت حافظه بهتری داشته باشه!
۱- متغییر configureCell:
این متغییر کارش handle کردن تایپ های مختلف cell هامون هستش، که تشخصی بده cell الانی از کدوم تایپ هست و بسازتش.
خوب خط اولش که معلومه چی هست، برای جلوگیری از retainCycle این کار رو انجام دادیم و یه switch گذاشتیم که انواع enum های TableViewItem رو که توی viewModel مون تعریف کردیم رو تشخیص بدیم و هر نوعی رو بر اساس cell خودش یه تابع نوشتیم که config اش کنه و اطلاعاتش رو ست کنه، برای تفکیک پذیری بهتر و تمیزتر شدن کدها توابع رو توی یه extention داخل همین viewController نوشتیم.
۲- متغیر titleForHeaderInSection:
این متغییر هم کارش مدیریت و هندل کردن تایپهای مختلف section های tableView مون هستش که داخلش یه switch گذاشتیم تا انواع case های متغییر TableViewSection رو که توی viewModel مون تعریف کردیم رو تشخیص بده و عنوانش رو ازش بگیره، عکس دوممون اینجا به درد میخوره الان فکنم بهتر بتونید تشخیص بدید کدوم یکی حالت مناسبتر کارتون هست.
حالا کافی هستش تا یه تابع به اسم setupBinding تعریف کنیم و tableView مون رو به datasource ای که ساختیم بایند کنیم تا وقتی تابع setDataSource در viewModel فراخوانی شد به صورت خودکار tableView ما ساخته بشه!
بر خلاف مقاله قبلی که فقط یه نوع cell داشتیم و tableView مون رو به همون یه دونه bind کردیم، اینجا tableView مون رو به datasource مون بایند میکنیم تا اون تشخصی بده الان tableView کدوم نوع cell رو نمایش میده و اون رو config کنه برای کاربر.
نکته آخر: حتما یادتون هستش که باید انواع cell هاتون رو هم برای tableView مثل همیشه register کنید دیگه ? !
خوب سعی کردیم توی این مقاله و مقاله قبل انواع مختلف tableView رو به روش rx براتون توضیح بدم الان که به کدها نیگاه بکنید میبینید که چه تمیزتر و مرتب تر از حالتی که با delegate معمولی tableView رو پیاده سازی میکنیم این کار رو انجام دادیم و همه چیز تفکیک بیشتری داره و روی جریان دادههای اپ هم کنترل بیشتری داریم. این هستش لذت برنامه نویس با RxSwift !
سورس کدهای این مقاله رو هم میتونید از این آدرس گیت هاب دانلود کنید.
توی مقاله بعدی سعی میکنم که کمی ریز کاری های بیشتری از کار با tableView رو به روش RxSwift بگم و با چندتا از Operator های مرتبط هم آشناتون کنم، اینکه چه جوری میشه یه cell رو انتخاب کردش یا چه طور از willDisplayCell استفاده کردش و همین طور اگر مثلا یه SearchBar هم داشته باشه tableView مون چه طوری میتونیم لیست فیلتر شده رو نشون بدیم و بین لیست فیلتر شده و لیست اصلی tableView مون سویچ کنه.
مثل همیشه خوشحال میشم که اگر نظر یا پیشنهادی داشتید در مورد مقاله، نوع کد زدن و ... رو باهام در میون بذارید، تا با هم و در کنار هم بیشتر پیشرفت کنیم.?
ممنون از همراهیتون.