إعداد مشروع إنشاء تطبيق مناخي مع توقع الطقس |
في مارس من هذا العام، قامت شركتى Dark Sky و Forecast .io بتقديم التوقعات. والتوقع هو عبارة عن نظام مناخي بسيط يسمى API وهو برنامج يمكنه الكشف عن بيانات الطقس على كل من المدى البعيد والمدى القصير، وفي هذه السلسلة، سوف تظهر لك كيفية إنشاء تطبيق الطقس الرائع لدائرة الرقابة الداخلية مدعوم بالتوقعات.
مـقـــدمــــــــة
في وقت سابق من هذا العام، قدمت شركة Dark Sky التوقعات، وهو API بسيط يمكنه التنبؤ بالطقس على المدى البعيد والقصير. في هذه السلسلة سوف نقوم بإنشاء تطبيق دائرة الرقابة الداخلية مدعوم من قبل API Forecast ونقدم التوقعات مجاناً لعدد يصل إلى الآلاف ممن يقومون باستدعاء API يومياً، لذا لا تتردد في التسجيل للحصول على حساب مطور، تابع معي.
على الرغم من أن عدد الأغلفة مفتوحة المصدر لتوقعات API تتوفر في هذه السلسلة سوف نستخدم مكتبة AFNetworking Library للإستعلام عن توقعات API في الجزء الأول من هذه السلسلة، فإننا سنضع الأساس للمشروع وتنفيذ واجهة المستخدم الأساسية. على الرغم من أن طلبنا فى إطار بسيط، إلا أنه سيتم دعم مواقع متعددة، وهذا ما سنركز عليه في هذا المقال.
1. إعداد المشروع
الخطوة 1: إنشاء المشروع
قم بفتح برنامج X-Code وقم بإنشاء مشروع جديد "New Project" يعتمد على قالب "Empty Application" كما هو واضح فى (الشكل 1) ثم قم بتسمية المشروع بأسم Rain وقم بتمكين Automatic Reference Counting كما في (الشكل 2).
إعداد مشروع إنشاء تطبيق مناخي مع توقع الطقس |
إعداد مشروع إنشاء تطبيق مناخي مع توقع الطقس |
الخطوة 2: إضافة المكتبات "Libraries"
فى هذا المشروع، سوف نقوم باستخدام ثلاثة مكتبات مفتوحة المصدر (١) SVProgressHUD ويتم إنشاؤها بواسطة Sam Vermette
(2) AFNetworking ويتم إنشاؤها بواسطة Mattt Thompson
(3) ViewDeck ويتم إنشاؤها بواسطة Tom Adriaenssen
وبما أننى أحب بشراهة التعامل مع CocoaPods سوف أقوم باستخدامه من أجل تثبيت وإدارة المكتبات التى أخترناها أعلاه فى مشروعنا.
إذا لم تكن معتاداً على استخدام CocoaPods، فأنا أوصيك بزيارة الموقع الإلكتروني للـ: CocoaPods أو قراءة مقدمتي لـ: CocoaPods يمكنك أيضاً إضافة كل مكتبة لمشروعك يدوياً إذا كنت تفضل عدم استخدام CocoaPods.
أغلق مشروعك "Close your project" ثم انتقل إلى أصل المشروع، وأنشىء ملف اسمه Podfile افتح Podfile في محرر النصوص المفضل لديك واستبدل محتوياته بما هو ظاهر عندك أدناه.
في pod file الخاص بالمشروع، سوف نقوم بتحديد النظام الأساسي، وهدف الإنتشار، والجرابات "Pods" التى نريد إدراجها في المشروع.
platform :ios, '6.0' pod 'ViewDeck', '~> 2.2.11'pod 'AFNetworking', '~> 1.2.1'pod 'SVProgressHUD', '~> 0.9.0'
قم بفتح التطبيق Terminal، ثم انتقل إلى أصل المشروع، وقم بتثبيت المكتبات من خلال تنفيذ pod install بالإضافة إلى تثبيت الأغلفة الثلاثة التي حددناها فى ملف الغلاف الخاص بالمشروع. ولقد خلقت لنا CocoaPods بالفعل مساحة للعمل فى X-Code. قم بفتح مساحة العمل الجديدة قبل تنفيذ الأمرOpen Rain.xcworkspace من سطر الأوامر.
الخطوة 3: إضافة التبعيات
إعداد مشروع إنشاء تطبيق مناخي مع توقع الطقس |
قبل أن نتمكن من الإستمرار، نحن بحاجة لربط مشروعنا مع مجموعة من الهياكل أو
البنايات. وتعتمد مكتبة AFNetworking على Mobile Core Services و
System Configuration والمكتبة ViewDeck مما يحقق الإستفاة من الإطار
مساحة العمل Quartz Core حدد الم. حدد المشروع من Project Navigator ثم
اختر Rain target من قائمة الأهداف، افتح صفحة Build Phases فى الجزء
العلوي، ثم قم بتوسيع Link Binary With Libraries. اضغط فوق زر (+) كي
تستطيع ربط مشروعك مع إطارات العمل المذكورة آنفاً سنقوم باستخدام إطار Core
Location. فى وقت لاحق من هذا المقال، والآن هو الوقت المناسب لربط مشروعك
الخاص بهذا الإطار، كما فى ( الشكل 3 )
الخطوة 4: تحريرالملفات الرئيسية المترجمة سابقاً
قبل أن نبدأ تنفيذ البنية الأساسية لتطبيق الطقس لدينا، أنها فكرة جيدة لتعديل الملف
الرئيسي المترجم مسبقاً في مشروعناً. أضف عبارة المضمون لكل من الأطر التي
أضفناها إلى مشروعنا منذ لحظة وتقوم بفعل نفس الوظيفة بالنسبة للمكتبات
AFNetworking، SVProgressHUD، وViewDeck.
الرئيسي المترجم مسبقاً في مشروعناً. أضف عبارة المضمون لكل من الأطر التي
أضفناها إلى مشروعنا منذ لحظة وتقوم بفعل نفس الوظيفة بالنسبة للمكتبات
AFNetworking، SVProgressHUD، وViewDeck.
#import <Availability.h>
#ifndef __IPHONE_3_0
#warning "This project uses features only available in iOS SDK 3.0 and later."
#endif
#ifdef __OBJC__
#import <UIKit/UIKit.h>
#import <Foundation/Foundation.h>
#import <QuartzCore/QuartzCore.h>
#import <CoreLocation/CoreLocation.h>
#import <MobileCoreServices/MobileCoreServices.h>
#import <SystemConfiguration/SystemConfiguration.h>
#import "AFNetworking.h"
#import "SVProgressHUD.h"
#import "IIViewDeckController.h"
#endif
2. وضع الأساسيات
مفهوم وبنية التطبيق سهلة وبسيطة. حيث يدير التطبيق ثلاث وجهات:
(1) مشهد في المنتصف يبين الأحوال الجوية الحالية لموقع معين، ومشهد على اليمين
يبين الأحوال الجوية خلال الأيام القليلة المقبلة، ومشهد على اليسار مع قائمة من المواقع.
يبين الأحوال الجوية خلال الأيام القليلة المقبلة، ومشهد على اليسار مع قائمة من المواقع.
والبنية الأساسية سوف تقدم لنا إحساساً أفضل بالموضوع بمجرد أن نقوم بتنفيذه.
لإنشاء هذا الهيكل، علينا الإستفادة من ViewDeck library الرائع، حيث يتم إنشاؤه
وإدارته من قبل Tom Adriaenssen ، وتعتبر مكتبة ViewDeck واحدة من أقوى
أنماط تصميمات عروض الإنزلاق الأصلية والرائعة في الفيس بوك لدائرة الرقابة
الداخلية.
الخطوة 1: متحكمات العرض
قبل أن نضع مكتبة ViewDeck للإستخدام، نحن بحاجة إلى إنشاء طبقات متحكم
العروض التى تدير الثلاث مشاهد التى قد تم توضيحها أعلاه.
العروض التى تدير الثلاث مشاهد التى قد تم توضيحها أعلاه.
قم بإنشاء ثلاثة أقسام فرعية UIViewController تسمى
MTWeatherViewController ، MTForecastViewController ،
و MTLocationsViewController ، على الترتيب (الشكل 4). لا تنسى إنشاء
واجهة المستخدم أو ملف XIB لكل فئة (الشكل 4).
MTWeatherViewController ، MTForecastViewController ،
و MTLocationsViewController ، على الترتيب (الشكل 4). لا تنسى إنشاء
واجهة المستخدم أو ملف XIB لكل فئة (الشكل 4).
إعداد مشروع إنشاء تطبيق مناخي مع توقع الطقس |
الخطوة 2: إنشاء وحدة تحكم مشاهدة العرض
افتح MTAppDelegate.m ثم قم بإدخال الملفات الرئيسية الخاصه بالثلاث أقسام
الفرعية، أضف إمتداد الملحق ثم قم بإنشاء خاصية من النوع UIViewController.
وقم بتسميته viewDeckController والسبب في ذلك سوف يتضح في خلال لحظات.
الفرعية، أضف إمتداد الملحق ثم قم بإنشاء خاصية من النوع UIViewController.
وقم بتسميته viewDeckController والسبب في ذلك سوف يتضح في خلال لحظات.
#import "MTAppDelegate.h" #import "MTWeatherViewController.h"#import "MTForecastViewController.h"#import "MTLocationsViewController.h" @interface MTAppDelegate () @property (strong, nonatomic) IIViewDeckController *viewDeckController; @end
في application:didFinishLaunchingWithOptions:
نبدأ بإنشاء نموذج لكل واحدة من الطبقات الفرعية الثلاث لـ: UIViewController ثم
نقوم بالبدء في إنشاء نموذج من الطبقة IIViewDeckController ثم تمرير متحكم
العروض كبرهان لـ: initWithCenterViewController:leftViewController:rightViewContro
ller
نقوم بالبدء في إنشاء نموذج من الطبقة IIViewDeckController ثم تمرير متحكم
العروض كبرهان لـ: initWithCenterViewController:leftViewController:rightViewContro
ller
وكما يشير مؤشر البداية، فإن متحكم العروض الذى قمنا بإنشائه يتحكم فى مركز ويسار ويمين العرض.
أما عن بقية تنفيذ application:didFinishLaunchingWithOptions فمن
المؤكد أنه أصبح مألوفاً بالنسبة لك. حيث أننا نقوم بتحديد بداية نافذة التطبيقات ثم
ضبط متحكم العروض كالتالي:
قم ببناء ثم تشغيل التطبيق في برنامج المحاكاه الخاص بـ: ios
المؤكد أنه أصبح مألوفاً بالنسبة لك. حيث أننا نقوم بتحديد بداية نافذة التطبيقات ثم
ضبط متحكم العروض كالتالي:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { // Initialize View Controllers MTLocationsViewController *leftViewController = [[MTLocationsViewController alloc] initWithNibName:@"MTLocationsViewController" bundle:nil]; MTForecastViewController *rightViewController = [[MTForecastViewController alloc] initWithNibName:@"MTForecastViewController" bundle:nil]; MTWeatherViewController *centerViewController = [[MTWeatherViewController alloc] initWithNibName:@"MTWeatherViewController" bundle:nil]; // Initialize View Deck Controller self.viewDeckController = [[IIViewDeckController alloc] initWithCenterViewController:centerViewController leftViewController:leftViewController rightViewController:rightViewController]; // Initialize Window self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; // Configure Window [self.window setRootViewController:self.viewDeckController]; [self.window makeKeyAndVisible]; return YES;}
قم ببناء ثم تشغيل التطبيق في برنامج المحاكاه الخاص بـ: ios
أو على برنامج حسي فيزيائي كي ترى المكتبه ViewDeck وبالرغم من أن كل
المشاهدات والعروض فى متحكم العروض تكون فارغة تماماً فإن بناء التطبيق الأساسي
يكون جاهزاً.
المشاهدات والعروض فى متحكم العروض تكون فارغة تماماً فإن بناء التطبيق الأساسي
يكون جاهزاً.
3- إضافة الأماكن والمواضع
كما ذكرت فى المقدمة في هذه التذكرة التعليمية سوف نضيف كيفية إضافة المواضع إلى
قائمة المواضع التى يتم إدارتها عن طريق التطبيق ذاته.
قائمة المواضع التى يتم إدارتها عن طريق التطبيق ذاته.
حيث أن الطبقة MTLocationsViewController تكون بمثابة الشاحن الرئيسي
لإدارة قائمة المواضع وتقديمها فى جدول العروض.
لإدارة قائمة المواضع وتقديمها فى جدول العروض.
يستطيع المستخدم إضافة الموضع الحالي إلى قائمة المواضع عن طريق الانتقال إلى
الصف الأول من جدول العروض، الذى سوف يكون مسمى باسم "Add Current
Location".
الصف الأول من جدول العروض، الذى سوف يكون مسمى باسم "Add Current
Location".
إضافة موضع جديد إلى إطار عمل المواضع الأصلي هو مسؤولية الطبقة
MTWeatherViewController كما سوف نرى فى خلال بضع دقائق.
MTWeatherViewController كما سوف نرى فى خلال بضع دقائق.
ولكن هذا يتركنا مع مشكلة أخرى وهي: كيف سيتم العلم أو الإنذار عن المتحكم في
مشاهدة الطقس حينما يقوم المستخدم بالانتقال إلى الصف الأول من متحكم عرض
المواضع؟ مركز الملاحظات والإعلام؟
مشاهدة الطقس حينما يقوم المستخدم بالانتقال إلى الصف الأول من متحكم عرض
المواضع؟ مركز الملاحظات والإعلام؟
والتفويض هو الإختيار الأمثل فى هذا السياق.
كلما واجهت الحاجة إلى الاتصال في اتجاه واحد بين كائنين، فإنني أميل إلى إختيار
الوفد لصالح الإخطارات. حيث أن مندوب البروتوكولات أسهل بكثير كي تدير رأسك
عنه وإمتداده يكون بصورة بسيطة كإعلان عن طريقة أخرى.
الوفد لصالح الإخطارات. حيث أن مندوب البروتوكولات أسهل بكثير كي تدير رأسك
عنه وإمتداده يكون بصورة بسيطة كإعلان عن طريقة أخرى.
وثمة خيار آخر يتمثل في تمرير إشارة إلى وحدة تحكم عرض الطقس إلى متحكم
عرض المواقع، ولكن أنا لا أحب هذا النوع من ضيق الاقتران. فضيق الاقتران يجعل
الكود أقل قابلية لإعادة الاستخدام وأنه يؤدي إلى التسلسل الهرمي المعقد أكثر من اللازم
عندما يكبر قاعدة الكود مع مرور الوقت. والتفويض هو الخيار الصحيح لهذه المشكلة.
عرض المواقع، ولكن أنا لا أحب هذا النوع من ضيق الاقتران. فضيق الاقتران يجعل
الكود أقل قابلية لإعادة الاستخدام وأنه يؤدي إلى التسلسل الهرمي المعقد أكثر من اللازم
عندما يكبر قاعدة الكود مع مرور الوقت. والتفويض هو الخيار الصحيح لهذه المشكلة.
الخطوة 1: إعلان بروتوكول التفويض
افتح MTLocationsViewController.h وقم بتحديث ملف الهيدر كما هو مبين
أدناه. نحن بصدد إنشاء خاصية لمفوض متحكم العرض. ونقوم بإعلان بروتوكول
MTLocationsViewControllerDelegate ويحدد البروتوكول طريقتين، (1)
controllerShouldAddCurrentLocation ، الذي يتم استدعاؤه حينما يتم شغل
الصف الأول في جدول العروض الخاص بمتحكم العروض، (2)
controller:didSelectLocation ، الذي يتم استدعاؤه عند قيام المستخدم بتحديد
موقع من قائمة المواقع.
أدناه. نحن بصدد إنشاء خاصية لمفوض متحكم العرض. ونقوم بإعلان بروتوكول
MTLocationsViewControllerDelegate ويحدد البروتوكول طريقتين، (1)
controllerShouldAddCurrentLocation ، الذي يتم استدعاؤه حينما يتم شغل
الصف الأول في جدول العروض الخاص بمتحكم العروض، (2)
controller:didSelectLocation ، الذي يتم استدعاؤه عند قيام المستخدم بتحديد
موقع من قائمة المواقع.
#import <UIKit/UIKit.h> @protocol MTLocationsViewControllerDelegate; @interface MTLocationsViewController : UIViewController @property (weak, nonatomic) id<MTLocationsViewControllerDelegate> delegate; @end @protocol MTLocationsViewControllerDelegate <NSObject>- (void)controllerShouldAddCurrentLocation:(MTLocationsViewController *)controller;- (void)controller:(MTLocationsViewController *)controller didSelectLocation:(NSDictionary *)location;@end
الخطوة 2: إضافة جدول العرض
أعد زيارة MTLocationsViewController.h مرة أخرى. قم بإنشاء منفذ لعرض
جدول وحدة التحكم وتأكد من مطابقة الطبقة MTLocationsViewController إلى
كل من البروتوكولات UITableViewDataSource و UITableViewDelegate.
جدول وحدة التحكم وتأكد من مطابقة الطبقة MTLocationsViewController إلى
كل من البروتوكولات UITableViewDataSource و UITableViewDelegate.
#import <UIKit/UIKit.h> @protocol MTLocationsViewControllerDelegate; @interface MTLocationsViewController : UIViewController <UITableViewDataSource, UITableViewDelegate> @property (weak, nonatomic) id<MTLocationsViewControllerDelegate> delegate; @property (weak, nonatomic) IBOutlet UITableView *tableView; @end @protocol MTLocationsViewControllerDelegate <NSObject>- (void)controllerShouldAddCurrentLocation:(MTLocationsViewController *)controller;- (void)controller:(MTLocationsViewController *)controller didSelectLocation:(NSDictionary *)location;@end
قم بفتح MTLocationsViewController.xib ، قم بإضافة جدول عرض إلى
صفحة العروض الخاصة بالمتحكم، وتحديد dataSource الخاص بجدول العرض
والمنفذ delegate إلى File's Owner object حدد File's Owner object ثم
قم بتوصيل منفذ tableView الخاص به إلى جدول العرض الذى أضفناه سابقاً إلى
صفحة متحكم العروض (الشكل 5).
صفحة العروض الخاصة بالمتحكم، وتحديد dataSource الخاص بجدول العرض
والمنفذ delegate إلى File's Owner object حدد File's Owner object ثم
قم بتوصيل منفذ tableView الخاص به إلى جدول العرض الذى أضفناه سابقاً إلى
صفحة متحكم العروض (الشكل 5).
إعداد مشروع إنشاء تطبيق مناخي مع توقع الطقس |
الخطوة 3: ملء عرض الجدول
قبل أن تقوم بتنفيذ البروتوكولات UITableViewDataSource
و UITableViewDelegate ، نحن بحاجة إلى إنشاء خاصية من شأنها أن تكون
بمثابة مصدر بيانات جدول العرض.
و UITableViewDelegate ، نحن بحاجة إلى إنشاء خاصية من شأنها أن تكون
بمثابة مصدر بيانات جدول العرض.
قم بإنشاء ملحق فئوي أو إضافة فئوية في الجزء العلوي من
MTLocationsViewController.m ثم إنشاء خاصية تسمى لستينص من النوع
NSMutableArray فإنه سيتم تخزين المواقع التي تم إدارتها بواسطة التطبيق
الخاص بنا.
MTLocationsViewController.m ثم إنشاء خاصية تسمى لستينص من النوع
NSMutableArray فإنه سيتم تخزين المواقع التي تم إدارتها بواسطة التطبيق
الخاص بنا.
#import "MTLocationsViewController.h" @interface MTLocationsViewController () @property (strong, nonatomic) NSMutableArray *locations; @end
تنفيذ البروتوكولات UITableViewDataSource و UITableViewDelegate
غير واضحة إلى حد ما. فنحن نبدأ بإعلان سلسلة من الثوابت لمعرف إعادة استخدام
الخلية.
غير واضحة إلى حد ما. فنحن نبدأ بإعلان سلسلة من الثوابت لمعرف إعادة استخدام
الخلية.
في طريقة viewDidLoad الخاصة بوحدة تحكم العرض نحن نستدعي
setupView ، وهي طريقة مساعدة تساعدنا أثناء تكوين واجهة المستخدم الخاصة
بالمتحكم فى طريقة العرض.
setupView ، وهي طريقة مساعدة تساعدنا أثناء تكوين واجهة المستخدم الخاصة
بالمتحكم فى طريقة العرض.
في setupView ، نحن نخبر جدول العروض أن يقوم باستخدام فئة
UITableViewCell كي يقوم بإنشاء مثيل لجدول العرض الجديد الذى قمنا بتعريفه
في وقت سابق.
static NSString *LocationCell = @"LocationCell";- (void)viewDidLoad { [super viewDidLoad]; // Setup View [self setupView];} - (void)setupView { // Register Class for Cell Reuse [self.tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:LocationCell];}
تنفيذ بروتوكولات UITableViewDataSource و UITableViewDelegate هو
شيء تافه وبسيط كما ترون أدناه.
اثنين من تفاصيل تنفيذ تتطلب الشرح قليلاً.
نقوم بتخزين كل موضع على هيئة قاموس له أربعة مفاتيح أو أربعة مداخل، (1)
المدينة (2) القطر (3) خط العرض (4) خط الطول.
المدينة (2) القطر (3) خط العرض (4) خط الطول.
مع الوضع في الإعتبار أن تنفيذ configureCell:atIndexPath ينبغي أن يصبح
أكثر وضوحاً. لاحظ أن configureCell: atIndexPath ليس أكثر من طريقة
أخرى للمساعدة.
أكثر وضوحاً. لاحظ أن configureCell: atIndexPath ليس أكثر من طريقة
أخرى للمساعدة.
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { return 1;}- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { return ([self.locations count] + 1);}- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:LocationCell forIndexPath:indexPath]; // Configure Cell [self configureCell:cell atIndexPath:indexPath]; return cell;}- (void)configureCell:(UITableViewCell *)cell atIndexPath:(NSIndexPath *)indexPath { if (indexPath.row == 0) { [cell.textLabel setText:@"Add Current Location"]; } else { // Fetch Location NSDictionary *location = [self.locations objectAtIndex:(indexPath.row - 1)]; // Configure Cell [cell.textLabel setText:[NSString stringWithFormat:@"%@, %@", location[@"city"], location[@"country"]]]; }}- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath { return NO;}- (BOOL)tableView:(UITableView *)tableView canMoveRowAtIndexPath:(NSIndexPath *)indexPath { return NO; }
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { [tableView deselectRowAtIndexPath:indexPath animated:YES]; if (indexPath.row == 0) { // Notify Delegate [self.delegate controllerShouldAddCurrentLocation:self]; } else { // Fetch Location NSDictionary *location = [self.locations objectAtIndex:(indexPath.row - 1)]; // Notify Delegate [self.delegate controller:self didSelectLocation:location]; } // Show Center View Controller [self.viewDeckController closeLeftViewAnimated:YES];}
و tableView: didSelectRowAtIndexPath يتطلب أيضاً شرحاً موجزاً.
إذا كان المستخدم قد استغل الصف الأول، والمكتوب عليه Add Current Location
، يتم إعلام المندوب إلى أن الموقع الحالي ينبغي أن يضاف إلى قائمة المواقع. إذا تم
استغلال أي صف آخر في جدول العرض، يتم تمرير الموقع المناظر كما الوسيطة
الثانية من controller:didSelectLocation
، يتم إعلام المندوب إلى أن الموقع الحالي ينبغي أن يضاف إلى قائمة المواقع. إذا تم
استغلال أي صف آخر في جدول العرض، يتم تمرير الموقع المناظر كما الوسيطة
الثانية من controller:didSelectLocation
طريقة تفويض أخرى من بروتوكول المفوض MTLocationsViewController
حيث يقوم ذلك بتوجيه نظر المندوب أو المفوض إلى أن التطبيق يجب أن يقوم بتحديد
موقع جديد كموقع application't الافتراضي وبيانات الطقس لهذا الموقع يجب أن
تكون سهلة المنال.
السطر الأخير من tableView: didSelectRowAtIndexPath هو أيضاً جدير
بالذكر.
بالذكر.
على سبيل المثال IIViewDeckController يقوم بتحديد نفسه إلى متحكمات العرض
التي يديرها. توفر خاصية viewDeckController الوصول إلى وحدة تحكم العرض
، وهو مناسب إذا كنت بحاجة إلى الوصول إلى صفحة متحكم العروض.
التي يديرها. توفر خاصية viewDeckController الوصول إلى وحدة تحكم العرض
، وهو مناسب إذا كنت بحاجة إلى الوصول إلى صفحة متحكم العروض.
فهو يعمل بشكل يشبه كثيراً خاصية نافيجاتيونسونتروللير من نموذج متحكمات العرض
. في السطر الأخير من tableView: didSelectRowAtIndexPath قد أخبرنا
متحكم العرض المزخرف بإغلاق العرض الأيسر، وهو ما يعني أن المشهد أو العرض
الأوسط يصبح مرئياً مرة أخرى.
الخطوة 4: مفاتيح وثوابت
قبل أن نواصل ملء جدول عرض المواقع، نحن بحاجة إلى إيلاء الإهتمام لبعض أفضل
الممارسات. نحن نستخدم حالياً سلسلة حرفية للوصول إلى قيم قاموس الموقع. على
الرغم من أن هذا يعمل بشكل جيد تماماً، فمن الأفضل وأكثر أماناً استخدام ثوابت خيطية
لهذا الغرض. لجعل هذا كله بسيطاً وسهل الصيانة والتعديل، فإننا نعرف ثوابت خيطية
في الموقع الأوسط. اسمحوا لي أن أبين لكم كيف يعمل هذا.
الممارسات. نحن نستخدم حالياً سلسلة حرفية للوصول إلى قيم قاموس الموقع. على
الرغم من أن هذا يعمل بشكل جيد تماماً، فمن الأفضل وأكثر أماناً استخدام ثوابت خيطية
لهذا الغرض. لجعل هذا كله بسيطاً وسهل الصيانة والتعديل، فإننا نعرف ثوابت خيطية
في الموقع الأوسط. اسمحوا لي أن أبين لكم كيف يعمل هذا.
قم بإنشاء فئة فرعية من NSObject وقم بتسميتها MTConstants قم باستبدال
محتويات MTConstants.h و MTConstants.m كما هو مبين أدناه. يجب أن
يكون واضحاً لك أن MTConstants ليس فئة Objective-C أنها ليست أكثر من
مكاناً مركزياً لتخزين مجموعة من الثوابت المحددة لمشروعنا.
محتويات MTConstants.h و MTConstants.m كما هو مبين أدناه. يجب أن
يكون واضحاً لك أن MTConstants ليس فئة Objective-C أنها ليست أكثر من
مكاناً مركزياً لتخزين مجموعة من الثوابت المحددة لمشروعنا.
#pragma mark -#pragma mark User Defaultsextern NSString * const MTRainUserDefaultsLocation;extern NSString * const MTRainUserDefaultsLocations; #pragma mark -#pragma mark Notificationsextern NSString * const MTRainDidAddLocationNotification;extern NSString * const MTRainLocationDidChangeNotification; #pragma mark -#pragma mark Location Keysextern NSString * const MTLocationKeyCity;extern NSString * const MTLocationKeyCountry;extern NSString * const MTLocationKeyLatitude;extern NSString * const MTLocationKeyLongitude;
#import "MTConstants.h" #pragma mark -#pragma mark User DefaultsNSString * const MTRainUserDefaultsLocation = @"location";NSString * const MTRainUserDefaultsLocations = @"locations"; #pragma mark -#pragma mark NotificationsNSString * const MTRainDidAddLocationNotification = @"com.mobileTuts.MTRainDidAddLocationNotification";NSString * const MTRainLocationDidChangeNotification = @"com.mobileTuts.MTRainLocationDidChangeNotification"; #pragma mark -#pragma mark Location KeysNSString * const MTLocationKeyCity = @"city";NSString * const MTLocationKeyCountry = @"country";NSString * const MTLocationKeyLatitude = @"latitude";NSString * const MTLocationKeyLongitude = @"longitude";
لجعل MTConstants مفيدة حقاً، وإضافة عبارة الاستيراد لـ: MTConstants.h إلى
الملف الرئيسى المشغل سابقاً الخاص بمشروعك لذلك فإن الثوابت المعلنة في
MTConstants تتوفر في جميع مراحل المشروع.
MTConstants تتوفر في جميع مراحل المشروع.
#import <Availability.h> #ifndef __IPHONE_3_0#warning "This project uses features only available in iOS SDK 3.0 and later."#endif #ifdef __OBJC__ #import <UIKit/UIKit.h> #import <Foundation/Foundation.h> #import <QuartzCore/QuartzCore.h> #import <CoreLocation/CoreLocation.h> #import <MobileCoreServices/MobileCoreServices.h> #import <SystemConfiguration/SystemConfiguration.h> #import "AFNetworking.h" #import "SVProgressHUD.h" #import "IIViewDeckController.h" #import "MTConstants.h"#endif
يمكننا الآن تحديث configureCell: atIndexPath
(MTLocationsViewController.m) كما هو مبين أدناه. فهذا ليس فقط سوف
يعطينا كوداً مكتملاً، وأداءاً سريعاً وبسيطاً، بل أن الإستفادة الحقيقية من هذه الممارسات
هي أن هذا البرنامج سوف يحذرنا في حالة الأخطاء المطبعية. أنا متأكد أنه لا يجب أن
أخبركم بأن الأخطاء المطبعية هي واحدة من الأسباب الأكثر شيوعاً من الأخطاء في
تطوير البرمجيات.
(MTLocationsViewController.m) كما هو مبين أدناه. فهذا ليس فقط سوف
يعطينا كوداً مكتملاً، وأداءاً سريعاً وبسيطاً، بل أن الإستفادة الحقيقية من هذه الممارسات
هي أن هذا البرنامج سوف يحذرنا في حالة الأخطاء المطبعية. أنا متأكد أنه لا يجب أن
أخبركم بأن الأخطاء المطبعية هي واحدة من الأسباب الأكثر شيوعاً من الأخطاء في
تطوير البرمجيات.
- (void)configureCell:(UITableViewCell *)cell atIndexPath:(NSIndexPath *)indexPath { if (indexPath.row == 0) { [cell.textLabel setText:@"Add Current Location"]; } else { // Fetch Location NSDictionary *location = [self.locations objectAtIndex:(indexPath.row - 1)]; // Configure Cell [cell.textLabel setText:[NSString stringWithFormat:@"%@, %@", location[MTLocationKeyCity], location[MTLocationKeyCountry]]]; }}
في الوقت الراهن، الخاصية locations فارغة وهكذا سوف يكون جدول العرض. في
initWithNibName:bundle نحن نستدعى loadLocations كطريقة مساعدة
تقوم بتحميل مجموعة من المواقع والمواضع.
initWithNibName:bundle نحن نستدعى loadLocations كطريقة مساعدة
تقوم بتحميل مجموعة من المواقع والمواضع.
في loadLocations ، قم بتحميل مجموعة من المواقع التي يتم تخزينها في قاعدة
البيانات الخاصه بمستخدم التطبيق. لاحظ أننا نستخدم ثابت خيطي أخر قد أعلنا عنه في
MTConstants.h
البيانات الخاصه بمستخدم التطبيق. لاحظ أننا نستخدم ثابت خيطي أخر قد أعلنا عنه في
MTConstants.h
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil { self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]; if (self) { // Load Locations [self loadLocations]; } return self;}
- (void)loadLocations { self.locations = [NSMutableArray arrayWithArray:[[NSUserDefaults standardUserDefaults] objectForKey:MTRainUserDefaultsLocations]];}
خطوة 5: تعيين مندوب (مفوض)
كما ذكرت سابقاً، فإن المثال MTWeatherViewController بمثابة مفوض مواضع
متحكم العروض.
متحكم العروض.
أعد زيارة MTAppDelegate.m وقم بتحديث التطبيق:
didFinishLaunchingWithOptions كما هو مبين أدناه.
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { // Initialize View Controllers MTLocationsViewController *leftViewController = [[MTLocationsViewController alloc] initWithNibName:@"MTLocationsViewController" bundle:nil]; MTForecastViewController *rightViewController = [[MTForecastViewController alloc] initWithNibName:@"MTForecastViewController" bundle:nil]; MTWeatherViewController *centerViewController = [[MTWeatherViewController alloc] initWithNibName:@"MTWeatherViewController" bundle:nil]; // Configure Locations View Controller [leftViewController setDelegate:centerViewController]; // Initialize View Deck Controller self.viewDeckController = [[IIViewDeckController alloc] initWithCenterViewController:centerViewController leftViewController:leftViewController rightViewController:rightViewController]; // Initialize Window self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; // Configure Window [self.window setRootViewController:self.viewDeckController]; [self.window makeKeyAndVisible]; return YES;}
قبل إجراء هذا التغيير، يجب أن يظهر تحذير مفاجىء وفوري يخبرك بأن
MTWeatherViewController لا يتوافق مع بروتوكول
MTLocationsViewControllerDelegate
البرنامج المترجم على حق لذلك دعونا نقوم بإصلاح هذا.
افتح MTWeatherViewController.h ثم احصل على الملف الرئيسى لـ:
MTLocationsViewController ، وطابق MTWeatherViewController
لبروتوكول MTLocationsViewControllerDelegate
MTLocationsViewController ، وطابق MTWeatherViewController
لبروتوكول MTLocationsViewControllerDelegate
#import <UIKit/UIKit.h> #import "MTLocationsViewController.h" @interface MTWeatherViewController : UIViewController <MTLocationsViewControllerDelegate> @end
انتظر.. هل من تحذير آخر؟ نحن لم ننفذ الطريقتين المطلوبتين لـ: بروتوكول التفويض
حتى الآن. افتح MTWeatherViewController.m وقم بإضافة تنفيذ لكل من طرق
التفويض.
- (void)controllerShouldAddCurrentLocation:(MTLocationsViewController *)controller { NSLog(@"%s", __PRETTY_FUNCTION__);} - (void)controller:(MTLocationsViewController *)controller didSelectLocation:(NSDictionary *)location { NSLog(@"%s", __PRETTY_FUNCTION__);}
خطوة 6: جلب الموقع الحالي
حان الوقت أخيراً لجلب الموقع الحالي للجهاز. أضف إمتداد الفئة أو الملحق الفئوي في
الجزء العلوي من MTWeatherViewController.m ثم أعلن عن خاصيتين، (1)
location (NSDictionary) لتخزين الموقع الافتراضي للتطبيق و(2)
locationManager (CLLocationManager)، سوف نستخدمه لجلب موقع
الجهاز.
الجزء العلوي من MTWeatherViewController.m ثم أعلن عن خاصيتين، (1)
location (NSDictionary) لتخزين الموقع الافتراضي للتطبيق و(2)
locationManager (CLLocationManager)، سوف نستخدمه لجلب موقع
الجهاز.
قم بمطابقة الفئة MTWeatherViewController للبروتوكول
CLLocationManagerDelegate وعرف متغيرأخر اسمه _locationFound
من نوع BOOL والغرض من _locationFound سوف يصبح واضحاً في خلال
بضع دقائق.
CLLocationManagerDelegate وعرف متغيرأخر اسمه _locationFound
من نوع BOOL والغرض من _locationFound سوف يصبح واضحاً في خلال
بضع دقائق.
#import "MTWeatherViewController.h" @interface MTWeatherViewController () <CLLocationManagerDelegate> { BOOL _locationFound;} @property (strong, nonatomic) NSDictionary *location; @property (strong, nonatomic) CLLocationManager *locationManager; @end
فى المهيىء المحدد للفئة، initWithNibName:bundle سوف نقوم بتهيئة وتكوين
مدير الموضع. نحن نحدد متحكم العروض كما لو كان مفوض مدير الموقع وتحديد
خاصية accuracy الخاصه بمدير الموقع إلى
kCLLocationAccuracyKilometer
ليست هناك حاجة إلى دقة أفضل فنحن فقط بحاجة إلى موقع لبيانات الطقس.
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil { self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]; if (self) { // Initialize Location Manager self.locationManager = [[CLLocationManager alloc] init]; // Configure Location Manager [self.locationManager setDelegate:self]; [self.locationManager setDesiredAccuracy:kCLLocationAccuracyKilometer]; } return self;}
الجزء التالي من اللغز قيد التنفيذ locationManager: didUpdateLocations ،
إحدى الطرق للبروتوكول CLLocationManagerDelegate ، الذي يتم استدعاؤه
في كل مرة مقوم فيها مدير الموقع بعمل تحديث لـ: موقع الأجهزة.
المرحلة الثانية من locationManager: didUpdateLocations هي نماذج من
CLLocation
CLLocation
وتنفيذ locationManager: didUpdateLocations يكشف أيضاً عن الغرض
من _locationFound
من _locationFound
بالرغم من حقيقة أننا نخبر مدير المواقع أن يقوم بوقف تحديث الموقع بمجرد أن يتم
استدعاء locationManager: didUpdateLocations ، فإنه ليس من غير
المألوف أن يقوم تحديث أخر للموقع باستدعاء locationManager
didUpdateLocations: مرة أخرى حتى بعد إرسال مدير الموقع رسالة من
stopUpdatingLocation
استدعاء locationManager: didUpdateLocations ، فإنه ليس من غير
المألوف أن يقوم تحديث أخر للموقع باستدعاء locationManager
didUpdateLocations: مرة أخرى حتى بعد إرسال مدير الموقع رسالة من
stopUpdatingLocation
إذا حدث هذا، سوف نضيف نفس الموقع مرتين إلى قائمة المواقع.
الحل البسيط هو استخدام متغير مساعد، _locationFound حيث أنه سيحافظ على
المسارالذي نحن فيه.
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations { if (![locations count] || _locationFound) return; // Stop Updating Location _locationFound = YES; [manager stopUpdatingLocation]; // Current Location CLLocation *currentLocation = [locations objectAtIndex:0]; // Reverse Geocode CLGeocoder *geocoder = [[CLGeocoder alloc] init]; [geocoder reverseGeocodeLocation:currentLocation completionHandler:^(NSArray *placemarks, NSError *error) { if ([placemarks count]) { _locationFound = NO; [self processPlacemark:[placemarks objectAtIndex:0]]; } }];}
نحن نستخرج الموقع الأول من مجموعة المواقع ونستخدم فئة CLGeocoder لعكس
الترميز الجغرافي لهذا الموقع.
الترميز الجغرافي العكسي يعني ببساطة معرفة اسم (أقرب) مدينة والبلد التى يقع فيها
الموقع.
الموقع.
معالج الإتمام من reverseGeocodeLocation يقوم بإرجاع مجموعة من
العلامات الموضعية. والهدف من العلامات الموضعية ببساطة ليس أكثر من وعاء
لتخزين بيانات الموقع للتنسيق.
العلامات الموضعية. والهدف من العلامات الموضعية ببساطة ليس أكثر من وعاء
لتخزين بيانات الموقع للتنسيق.
- (void)processPlacemark:(CLPlacemark *)placemark { // Extract Data NSString *city = [placemark locality]; NSString *country = [placemark country]; CLLocationDegrees lat = placemark.location.coordinate.latitude; CLLocationDegrees lon = placemark.location.coordinate.longitude; // Create Location Dictionary NSDictionary *currentLocation = @{ MTLocationKeyCity : city, MTLocationKeyCountry : country, MTLocationKeyLatitude : @(lat), MTLocationKeyLongitude : @(lon) }; // Add to Locations NSUserDefaults *ud = [NSUserDefaults standardUserDefaults]; NSMutableArray *locations = [NSMutableArray arrayWithArray:[ud objectForKey:MTRainUserDefaultsLocations]]; [locations addObject:currentLocation]; [locations sortUsingDescriptors:@[[NSSortDescriptor sortDescriptorWithKey:MTLocationKeyCity ascending:YES]]]; [ud setObject:locations forKey:MTRainUserDefaultsLocations]; // Synchronize [ud synchronize]; // Update Current Location self.location = currentLocation; // Post Notifications NSNotification *notification2 = [NSNotification notificationWithName:MTRainDidAddLocationNotification object:self userInfo:currentLocation]; [[NSNotificationCenter defaultCenter] postNotification:notification2];}
في processPlacemark ، نحن نقوم باستخراج البيانات التي نبحث عنها، وهي
المدينة، البلد، خط العرض، وخط الطول، وحفظها في القاموس، وتحديث مجموعة من
المواقع في قاعدة البيانات الافتراضية للمستخدم للتطبيق.
لاحظ أننا قمنا بفرز مجموعة من المواقع قبل تحديث قاعدة البيانات الافتراضية
للمستخدم. حيث يتم تحديث خاصية location الخاصة بمتحكم العروض مع الموقع
الجديد ويتم إرسال إشعار يخطر أي كائن مهتم بهذا الحدث.
للمستخدم. حيث يتم تحديث خاصية location الخاصة بمتحكم العروض مع الموقع
الجديد ويتم إرسال إشعار يخطر أي كائن مهتم بهذا الحدث.
هذا ليس كل شيء، فقد تجاوزنا أيضاً خاصية location الخاصة بمتحكم العروض.
لأن فئة MTWeatherViewController هي المسؤولة عن إضافة مواقع جديدة،
يمكننا تفويض بضع مسؤولين إضافيين لهذه الفئة، مثل تحديث الموقع الافتراضي في
قاعدة البيانات الافتراضية للمستخدم.
يمكننا تفويض بضع مسؤولين إضافيين لهذه الفئة، مثل تحديث الموقع الافتراضي في
قاعدة البيانات الافتراضية للمستخدم.
لأن أجزاء أخرى من التطبيق تحتاج أيضاً إلى معرفة التغير في الموقع، ويتم نشر
إشعار باسم MTRainLocationDidChangeNotification
إشعار باسم MTRainLocationDidChangeNotification
نحن أيضاً نقوم باستدعاء updateView أسلوب مساعد آخر سننفذه قريباً.
- (void)setLocation:(NSDictionary *)location { if (_location != location) { _location = location; // Update User Defaults NSUserDefaults *ud = [NSUserDefaults standardUserDefaults]; [ud setObject:location forKey:MTRainUserDefaultsLocation]; [ud synchronize]; // Post Notification NSNotification *notification1 = [NSNotification notificationWithName:MTRainLocationDidChangeNotification object:self userInfo:location]; [[NSNotificationCenter defaultCenter] postNotification:notification1]; // Update View [self updateView]; }}
خطوة 7: إضافة تسمية
نحن لن نقضي الكثير من الوقت على واجهة المستخدم في هذا البرنامج التعليمي، ولكن
للتأكد من أن كل شيء يعمل كما نتوقع، فمن الجيد أن يكون بعض التغذيات العكسية
البصرية بإضافة تسمية معينة إلى صفحة متحكم العروض الخاصة بالطقس لعرض
الموقع المحدد.
للتأكد من أن كل شيء يعمل كما نتوقع، فمن الجيد أن يكون بعض التغذيات العكسية
البصرية بإضافة تسمية معينة إلى صفحة متحكم العروض الخاصة بالطقس لعرض
الموقع المحدد.
قم بفتح MTWeatherViewController.h وأنشئ منفذاً من نوع UILabel وقم
بتسميته labelLocation
بتسميته labelLocation
#import <UIKit/UIKit.h> #import "MTLocationsViewController.h" @interface MTWeatherViewController : UIViewController <MTLocationsViewControllerDelegate> @property (weak, nonatomic) IBOutlet UILabel *labelLocation; @end
افتح MTWeatherViewController.xib ، قم بإضافة تسمية لصفحة متحكم
العروض، وقم بتوصيل المنفذ مع التسمية المضافة حديثاً (الشكل 6).
في updateView (MTWeatherViewController.m) ، نقوم بتحديث التسمية
مع الموقع الجديد كما هو موضح أدناه.
إعداد مشروع إنشاء تطبيق مناخي مع توقع الطقس |
خطوة 8: تنفيذ بروتوكول التفويض
وبفضل العمل الذي قمنا به حتى الآن، فإن تنفيذ اثنين من طرق بروتوكول
MTLocationsViewControllerDelegate أصبح أمراً سهلاً.
MTLocationsViewControllerDelegate أصبح أمراً سهلاً.
في controllerShouldAddCurrentLocation ، نخبر مدير الموقع أن يبدأ
بتحديث الموقع.
بتحديث الموقع.
في controller:didSelectLocation ، نحن نقوم بضبط خاصية location
الخاصة بمتحكم العروض إلى الموقع الذى قام المستخدم باختياره فى متحكم عرض
المواقع، والذي بدوره يقوم باستدعاء الطريقة الابتدائية التى تجاهلناها قليلاً مؤخراً.
الخاصة بمتحكم العروض إلى الموقع الذى قام المستخدم باختياره فى متحكم عرض
المواقع، والذي بدوره يقوم باستدعاء الطريقة الابتدائية التى تجاهلناها قليلاً مؤخراً.
4. اللمسات النهائية
قبل اختتام الدفعة الأولى من هذه السلسلة، نحن بحاجة إلى إضافة بعض اللمسات النهائية.
عندما يطلق المستخدم هذا التطبيق، على سبيل المثال، فإن خاصية location للفئة
MTWeatherViewController تحتاج لتعيينها فى الموقع الذى تم تخزينه في
التطبيق الافتراضي للمستخدم. بالإضافة إلى ذلك، عندما يقوم المستخدم بإطلاق تطبيقنا
للمرة الأولى، لم يتم تعيين موقع افتراضي بعد خلفية تطبيق المستخدم. هذه ليست
مشكلة كبيرة، ولكن لتقديم خبرة جيدة للمستخدم فمن الأفضل أن يتم جلب الموقع الحالي
تلقائياً للمستخدم عندما يطلق التطبيق للمرة الأولى.
عندما يطلق المستخدم هذا التطبيق، على سبيل المثال، فإن خاصية location للفئة
MTWeatherViewController تحتاج لتعيينها فى الموقع الذى تم تخزينه في
التطبيق الافتراضي للمستخدم. بالإضافة إلى ذلك، عندما يقوم المستخدم بإطلاق تطبيقنا
للمرة الأولى، لم يتم تعيين موقع افتراضي بعد خلفية تطبيق المستخدم. هذه ليست
مشكلة كبيرة، ولكن لتقديم خبرة جيدة للمستخدم فمن الأفضل أن يتم جلب الموقع الحالي
تلقائياً للمستخدم عندما يطلق التطبيق للمرة الأولى.
يمكننا القيام بالعديد من التغيرات من خلال تعديل viewDidLoad الخاص بوحدة
تحكم عرض الطقس كما هو موضح أدناه.
تحكم عرض الطقس كما هو موضح أدناه.
إن خاصية موقع متحكم العروض يتم تعيينها وفق قاعدة البيانات الافتراضية الخاصة
بالمستخدم.
بالمستخدم.
إذا لم يوجد أي موقع، فهذا هو self.location ويكون nil ، ونحن نخبر مدير الموقع
أن يقوم ببدء تحديث الموقع. أو بعبارة أخرى، عندما يتم تشغيل التطبيق لأول مرة، يتم
استرداد الموقع الحالي وتخزينه تلقائياً.
أن يقوم ببدء تحديث الموقع. أو بعبارة أخرى، عندما يتم تشغيل التطبيق لأول مرة، يتم
استرداد الموقع الحالي وتخزينه تلقائياً.
هناك نهاية ملحة بأننا نحتاج إلى عملية ربط.
فعند إضافة موقع جديد لمجموعة من المواقع، فإن متحكم عرض الطقس ينشر لنا
إشعاراً بأننا في حاجة إلى تحديث الفئة MTLocationsViewController بحيث
يضيف نفسه كمراقب وملاحظ لهذه الإخطارات.
إشعاراً بأننا في حاجة إلى تحديث الفئة MTLocationsViewController بحيث
يضيف نفسه كمراقب وملاحظ لهذه الإخطارات.
من خلال القيام بذلك، فإن متحكم عرض المواقع يمكنه تحديث طريقة جدول العرض
الخاص به كلما تمت إضافة موقع جديد.
أعد زيارة MTLocationsViewController.m وقم بتحديث
initWithNibName:bundle كما هو مبين أدناه.
initWithNibName:bundle كما هو مبين أدناه.
أضفنا متحكم العروض كمراقب للإخطارات بإسم
MTRainDidAddLocationNotification
MTRainDidAddLocationNotification
حيث أن تنفيذ didAddLocation يكون واضحاً ومباشراً، ومن هنا يمكن أن نضيف
الموقع الجديد لمجموعة المواقع، أفرز تلك المجموعة بالمدينة، وأعد تحميل جدول
العرض.
الموقع الجديد لمجموعة المواقع، أفرز تلك المجموعة بالمدينة، وأعد تحميل جدول
العرض.
لا تنسى إزالة وحدة تحكم العرض كمراقب في طريقة dealloc.
بل هو أيضاً ممارسة جيدة لتعيين الخاصية delegate الخاصة بوحدة التحكم في
العرض إلى nil في dealloc.
العرض إلى nil في dealloc.
قم ببناء وتشغيل التطبيق لترى كيف يعمل كل هؤلاء معاً.
قد ترغب في تشغيل التطبيق في محاكي دائرة الرقابة الداخلية بدلاً من تشغيله على
جهاز فعلي، لأن محاكي دائرة الرقابة الداخلية يدعم محاكاة المواقع (الشكل 7)، الأمر
الذي يجعل من السهل جداً اختبار التطبيقات القائمة على الموقع مثل هذا الذي قد أنشأناه.
جهاز فعلي، لأن محاكي دائرة الرقابة الداخلية يدعم محاكاة المواقع (الشكل 7)، الأمر
الذي يجعل من السهل جداً اختبار التطبيقات القائمة على الموقع مثل هذا الذي قد أنشأناه.
الخلاصة:
على الرغم من أننا لم نقم بتشغيل Forecast API حتى الآن، فقد قمنا بقدر كبير من
العمل في هذه المقالة.
العمل في هذه المقالة.
آمل أن تكون قد حاولت عمل CocoaPods وأن تكون مقتنعاً بمدى قوته ومرونته.
في الدفعة القادمة من هذه السلسلة، سوف نركز على Forecast API ومكتبة
AFNetworking
إلى اللقاء فى الدرس القادم إن شاء الله.
ليست هناك تعليقات: