نظرة عامة على هندسة سويفت

مرحبا القارئ!

في هذه المقالة سأتحدث عن بنية تطبيقات iOS - Clean Swift . سننظر في النقاط النظرية الرئيسية ونحلل مثالاً في الممارسة.



نظرية


للبدء ، سنقوم بتحليل المصطلحات الأساسية للهندسة المعمارية. في Clean Swift ، يتكون التطبيق من مشاهد ، أي كل شاشة التطبيق هو مشهد واحد. التفاعل الرئيسي في المشهد يمر عبر حلقة متسلسلة بين مكونات ViewController -> Interactor -> مقدم العرض . وهذا ما يسمى دورة VIP .

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



رأي


عناصر Twitter أو XIBs أو UI المكتوبة من خلال التعليمات البرمجية.

ViewController


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

interactor ل


أنه يحتوي على منطق الأعمال للمشهد.

يعمل مع الشبكة وقاعدة البيانات والوحدات النمطية للجهاز.

يتلقى Interactor طلبًا من ViewController (مع بيانات أو فارغ) ، ويقوم بمعالجته ، وإذا لزم الأمر ، ينقل بيانات جديدة إلى مقدم العرض .

مقدم


وهو يشارك في إعداد البيانات للعرض.

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

نماذج


مجموعة من الهياكل لنقل البيانات بين مكونات دورة VIP . كل دائرة من الدائرة بها 3 أنواع من الهياكل:

  • طلب - بنية البيانات (النص من TextField ، وما إلى ذلك) للنقل من ViewController إلى Interactor
  • استجابة - بنية مع البيانات (التي تم تنزيلها من الشبكة ، وما إلى ذلك) للنقل من Interactor إلى مقدم العرض
  • ViewModel - هيكل مع البيانات التي تمت معالجتها (تنسيق النص ، وما إلى ذلك) في مقدم العرض للنقل مرة أخرى إلى ViewController

عامل


تفريغ Interactor ، مع الأخذ في جزء من منطق العمل للتطبيق إذا كان Interactor ينمو بسرعة.

يمكنك أيضًا إنشاء عمال مشتركين في جميع المشاهد ، إذا تم استخدام وظائفهم في عدة مشاهد.

كمثال ، في Worker ، يمكنك جعل منطق العمل مع شبكة أو قاعدة بيانات.

راوتر


يتم أخذ كل المنطق المسؤول عن التحولات ونقل البيانات بين المشاهد في جهاز التوجيه .



لتوضيح صورة دورة VIP ، سأقدم مثالًا قياسيًا - تفويض.

  1. أدخل المستخدم اسم المستخدم وكلمة المرور الخاصة به ، وانقر على زر التفويض
  2. يقوم ViewController بتشغيل IBAction ، وبعد ذلك يتم إنشاء هيكل ببيانات المستخدم التي تم إدخالها في TextFields (نماذج -> طلب)
  3. يتم تمرير البنية التي تم إنشاؤها إلى طريقة fetchUser في Interactor'e
  4. يقوم Interactor بإرسال طلب إلى الشبكة ويتلقى ردًا حول نجاح التفويض
  5. استنادًا إلى البيانات المستلمة ، ينشئ هيكلًا بالنتيجة (النماذج -> الاستجابة) ويتم تمريره إلى طريقة العرض الحالي في مقدم العرض
  6. يقوم مقدم العرض بتنسيق البيانات حسب الحاجة ويعيدها (الطرز -> ViewModel ) إلى طريقة عرض المستخدم في ViewController'e
  7. يعرض ViewController البيانات المستلمة للمستخدم. في حالة التفويض ، قد يتم عرض خطأ أو قد يتم تشغيل الانتقال إلى مشهد آخر باستخدام جهاز التوجيه

وبالتالي ، نحصل على بنية واحدة ومتسقة ، مع توزيع المسؤوليات إلى مكونات.

ممارسة


الآن دعونا نلقي نظرة على مثال عملي صغير يوضح كيف تسير دورة VIP . في هذا المثال ، سنحاكي تحميل البيانات عند فتح مشهد (شاشة). قمت بتمييز الأقسام الرئيسية من الكود بالتعليقات.

ترتبط دورة VIP بأكملها بالبروتوكولات ، والتي توفر القدرة على استبدال أي وحدات دون تعطيل التطبيق.
يتم إنشاء بروتوكول DisplayLogic لـ ViewController ، وهو رابط يتم تمريره إلى مقدم العرض للتذكير لاحقًا. بالنسبة لـ Interactor ، يتم إنشاء بروتوكولي BusinessLogic ، وهو مسؤول عن استدعاء أساليب من ViewController و DataSource ، لتخزين البيانات ونقل مشهد آخر عبر جهاز التوجيه إلى Interactor . يشترك مقدم العرض في بروتوكول PresentationLogic للاتصال من Interactor . العنصر الذي يربط بين كل هذا هو النماذج . أنه يحتوي على هياكل بمساعدة المعلومات التي يتم تبادلها بين مكونات دورة VIP . سنبدأ تحليل الشفرة به.



نماذج


في المثال أدناه ، بالنسبة للمشهد الرئيسي ، قمت بإنشاء ملف HomeModels يحتوي على مجموعة من الاستعلامات لحلقة VIP .
سيكون طلب FetchUser مسؤولاً عن تحميل بيانات المستخدم ، والتي سننظر فيها أكثر.

// Models
/// VIP
enum HomeModels {
/// VIP
enum FetchUser {
/// Interactor View Controller
struct Request {
let userName: String
}
/// Presentor Interactor
struct Response {
let userPhone: String
let userEmail: String
}
/// View Controller Presentor
struct ViewModel {
let userPhone: String
let userEmail: String
}
}
}

ViewController


عندما تتم تهيئة الفصل ، نقوم بتفعيل فئات Interactor و Presenter لهذا المشهد وننشئ التبعيات بينهما.
كذلك في ViewController'e هناك رابط إلى Interactor فقط . باستخدام هذا الرابط ، سنقوم بإنشاء طلب إلى fetchUser (request :) method في Interactor لبدء دورة VIP .

هنا يجدر الانتباه إلى كيفية حدوث طلب Interactor . في الأسلوب loadUserInfromation () ، نقوم بإنشاء مثيل لهيكل الطلب ، حيث نقوم بتمرير القيمة الأولية. يمكن أن تؤخذ من TextField ، الجداول ، وهلم جرا. يتم تمرير مثيل بنية الطلب إلى fetchUser (request :) method ، والذي هو في بروتوكول BusinessLogic الخاص بـ Interactor الخاص بنا.

// ViewController
///
protocol HomeDisplayLogic: class {
///
func displayUser(_ viewModel: HomeModels.FetchUser.ViewModel)
}
final class HomeViewController: UIViewController {
/// Interactor'a
var interactor: HomeBusinessLogic?
override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) {
super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
setup()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
setup()
}
///
private func setup() {
// VIP
let interactor = HomeInteractor()
let presenter = HomePresenter()
//
interactor.presenter = presenter
presenter.viewController = self
// Interactor View Controller
self.interactor = interactor
}
override func viewDidLoad() {
super.viewDidLoad()
//
fetchUser()
}
/// Interactor
private func loadUserInfromation() {
// Interactor
let request = HomeModels.FetchUser.Request(userName: "Aleksey")
// Interactor'a
interactor?.fetchUser(request)
}
}
/// HomeDisplayLogic
extension HomeViewController: HomeDisplayLogic {
func displayUser(_ viewModel: HomeModels.FetchUser.ViewModel) {
print(viewModel)
}
}

interactor ل


يحتوي مثيل فئة Interactor على ارتباط إلى بروتوكول PresentationLogic ، والذي يتم بموجبه توقيع مقدم العرض .

يمكن أن يحتوي الأسلوب fetchUser (request :) على أي منطق لتحميل البيانات. على سبيل المثال ، لقد قمت للتو بإنشاء ثوابت ، مع البيانات التي تم الحصول عليها بشكل مفترض.

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

// Interactor
/// Interactor'a
protocol HomeBusinessLogic: class {
///
func fetchUser(_ request: HomeModels.FetchUser.Request)
}
final class HomeInteractor: HomeBusinessLogic {
///
var presenter: HomePresentationLogic?
func fetchUser(_ request: HomeModels.FetchUser.Request) {
//
//
let userPhone = "+7 (999) 111-22-33"
let userEmail = "im@alekseypleshkov.ru"
// ...
// Presentor'
let response = HomeModels.FetchUser.Response(userPhone: userPhone, userEmail: userEmail)
// Presentor'
presenter?.presentUser(response)
}
}

مقدم


له رابط إلى بروتوكول DisplayLogic ، والذي بموجبه يتم توقيع ViewController . لا يحتوي على أي منطق أعمال ، ولكن فقط تنسيق البيانات المستلمة قبل عرضها. في المثال ، قمنا بتنسيق رقم الهاتف ، وقمنا بإعداد مثيل لهيكل ViewModel ، وقمنا بتمريره إلى ViewController باستخدام طريقة displayUser (viewModel :) في بروتوكول DisplayLogic ، حيث يتم بالفعل عرض البيانات.

///
protocol HomePresentationLogic: class {
/// Interactor'a
func presentUser(_ response: HomeModels.FetchUser.Response)
}
final class HomePresenter: HomePresentationLogic {
/// View Controller'a
weak var viewController: HomeDisplayLogic?
func presentUser(_ response: HomeModels.FetchUser.Response) {
//
let formattedPhone = response.userPhone.replacingOccurrences(of: "-", with: " ")
// ViewModel View Controller
let viewModel = HomeModels.FetchUser.ViewModel(userPhone: formattedPhone, userEmail: response.userEmail)
// View Controller'a
viewController?.displayUser(viewModel)
}
}

استنتاج


مع هذه البنية ، أتيحت لنا الفرصة لتوزيع المسؤوليات ، وتحسين راحة اختبار التطبيق ، وتقديم قابلية استبدال الأقسام الفردية للتطبيق ومعيار كتابة التعليمات البرمجية للعمل في فريق.

شكرا لك على القراءة حتى النهاية.

سلسلة من المقالات


  1. فهم الهندسة النظيفة سويفت (أنت هنا)
  2. توجيه البيانات ونقلها في النظيفة سويفت الهندسة المعمارية
  3. عمال النظيفة سويفت الهندسة المعمارية
  4. اختبار وحدة في الهندسة النظيفة سويفت
  5. مثال على بنية متجر بسيط عبر الإنترنت Clean Swift

جميع مكونات المشهد: رابط
مساعدة في كتابة مقال: باستيان

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


All Articles