شبكة iOS المركزية وغير المنفصلة: برنامج تعليمي AFNetworking مع فصل فردي

نشرت: 2022-03-11

عندما يتعلق الأمر بأنماط معمارية iOS ، فإن نمط تصميم Model-View-Controller (MVC) يعد رائعًا لطول العمر وقابلية الصيانة لقاعدة كود التطبيق. يسمح بإعادة استخدام الفئات بسهولة أو استبدالها لدعم المتطلبات المختلفة عن طريق فصلها عن بعضها البعض. هذا يساعد على تعظيم مزايا البرمجة الشيئية (OOP).

بينما تعمل بنية تطبيق iOS هذه بشكل جيد على المستوى الجزئي (الشاشات / الأقسام الفردية للتطبيق) ، فقد تجد نفسك تضيف وظائف مماثلة لنماذج متعددة مع نمو تطبيقك. في حالات مثل الشبكات ، يمكن أن يكون نقل المنطق المشترك من فئات النموذج الخاصة بك إلى فئات المساعد الفردي نهجًا أفضل. في هذا البرنامج التعليمي AFNetworking iOS ، سوف أعلمك كيفية إعداد كائن شبكة مركزي فردي يمكن إعادة استخدامه ، منفصل عن مكونات MVC ذات المستوى الجزئي ، من خلال تطبيق العمارة المنفصلة.

دروس AFNetworking: الشبكات المركزية والمنفصلة مع Singleton

مشكلة شبكات iOS

قامت Apple بعمل رائع في تجريد العديد من تعقيدات إدارة أجهزة الهاتف المحمول في مجموعات SDK سهلة الاستخدام لنظام التشغيل iOS ، ولكن في بعض الحالات ، مثل الشبكات والبلوتوث و OpenGL ومعالجة الوسائط المتعددة ، يمكن أن تكون الفصول مرهقة بسبب هدفها في الاحتفاظ بها. SDKs مرنة. لحسن الحظ ، أنشأ مجتمع مطوري iOS الثري أطر عمل عالية المستوى لتبسيط حالات الاستخدام الأكثر شيوعًا في محاولة لتبسيط تصميم التطبيق وهيكله. يعرف المبرمج الجيد ، الذي يستخدم أفضل ممارسات هندسة تطبيقات iOS ، الأدوات التي يجب استخدامها ، ولماذا تستخدمها ، ومتى يكون من الأفضل كتابة الأدوات والفئات الخاصة بك من البداية.

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

مشكلة AFNetworking

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

  • طلبات شبكة متعددة باستخدام أساليب وخصائص متشابهة في وحدة تحكم عرض واحدة

  • طلبات متطابقة تقريبًا في وحدات تحكم عرض متعددة تؤدي إلى متغيرات مشتركة موزعة يمكن أن تخرج عن المزامنة

  • طلبات الشبكة في فصل دراسي لبيانات غير مرتبطة بهذه الفئة

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

  • إصدارات API لدعم أجيال متعددة من التطبيق

  • إضافة معلمات جديدة أو تغييرات على المعلمات الحالية بمرور الوقت لتوسيع القدرة

  • تنفيذ واجهات برمجة تطبيقات جديدة تمامًا

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

كيف نتعامل مع قيود AFNetworking؟

قم بإنشاء شبكة فردية لإضفاء الطابع المركزي على معالجة الطلبات والاستجابات ومعاييرها.

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

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

إليكم سبب استخدام مفردة للتواصل:

  • تتم تهيئته بشكل ثابت ، وبمجرد إنشائه ، سيكون له نفس الأساليب والخصائص المتاحة لأي فئة تحاول الوصول إليها. لا توجد فرصة لمشكلات المزامنة الفردية أو طلب البيانات من مثيل خاطئ للفصل الدراسي.

  • يمكنك تقييد مكالمات واجهة برمجة التطبيقات (API) الخاصة بك للبقاء أقل من حد السعر (على سبيل المثال ، عندما يتعين عليك الاحتفاظ بطلبات واجهة برمجة التطبيقات الخاصة بك أقل من خمسة في الثانية).

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

  • يمكن إعادة استخدام الخصائص المشتركة بين العديد من طلبات الشبكة.

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

  • يمكن فصل طلبات الشبكة تمامًا عن طرق العرض ووحدات التحكم حتى تتمكن من المتابعة حتى بعد تدمير طرق العرض ووحدات التحكم.

  • يمكن أن يكون تسجيل الشبكة مركزيًا ومبسطًا.

  • يمكن إعادة استخدام الأحداث الشائعة للفشل مثل التنبيهات لجميع الطلبات.

  • يمكن إعادة استخدام الهيكل الرئيسي لمثل هذا المفرد في مشاريع متعددة مع تغييرات بسيطة في الخصائص الثابتة من المستوى الأعلى.

بعض أسباب عدم استخدام المفردات:

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

  • لا يمكن تصنيف الأحرف المفردة.

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

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

  • يمكن أن تصبح تسربات الذاكرة في المفرد مشكلة مهمة لأن المفرد نفسه لا يتم إلغاء تخصيصه أبدًا.

ومع ذلك ، باستخدام أفضل ممارسات هندسة تطبيقات iOS ، يمكن التخفيف من هذه السلبيات. تتضمن بعض أفضل الممارسات ما يلي:

  • يجب على كل فرد التعامل مع مسؤولية واحدة.

  • لا تستخدم مفردات لتخزين البيانات التي سيتم تغييرها بسرعة بواسطة فئات أو سلاسل رسائل متعددة إذا كنت بحاجة إلى دقة عالية.

  • قم ببناء مفردات لتمكين / تعطيل الميزات بناءً على التبعيات المتاحة.

  • لا تقم بتخزين كميات كبيرة من البيانات في خصائص فردية لأنها ستستمر طوال عمر تطبيقك (ما لم تتم إدارتها يدويًا).

مثال منفرد بسيط مع AFNetworking

أولاً ، كشرط أساسي ، أضف AFNetworking إلى مشروعك. أبسط طريقة هي عبر Cocoapods والإرشادات موجودة في صفحة GitHub الخاصة بها.

أثناء تواجدك فيه ، أقترح إضافة UIAlertController+Blocks و MBProgressHUD (تمت إضافتها بسهولة مرة أخرى باستخدام CocoaPods). من الواضح أن هذه اختيارية ولكن هذا سيبسط التقدم والتنبيهات بشكل كبير إذا كنت ترغب في تنفيذها في المفرد في نافذة مندوب التطبيق.

بمجرد إضافة AFNetworking ، ابدأ بإنشاء فئة Cocoa Touch Class جديدة تسمى NetworkManager كفئة فرعية لـ NSObject . أضف طريقة الفصل للوصول إلى المدير. يجب أن يبدو ملف NetworkManager.h الخاص بك مثل الكود أدناه:

 #import <Foundation/Foundation.h> #import “AFNetworking.h” @interface NetworkManager : NSObject + (id)sharedManager; @end

بعد ذلك ، قم بتنفيذ طرق التهيئة الأساسية للمفرد واستورد رأس AFNetworking. يجب أن يبدو تنفيذ الفصل الدراسي الخاص بك كما يلي (ملاحظة: هذا يفترض أنك تستخدم حساب المرجع التلقائي):

 #import "NetworkManager.h" @interface NetworkManager() @end @implementation NetworkManager #pragma mark - #pragma mark Constructors static NetworkManager *sharedManager = nil; + (NetworkManager*)sharedManager { static dispatch_once_t once; dispatch_once(&once, ^ { sharedManager = [[NetworkManager alloc] init]; }); return sharedManager; } - (id)init { if ((self = [super init])) { } return self; } @end

رائعة! الآن نحن نطبخ ومستعدون لإضافة خصائص وطرق. كاختبار سريع لفهم كيفية الوصول إلى مفرد ، دعنا نضيف ما يلي إلى NetworkManager.h :

 @property NSString *appID; - (void)test;

وما يلي إلى NetworkManager.m :

 #define HOST @”http://www.apitesting.dev/” static const in port = 80; … @implementation NetworkManager … //Set an initial property to init: - (id)init { if ((self = [super init])) { self.appID = @”1”; } return self; } - (void)test { NSLog(@”Testing out the networking singleton for appID: %@, HOST: %@, and PORT: %d”, self.appID, HOST, port); }

ثم في ملف ViewController.m الرئيسي (أو أيًا كان لديك) ، قم باستيراد NetworkManager.h ثم في viewDidLoad أضف:

 [[NetworkManager sharedManager] test];

قم بتشغيل التطبيق وسترى ما يلي في الإخراج:

Testing our the networking singleton for appID: 1, HOST: http://www.apitesting.dev/, and PORT: 80

حسنًا ، لذلك من المحتمل ألا تخلط #define و static const و @property في وقت واحد مثل هذا ولكن ببساطة تظهر خياراتك من أجل الوضوح. يعتبر "static const" إعلانًا أفضل لسلامة النوع ، لكن #define يمكن أن يكون مفيدًا في بناء السلاسل لأنه يسمح باستخدام وحدات الماكرو. لما يستحق ، أنا أستخدم #define للإيجاز في هذا السيناريو. ما لم تكن تستخدم المؤشرات ، فلا يوجد فرق كبير في الممارسة بين مناهج التصريح هذه.

الآن بعد أن فهمت #defines والثوابت والخصائص والطرق ، يمكننا حذفها والانتقال إلى أمثلة أكثر صلة.

مثال على الشبكات

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

في AppDelegate.m ، دعنا نسجل افتراضيًا لرمزنا المميز:

 + (void)initialize { NSDictionary *defaults = [NSDictionary dictionaryWithObjectsAndKeys:@"", @"token", nil]; [[NSUserDefaults standardUserDefaults] registerDefaults:defaults]; }

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

مدير الشبكة

فوق @interface :

 typedef void (^NetworkManagerSuccess)(id responseObject); typedef void (^NetworkManagerFailure)(NSString *failureReason, NSInteger statusCode);

فيinterface:

property (nonatomic، strong) AFHTTPSessionManager * مدير الشبكات ؛

 - (void)tokenCheckWithSuccess:(NetworkManagerSuccess)success failure:(NetworkManagerFailure)failure;

مدير الشبكة. m:

حدد BASE_URL الخاص بنا:

 #define ENABLE_SSL 1 #define HOST @"http://www.apitesting.dev/" #define PROTOCOL (ENABLE_SSL ? @"https://" : @"http://") #define PORT @"80" #define BASE_URL [NSString stringWithFormat:@"%@%@:%@", PROTOCOL, HOST, PORT]

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

 - (AFHTTPSessionManager*)getNetworkingManagerWithToken:(NSString*)token { if (self.networkingManager == nil) { self.networkingManager = [[AFHTTPSessionManager alloc] initWithBaseURL:[NSURL URLWithString:BASE_URL]]; if (token != nil && [token length] > 0) { NSString *headerToken = [NSString stringWithFormat:@"%@ %@", @"JWT", token]; [self.networkingManager.requestSerializer setValue:headerToken forHTTPHeaderField:@"Authorization"]; // Example - [networkingManager.requestSerializer setValue:@"application/json" forHTTPHeaderField:@"Content-Type"]; } self.networkingManager.requestSerializer = [AFJSONRequestSerializer serializer]; self.networkingManager.responseSerializer.acceptableContentTypes = [self.networkingManager.responseSerializer.acceptableContentTypes setByAddingObjectsFromArray:@[@"text/html", @"application/json", @"text/json"]]; self.networkingManager.securityPolicy = [self getSecurityPolicy]; } return self.networkingManager; } - (id)getSecurityPolicy { return [AFSecurityPolicy defaultPolicy]; /* Example - AFSecurityPolicy *policy = [AFSecurityPolicy policyWithPinningMode:AFSSLPinningModeNone]; [policy setAllowInvalidCertificates:YES]; [policy setValidatesDomainName:NO]; return policy; */ } - (NSString*)getError:(NSError*)error { if (error != nil) { NSData *errorData = error.userInfo[AFNetworkingOperationFailingURLResponseDataErrorKey]; NSDictionary *responseObject = [NSJSONSerialization JSONObjectWithData: errorData options:kNilOptions error:nil]; if (responseObject != nil && [responseObject isKindOfClass:[NSDictionary class]] && [responseObject objectForKey:@"message"] != nil && [[responseObject objectForKey:@"message"] length] > 0) { return [responseObject objectForKey:@"message"]; } } return @"Server Error. Please try again later"; }

إذا قمت بإضافة MBProgressHUD ، فيمكن استخدامه هنا:

 #import "MBProgressHUD.h" @interface NetworkManager() @property (nonatomic, strong) MBProgressHUD *progressHUD; @end … - (void)showProgressHUD { [self hideProgressHUD]; self.progressHUD = [MBProgressHUD showHUDAddedTo:[[UIApplication sharedApplication] delegate].window animated:YES]; [self.progressHUD removeFromSuperViewOnHide]; self.progressHUD.bezelView.color = [UIColor colorWithWhite:0.0 alpha:1.0]; self.progressHUD.contentColor = [UIColor whiteColor]; } - (void)hideProgressHUD { if (self.progressHUD != nil) { [self.progressHUD hideAnimated:YES]; [self.progressHUD removeFromSuperview]; self.progressHUD = nil; } }

وطلب الشيكات الرمزية لدينا:

 - (void)tokenCheckWithSuccess:(NetworkManagerSuccess)success failure:(NetworkManagerFailure)failure { NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; NSString *token = [defaults objectForKey:@"token"]; if (token == nil || [token length] == 0) { if (failure != nil) { failure(@"Invalid Token", -1); } return; } [self showProgressHUD]; NSMutableDictionary *params = [NSMutableDictionary dictionary]; [[self getNetworkingManagerWithToken:token] GET:@"/checktoken" parameters:params progress:nil success:^(NSURLSessionTask *task, id responseObject) { [self hideProgressHUD]; if (success != nil) { success(responseObject); } } failure:^(NSURLSessionTask *operation, NSError *error) { [self hideProgressHUD]; NSString *errorMessage = [self getError:error]; if (failure != nil) { failure(errorMessage, ((NSHTTPURLResponse*)operation.response).statusCode); } }]; }

الآن ، في طريقة ViewController.m viewWillAppear ، سنسمي هذه الطريقة المفردة. لاحظ بساطة الطلب والتنفيذ الصغير من جانب View Controller.

 [[NetworkManager sharedManager] tokenCheckWithSuccess:^(id responseObject) { // Allow User Access and load content //[self loadContent]; } failure:^(NSString *failureReason, NSInteger statusCode) { // Logout user if logged in and deny access and show login view //[self showLoginView]; }];

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

وبالمثل ، يمكننا التعامل مع طلب POST لتسجيل الدخول: NetworkManager.h:

 - (void)authenticateWithEmail:(NSString*)email password:(NSString*)password success:(NetworkManagerSuccess)success failure:(NetworkManagerFailure)failure;

مدير الشبكة. m:

 - (void)authenticateWithEmail:(NSString*)email password:(NSString*)password success:(NetworkManagerSuccess)success failure:(NetworkManagerFailure)failure { if (email != nil && [email length] > 0 && password != nil && [password length] > 0) { [self showProgressHUD]; NSMutableDictionary *params = [NSMutableDictionary dictionary]; [params setObject:email forKey:@"email"]; [params setObject:password forKey:@"password"]; [[self getNetworkingManagerWithToken:nil] POST:@"/authenticate" parameters:params progress:nil success:^(NSURLSessionTask *task, id responseObject) { [self hideProgressHUD]; if (success != nil) { success(responseObject); } } failure:^(NSURLSessionTask *operation, NSError *error) { [self hideProgressHUD]; NSString *errorMessage = [self getError:error]; if (failure != nil) { failure(errorMessage, ((NSHTTPURLResponse*)operation.response).statusCode); } }]; } else { if (failure != nil) { failure(@"Email and Password Required", -1); } } }

يمكننا أن نكون خياليين هنا وإضافة تنبيهات باستخدام AlertController + Blocks في نافذة AppDelegate أو ببساطة إرسال كائنات الفشل مرة أخرى إلى وحدة التحكم في العرض. بالإضافة إلى ذلك ، يمكننا حفظ بيانات اعتماد المستخدم هنا أو بدلاً من ذلك السماح لوحدة التحكم في العرض بمعالجة ذلك. عادةً ما أقوم بتطبيق UserManager منفرد يتعامل مع بيانات الاعتماد والأذونات التي يمكنها التواصل مع NetworkManager مباشرةً (التفضيل الشخصي).

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

 - (void)loginUser { NSString *email = @"[email protected]"; NSString *password = @"SomeSillyEasyPassword555"; [[NetworkManager sharedManager] authenticateWithEmail:email password:password success:^(id responseObject) { // Save User Credentials and show content } failure:^(NSString *failureReason, NSInteger statusCode) { // Explain to user why authentication failed }]; }

وجه الفتاة! لقد نسينا إصدار API وإرسال نوع الجهاز. بالإضافة إلى ذلك ، قمنا بتحديث نقطة النهاية من "/ checktoken" إلى "/ token". نظرًا لأننا جعلنا شبكاتنا مركزية ، فمن السهل جدًا تحديث هذا الأمر. لا نحتاج إلى البحث في التعليمات البرمجية الخاصة بنا. نظرًا لأننا سنستخدم هذه المعلمات في جميع الطلبات ، فسننشئ مساعدًا.

 #define API_VERSION @"1.0" #define DEVICE_TYPE UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad ? @"tablet" : @"phone" - (NSMutableDictionary*)getBaseParams { NSMutableDictionary *baseParams = [NSMutableDictionary dictionary]; [baseParams setObject:@"version" forKey:API_VERSION]; [baseParams setObject:@"device_type" forKey:DEVICE_TYPE]; return baseParams; }

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

 … NSMutableDictionary *params = [self getBaseParams]; [[self getNetworkingManagerWithToken:token] GET:@"/checktoken" parameters:params progress:nil success:^(NSURLSessionTask *task, id responseObject) { … … NSMutableDictionary *params = [self getBaseParams]; [params setObject:email forKey:@"email"]; [params setObject:password forKey:@"password"]; [[self getNetworkingManagerWithToken:nil] POST:@"/authenticate" parameters:params progress:nil success:^(NSURLSessionTask *task, id responseObject) {

اختتام برنامج AFNetworking الخاص بنا

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

ركزنا في هذه المقالة على شبكة فردية فردية ولكن يمكن تطبيق نفس هذه المبادئ على العديد من الوظائف المركزية الأخرى مثل:

  • التعامل مع حالة المستخدم والأذونات
  • توجيه إجراءات اللمس للتنقل في التطبيق
  • إدارة الصوت والفيديو
  • تحليلات
  • إشعارات
  • ملحقات
  • والكثير الكثير…

ركزنا أيضًا على بنية تطبيق iOS ولكن يمكن أن يمتد هذا بسهولة إلى Android وحتى JavaScript. على سبيل المكافأة ، من خلال إنشاء رمز محدد للغاية وموجه للوظائف ، فإنه يجعل نقل التطبيقات إلى أنظمة أساسية جديدة مهمة أسرع بكثير.

باختصار ، من خلال قضاء بعض الوقت الإضافي في التخطيط المبكر للمشروع لإنشاء طرق فردية رئيسية ، مثل مثال الشبكات أعلاه ، يمكن أن تكون شفرتك المستقبلية أنظف وأبسط وأكثر قابلية للصيانة.