لقد شاركت مؤخرًا في تطوير الواجهة الأمامية أكثر من الجوّال ، وشاهدت بعض أنماط التصميم المثيرة جدًا التي كنت أعرفها بالفعل ، لكنني لم أتطرق إليها حقًا ... حتى الآن.
ولكن الآن كل هذا منطقي ، بعد الاستخدام من التطوير في React لعدة أسابيع ، والآن لا يمكنني العودة إلى طرقي القديمة في تطوير iOS. لن أتحول إلى javascript (AKA React Native) لتطوير تطبيقات الهاتف المحمول ، ولكن فيما يلي بعض الأشياء التي تعلمتها.
بالعودة إلى تطوير iOS ، قمت بإنشاء مشروع جديد وبدأت في استكشاف
ReSwift ، وهذا تطبيق لنموذج
Flux و
Redux في Swift. وهو يعمل بكل بساطة ، لقد استنسخت بنية تطبيق JavaScript عدة مرات ، والآن لدي حالة عالمية ، وتستمع وحدات التحكم الخاصة بي إلى هذه الحالة. تتكون وحدات التحكم نفسها من مكونات العرض التقديمي المختلفة التي تغليف سلوك معين للغاية.

يتم إجراء جميع التغييرات
الحالة في مكان واحد ، في
المخفض . واحد للبديل. يمكنك رؤية جميع
الإجراءات في مكان واحد. لا مزيد من رمز الشبكة أو استدعاء وحدات التحكم ، لا مزيد من طفرات الكائنات في طرق العرض. لا مزيد من رمز السباغيتي. هناك
حالة واحدة فقط ، وهذا صحيح ، ثم مكونات العرض التقديمي المختلفة الخاصة بك (وأصر عليها) تشترك في أجزاء مختلفة من
الولاية وتتفاعل وفقًا لذلك. هذا هو ببساطة أفضل بنية لتطبيق نموذج قوي.
على سبيل المثال. سابقًا ، تمت تعبئة وحدات التحكم في طريقة عرض تسجيل الدخول بالكثير من أسطر التعليمات البرمجية وحالات التحكم المختلفة ومعالجة الأخطاء وما إلى ذلك ... الآن يبدو الأمر كما يلي: (كمثال)
import UIKit import Base import ReSwift class LoginViewController: UIViewController { @IBOutlet var usernameField: UITextField! @IBOutlet var passwordField: UITextField! override func viewDidLoad() { super.viewDidLoad() store.subscribe(self) {state in state.usersState } } @IBAction func onLoginButton(_ sender: Any) { store.dispatch(AuthenticatePassword(username: usernameField.text!, password: passwordField.text!)) } @IBAction func onTwitterButton(_ sender: Any) { store.dispatch(AuthenticateTwitter()) } @IBAction func onFacebookButton(_ sender: Any) { store.dispatch(AuthenticateFacebook(from: self)) } }
أدوات التحكم والتمثيل لإجراءات
الإرسال في الحالة العامة ، تعمل هذه الإجراءات في الواقع مع الشبكة أو تطلق الأجزاء المختلفة التي سيحتاج التطبيق إلى تحويلها إلى الحالة الجديدة.
يمكن أن يؤدي
إجراء ما إلى إجراء آخر ، وهذا هو كيف يحدث لطلب شبكة ، على سبيل المثال ، لديك إجراء
FetchUser (معرّف: سلسلة) وإجراء واحد تقوم باعتراضه في مخفض يشبه SetUser (مستخدم: مستخدم). في المخفض ، أنت مسؤول عن دمج / دمج كائن جديد مع حالتك الحالية.
تحتاج أولاً إلى
الحالة ، وسيركز المثال الخاص بي حول كائن
المستخدم ، لذلك قد تبدو
الحالة مثل هذا:
struct UsersState { var users: [String: User] = [:] }
يجب أن يكون لديك ملف يتضمن جميع أنشطة الشبكة لكائن المستخدم.
struct FetchUser: Action { init(user: String) { GETRequest(path: "users/\(user)").run { (response: APIResponse<UserJSON>) in store.dispatch(SetUser(user: response.object)) } } }
بمجرد اكتمال الطلب ، فإنه يستدعي
إجراءً آخر ، يكون هذا الإجراء فارغًا بالفعل ، يجب الرجوع إليه ، على سبيل المثال ، في UserActions. يصف هذا الإجراء النتيجة التي يجب أن يعتمد عليها المخفض لتغيير الحالة.
struct SetUser: Action { let user: UserJSON? }
وأخيرًا ، يتم العمل الأكثر أهمية في
UsersReducer ، فأنت بحاجة إلى التقاط الإجراء والقيام ببعض الأعمال وفقًا لمحتوياته:
func usersReducer(state: UsersState?, action: Action) -> UsersState { var state = state ?? initialUsersState() switch action { case let action as SetUser: if let user = action.user { state.users[user.id] = User(json: user) } default: break } return state }
الآن كل ما نحتاج إليه هو
suscribe / الاشتراك في الحالة في وحدات التحكم أو طرق العرض ، وعندما يتغير ، قم باستخراج المعلومات الضرورية والحصول على قيم جديدة!
class UserViewController: UIViewController { var userId: String? { didSet { if let id = userId { store.dispatch(FetchUser(user: id)) } } } var user: User? { didSet { if let user = user { setupViewUser(user: user) } } } override func viewDidLoad() { super.viewDidLoad() store.subscribe(self) {state in state.usersState } } func setupViewUser(user: User) {
لكن الآن يجب إلقاء نظرة على أمثلة
ReSwift لفهم أعمق ، أخطط لنشر تطبيق مفتوح المصدر (في الواقع لعبة) باستخدام نمط التصميم هذا. لكن في الوقت الحالي ، تعرض الشفرة فكرة غير واضحة حول كيفية عمل كل هذا معًا.
لا تزال هذه بنية مبكرة جدًا في كتب Glose ، لكن لا يمكننا انتظار وضع التطبيق قيد الإنتاج باستخدام هذه البنية.
أشعر أن تطوير التطبيقات باستخدام هذا النمط سيوفر الكثير من الوقت والجهد. سوف يستغرق العمل أكثر قليلاً من
عميل REST البسيط بغباء ، لأنه سيكون هناك منطق أكثر بقليل داخل حالة العميل ، ولكن في النهاية سيوفر لك وقتًا لا يقدر بثمن لتصحيح الأخطاء. ستتمكن من تعديل العديد من العناصر محليًا ، ولن يكون هناك تغييرات متتالية بين وحدات التحكم وطرق العرض. أعد إنتاج الحالة بترتيب النسخ الاحتياطي وأرشفتها وإنشاء البرامج الوسيطة وما إلى ذلك. دفق بيانات التطبيق واضح ومركزي وبسيط.
يضيف نموذج
Redux قليلاً من البنية إلى التطبيق. لقد كنت أقوم بعمل MVC منذ فترة طويلة جدًا ، وأنا متأكد من أنه يمكنك إنشاء قاعدة رمز نظيفة ، ولكنك تميل إلى تطوير عادات غالباً ما تضر أكثر مما تنفع. يمكنك حتى أن تخطو خطوة إلى الأمام وتنفذ تطبيق Redux بالكامل من خلال التحكم في واجهة المستخدم الخاصة بك (مثل وحدات تحكم العرض ومشاهدي التنبيه وأدوات التحكم في التوجيه) في حالة منفصلة ، لكنني لم أنجز كل هذا بعد.
والاختبارات ... أصبح من السهل الآن تنفيذ اختبار الوحدة ، لأن كل ما تحتاج إلى اختباره هو مقارنة البيانات التي تدخلها بالبيانات الموجودة في الحالة العامة ، بحيث يمكن للاختبارات إرسال إجراءات وهمية ، ثم التحقق مما إذا كانت الحالة تتطابق مع ما تقوم أنت باختباره تريد أن.
على محمل الجد ، هذا هو المستقبل. المستقبل ل
Redux :)