مرحبا القارئ!
في مقال 
سابق ، تحدثت عن دورة 
VIP لهندسة 
Clean Swift . الآن سنتطرق إلى أحد أهم الموضوعات - 
نقل ونقل البيانات بين المشاهد.

نظرية
مكون 
جهاز التوجيه مسؤول عن منطق التنقل ونقل البيانات ، والذي يعد جزءًا من المشهد (اختياري بالطبع). تتم تهيئة في 
ViewController ، جنبا إلى جنب مع 
Interactor والمقدم .
يقوم جهاز التوجيه بتنفيذ بروتوكولين - 
RoutingLogic و 
DataPassing ، والذي 
سنملؤه بوظائفنا . يجب أن يحتوي 
RoutingLogic على الأساليب المسؤولة عن الانتقال إلى مشهد معين. 
DataPassing يحتوي على متغير 
dataStore ، والذي يشير إلى بروتوكول 
DataStore . 
تقوم Interactor Scenes بتنفيذ بروتوكول 
DataStore وتعمل مع المتغيرات المخزنة فيه. يحتوي 
جهاز التوجيه نفسه على ارتباط إلى 
ViewController من المشهد الخاص به.
باستخدام الرابط إلى 
ViewController ، ينتقل 
جهاز التوجيه بين المشاهد. للقيام بذلك ، يمكنك استخدام 
Segue أو إنشاء مشهد تريد إجراء عملية نقل برمجيًا إليه. الطريقة التي يتم استخدامها ليست مهمة ، والشيء الرئيسي بالنسبة لنا هو وجود رابط لمثيل فئة 
ViewController الذي 
نتحول إليه.
باستخدام الرابط إلى 
DataStore ، 
سننقل البيانات من 
Interactor لمشهد واحد إلى 
Interactor للمشهد الذي ننتقل إليه. وكما ذكرنا سابقًا ، فإن 
جهاز التوجيه هو 
الذي يحتاج إلى معرفة كيفية القيام بذلك.
ممارسة
على سبيل المثال ، سننقل النص من TextField إلى Label للمشهد الآخر. دعنا نفكر في طريقتين للانتقال بين المشاهد - وفقًا لـ 
Segue وبرمجيًا .
تحتوي فئة 
جهاز التوجيه على 3 مجموعات من الدلالات:
- طرق من تطبيق RoutingLogic (routeTo)
- الطرق المسؤولة عن التنقل (التنقل ، الانتقال دون Segue)
- طرق نقل البيانات (passDataTo ، إذا كان هناك بيانات لنقل)

إذا نجحنا في الانتقال عبر 
Segue ، على سبيل المثال ، عند النقر فوق زر ، فيجب أن 
نتجاوز في 
ViewController طريقة التحضير (لـ: المرسل :). سيتيح لك هذا الامتداد الاتصال بالطرق تلقائيًا من 
جهاز التوجيه باسم 
Segue .
إعداد Overriding (لـ: المرسل :) اختياري عند العمل مع Segue. يمكنك استبعادها من الكود واستدعاء performSegue (withIdentifier: sender :) في طريقة Router . هناك حاجة إلى إعداد فقط إذا كنت بحاجة إلى استخدام Segue جنبا إلى جنب مع نقل البيانات.|  | final class HomeViewController: UIViewController { | 
|  | // ... | 
|  |  | 
|  | override func prepare(for segue: UIStoryboardSegue, sender: Any?) { | 
|  | // Segue | 
|  | if let scene = segue.identifier { | 
|  |  | 
|  | // , Router | 
|  | // router?.routeToNAME(segue:) | 
|  | let selector = NSSelectorFromString("routeTo\(scene)WithSegue:") | 
|  |  | 
|  | // , | 
|  | // Segue | 
|  | if let router = router, router.responds(to: selector) { | 
|  | router.perform(selector, with: segue) | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | // ... | 
|  | } | 
الآن نأتي في النهاية إلى الشيء الأكثر إثارة للاهتمام - رمز 
جهاز التوجيه . يحتوي المثال على تعليقات ، لذلك سننظر فقط في النقاط الرئيسية.
في هذا 
الموجه ، نعمل مع مشهدين - 
الصفحة الرئيسية والتفاصيل . تتم معالجة الانتقال من المشهد الرئيسي بطريقتين - بواسطة 
Segue وبرمجيًا . يتم نقل البيانات من المشهد الرئيسي إلى مشهد 
التفاصيل .
يجب تسمية جميع الطرق في بروتوكول 
RoutingLogic وفقًا لمبدأ 
routeToNAME ، حيث 
NAME هو اسم 
Segue (المعرّف) الذي 
نحدده عند العمل مع 
Storyboard . يعد هذا ضروريًا ليس فقط من أجل راحة وجمال الاستخدام ، ولكن أيضًا من أجل محدد الأسلوب الخاص بنا في 
الإعداد (لـ: المرسل :) ViewController ، والذي قمنا بإعادة تعريفه مسبقًا.
أيضا في فئة 
HomeRouter هناك طرق تبدأ من 
navigateTo و 
passDataTo . الأولى مسؤولة عن منطق الانتقال ، في حين أن الأخيرة مسؤولة عن نقل البيانات. يتم إنشاء أساليب navigateTo فقط إذا تم الانتقال برمجيًا.
في المثال ، لدينا 
routeToDetail ( طريقة 
:) :) . المعلمة 
segue اختيارية منذ تحتوي الطريقة على تطبيق يتيح لك الاتصال به دون استخدام 
Segue . في كلتا الحالتين الانتقالية ، نحصل على قيم غير اختيارية 
لمشهد HomeViewController و 
HomeDataStore'a Home ، بالإضافة إلى روابط إلى 
ViewController ومشهد DataStore Detail . هنا يجدر الانتباه إلى حقيقة أن 
detailDS متغير ويتم تمريره إلى طريقة 
passDataToDetail باستخدام المعلمة 
pass-through (inout). هذا مهم لأنه بدون 
inout ، سيكون علينا وضع علامة على جميع بروتوكولات 
DataStore على أنها "ممكنة للتنفيذ فقط مع الفئات" (البروتوكول DetailDataStore: class) ، وهذا يستلزم العديد من الصعوبات ، بما في ذلك التقاط روابط قوية.
|  |  | 
|  | import UIKit | 
|  |  | 
|  | /// @objc | 
|  | /// prepare View Controller'e | 
|  | @objc protocol HomeRoutingLogic { | 
|  | /// Detail View Controller | 
|  | func routeToDetail(segue: UIStoryboardSegue?) | 
|  | } | 
|  |  | 
|  | protocol HomeDataPassing { | 
|  | var dataStore: HomeDataStore? { get } | 
|  | } | 
|  |  | 
|  | final class HomeRouter: NSObject, HomeRoutingLogic, HomeDataPassing { | 
|  |  | 
|  | // MARK: - Private | 
|  |  | 
|  | // MARK: - Public | 
|  |  | 
|  | weak var viewController: HomeViewController? | 
|  | var dataStore: HomeDataStore? | 
|  |  | 
|  | // MARK: - HomeRoutingLogic | 
|  |  | 
|  | func routeToDetail(segue: UIStoryboardSegue?) { | 
|  | if let segue = segue { | 
|  | // | 
|  | // Segue | 
|  |  | 
|  | // Detail View Controller | 
|  | // Data Store Router'e | 
|  | guard | 
|  | let homeDS = dataStore, | 
|  | let detailVC = segue.destination as? DetailViewController, | 
|  | var detailDS = detailVC.router?.dataStore | 
|  | else { fatalError("Fail route to detail") } | 
|  |  | 
|  | // , , , | 
|  | // "" | 
|  | passDataToDetail(source: homeDS, destination: &detailDS) | 
|  | } else { | 
|  | // , | 
|  | // Segue | 
|  |  | 
|  | // Detail View Controller Storyboard'a | 
|  | // Data Store Router'e | 
|  | guard | 
|  | let viewController = viewController, | 
|  | let homeDS = dataStore, | 
|  | let storyboard = viewController.storyboard, | 
|  | let detailVC = storyboard.instantiateViewController(withIdentifier: "Detail") as? DetailViewController, | 
|  | var detailDS = detailVC.router?.dataStore | 
|  | else { fatalError("Fail route to detail") } | 
|  |  | 
|  | passDataToDetail(source: homeDS, destination: &detailDS) | 
|  |  | 
|  | // , "" | 
|  | navigateToDetail(source: viewController, destination: detailVC) | 
|  | } | 
|  | } | 
|  |  | 
|  | // MARK: - Navigation | 
|  |  | 
|  | private func navigateToDetail(source: HomeViewController, destination: DetailViewController) { | 
|  | source.navigationController?.pushViewController(destination, animated: true) | 
|  | } | 
|  |  | 
|  | // MARK: - Passing data | 
|  |  | 
|  | /// destination inout, | 
|  | /// Data Store | 
|  | private func passDataToDetail(source: HomeDataStore, destination: inout DetailDataStore) { | 
|  |  | 
|  | // HomeDataStore DetailDataStore | 
|  | destination.message = source.message | 
|  | } | 
|  | } | 
استنتاج
هذا كل شيء. شكرا لك على القراءة حتى النهاية! أدناه ، سأترك رابطًا للمشروع إذا كنت ترغب في تجربة المقالة قيد التنفيذ.
سلسلة من المقالات
- نظرة عامة على هندسة سويفت النظيفة
- تمرير البيانات والبيانات في بنية سويفت النظيفة (أنت هنا)
- عمال النظيفة سويفت الهندسة المعمارية
- اختبار وحدة في الهندسة النظيفة سويفت
- مثال على بنية متجر بسيط عبر الإنترنت Clean Swift
رابط للمشروعمساعدة في كتابة مقال: 
باستيان