بسم الله سوف نبدأ هذه السلسلة من الشروحات والتي تختص بمكتبات Swift والبرمجة للـ IOS وإذا كنت لا تعلم كيف التعامل مع المكتبات وماهي فائدتها أطلع على موضوعي السابق COCOAPODS ماهي وما فائدتها وكيف تستخدمها ، سوف نخصص هذه السلسلة لشرح آفضل وأهم المكاتب للسويفت وتطوير IOS والتي تساعد الكثير وتسهل الكثير من العمل وتخرج لك بنتائج ممتازة وأكثر ثبات وسرعة .
وبداية سوف نبدأ مع أهم الأجزاء للتطبيقات وهو الإتصال بالسيرفر والتعامل مع بيانات JSON المرسلة من السيرفر ولذلك سوف نستخدم أفضل المكاتب Swift في هذا المجال وهي مكتبة Alamofire
مستوى الدرس : متوسط
ماهي Alamofire ولماذا ؟
مكتبة مبرمجة بالكامل بلغة Swift مختصة بالتواصل والإتصال مع السيرفرات والمواقع لإستقبال وإرسال البيانات من وإلى تطبيقك .
لماذا ؟ : لا تخلو معظم التطبيقات من التواصل مع السيرفر وكما يسمى ServerSide لكي يتم تخزين البيانات على السحاب وإستقبال البيانات من السحاب إذا كان التطبيق يحتاج ذلك .
واليوم لن نشرح كيفية إنشاء ServerSide ولكن لقد تطرقنا لها في عدة مواضيع ماذا قبل أغلاق خدمة Parse السحابية وماهي أفضل الخدمات الأخرى ، الجزء الأول و ماذا قبل أغلاق خدمة Parse السحابية وماهي أفضل الخدمات الأخرى ، الجزء الثاني .
تحميل وتثبيت Alamofire :
سوف يتم إستخدام COCOAPODS لهذه المهمه وإن لم تكن على معرفة بكيفية إستخدامها مشكلتك والله 😆 أمزح راجع موضوعي COCOAPODS ماهي وما فائدتها وكيف تستخدمها .
ببساطة في ملف podfile الخاص بالمشروع الذي نود العمل عليه سوف نستدعي
pod 'Alamofire', '~> 3.4'
بعدها نقوم بتشغل الأمر Pod Install من Terminal .
الأن هي جاهزه للإستخدام داخل ملفات مشروعك وكما هو متعارف أن أفضل طريقة للتعلم هي التطبيق على مثال لذلك سوف نعمل على مثال وهو تطبيق بسيط لجلب درجات الحرارة والمناخ من API جاهز وفي هذا الجزء سوف نتعلم إستقبال البيانات فقط وبإذن الله بالجزء القادم إرسال البيانات وبعدها سوف يتبعها أجزاء أكثر تقدم .
جلب البيانات من API :
ولهذه المهمه سوف نستخدم API جاهز ومجاني من موقع openweathermap.org ولكن عليك الحصول على key خاص بك وتستطيع التسجيل والحصول على واحد خاص أو إستخدام المفتاح الخاص بنا والواضح بالشرح .
بعد قراءة بسيطة لشرح API الخاص بجلب المناخ الحالي من هنا توصلنا إلى الرابط التالي
api.openweathermap.org/data/2.5/weather?id=105343&units=metric&APPID=071913a041f022290a6651f463045c65
ولكي تعلم ماذا حصل في هذا الرابط ولكي تأخذ فكرة هنا شرح مبسط عن المتغيرات التي وضعتها بالرابط
عند فتح الرابط على المتصفح أو أفضل إستخدام تطبيق PostMan لمحاكاة وتجربة الطلبات على APIs سوف نجد النتيجة التالية :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 |
{ "coord": { "lon": 39.22, "lat": 21.52 }, "weather": [ { "id": 800, "main": "Clear", "description": "clear sky", "icon": "01d" } ], "base": "cmc stations", "main": { "temp": 30.95, "pressure": 1017.04, "humidity": 91, "temp_min": 30.95, "temp_max": 30.95, "sea_level": 1019.01, "grnd_level": 1017.04 }, "wind": { "speed": 5.37, "deg": 199.507 }, "clouds": { "all": 0 }, "dt": 1465913069, "sys": { "message": 0.0033, "country": "SA", "sunrise": 1465872028, "sunset": 1465920406 }, "id": 105343, "name": "Jeddah", "cod": 200 } |
نعم هذه بيانات بصيغة JSON وهذا المطلوب لكي نتعامل معاه بتطبيقنا على IOS والأن سوف نبدأ بتجهيز تطبيقنا والواجهات وإستدعاء مكتبة Alamofire .
تجهيز تطبيق IOS وربط البيانات :
لن أتطرق لكيفية إنشاء تطبيق جديد ووضع Labels وتزبيط الواجهه على إفتراض إنك بمستوى متوسط وتعلم هذه الأمور لتصميم الواجهات عن طريق Xcode .
قمت بتصميم هذه الواجهه البسيطة لتطبيق IOS بإستخدام Xcode وبالمناسبة الخلفية من تصويري في 2012 😛 فرصه سعيدة 😆
وضعت البيانات بشكل وهمي والأن سوف نقوم بربطها بالسيرفر والمعلومات المعطاه من JSON
بدايةً لابد من إستدعاء المكتبة عن طريق الأمر import Alamofire
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
import UIKit import Alamofire class ViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() // Do any additional setup after loading the view, typically from a nib. } override func didReceiveMemoryWarning() { super.didReceiveMemoryWarning() // Dispose of any resources that can be recreated. } } |
الأن سوف نقوم بربط Labels من StoryBoards للكود الخاص بنا
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
import UIKit import Alamofire class ViewController: UIViewController { @IBOutlet weak var temp: UILabel! @IBOutlet weak var humidity: UILabel! @IBOutlet weak var windSpeed: UILabel! override func viewDidLoad() { super.viewDidLoad() // Do any additional setup after loading the view, typically from a nib. } override func didReceiveMemoryWarning() { super.didReceiveMemoryWarning() // Dispose of any resources that can be recreated. } } |
نحن الأن جاهزين للتعامل مع المكتبة وإستخدامها
سوف أقوم بإنشاء دالة تقوم بجلب البيانات لي وسوف أسميها getDataFromUrl
1 2 3 |
func getDataFromUrl() { } |
ومن ثم سوف أستخدم المكتبة لإرسال الطلب إلى الرابط وإستقبال البيانات المرسله من الرابط
1 2 3 4 5 6 7 |
func getDataFromUrl() { Alamofire.request(.METHOD , "URL") .responseJSON { response in } } |
METHOD : هنا نضع نوع الطلب مثلا GET أو POST أو غيرهم .
URL : نضع الرابط الخاص بنا والذي قمنا بإستنتاجه سابقا من موقع المناخ .
ليصبح معنا بالشكل التالي
1 2 3 4 5 6 7 |
func getDataFromUrl() { Alamofire.request(.GET , "http://api.openweathermap.org/data/2.5/weather?id=105343&units=metric&APPID=071913a041f022290a6651f463045c65") .responseJSON { response in } } |
الأن البيانات التي نريدها سوف تكون داخل response
ولكن لن تكون بصيغة JSON واضحة نستطيع الوصول لها بسهوله لذلك وبإستخدام دوال نفس المكاتبة سوف نخبره بأني يأتي لنا بقيم النتيجة فقط وترك الباقي وهذا ما نحتاجه
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
func getDataFromUrl() { Alamofire.request(.GET, "http://api.openweathermap.org/data/2.5/weather?id=105343&units=metric&APPID=071913a041f022290a6651f463045c65") .responseJSON { response in // هنا جلبنا قيم النتيجة ووضعناها بمتغير JSON // وطبعاً لأن بعض الآحيان لن تكون هناك نتيجة بسبب أن مثلا السيرفر // لا يعمل أو غيره لذلك وضعناها بجمله شرطية لكي لا ينهار التطبيق في حال كان لا توجد قيم if let JSON = response.result.value { } } } |
الأن بمتغير JSON توجد القيم التي نحتاجها والتي أشرنا إليها سابقاً
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 |
{ "coord": { "lon": 39.22, "lat": 21.52 }, "weather": [ { "id": 800, "main": "Clear", "description": "clear sky", "icon": "01d" } ], "base": "cmc stations", "main": { "temp": 30.95, "pressure": 1017.04, "humidity": 91, "temp_min": 30.95, "temp_max": 30.95, "sea_level": 1019.01, "grnd_level": 1017.04 }, "wind": { "speed": 5.37, "deg": 199.507 }, "clouds": { "all": 0 }, "dt": 1465913069, "sys": { "message": 0.0033, "country": "SA", "sunrise": 1465872028, "sunset": 1465920406 }, "id": 105343, "name": "Jeddah", "cod": 200 } |
وليس علينا سوا الوصول لها من متغير JSON ولأن تطبيقنا يوجد فيه فقط ثلاث بيانات وهي درجة الحرارة و نسبة الرطوبة و سرعة الرياح ، لذلك من هذه البيانات لن نحتاج إلا لـ temp , humidity , speed
ولكن لو نلاحظ إنها تقع تحت قيم أخرى ف مثلا temp و humidity نجدها إنها توجد داخل قيمة main وايضا سرعة الرياح speed توجد داخل قيمة wind والسؤال الأن كيف يمكننا الوصول لهذه القيم مباشرة وترك الباقي ؟
دعنا نتخليها كأنها أسماء بشر الجد هو المتغير الكبير JSON من ثم نذهب إلى الإبن فمثلاً نذهب إلى الأبن main لنجد إنه لديه أطفال من ضمنهم الطفل temp
لذلك يصبح إسم temp التالي ” temp بن main بن JSON ال Alamofire ” والنعم والله 😆 ههههه المهم
لذلك لكي نصل إلى temp علينا المرور على الأب أولا وذلك يتم بالكود على الطريقة التالية :
JSON["main"]["temp"]
أي سوف يصبح كود Swift كالتالي :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
func getDataFromUrl() { Alamofire.request(.GET, "http://api.openweathermap.org/data/2.5/weather?id=105343&units=metric&APPID=071913a041f022290a6651f463045c65") .responseJSON { response in if let JSON = response.result.value { if let temp = JSON["main"]!!["temp"]! { print(temp) } } } } |
قد يخطر ببالك سؤال لماذا وضعت علامات ! بعد main وبعد temp في لغة swift علامة ! تعني force unwrap يعني تأكيد أن هناك قيمة حقيقه اي إنني أأكد على السويفت بأن JSON يوجد لها أبناء على شكل arrays ولها خاصة إبن إسمه main أكيد والله وإنو كمان main هي عبارة عن array و لها آبن إسمه temp أكيد .
طيب ماذا لو نحن غير متأكدين من حضور القيمة لأي سبب من الأسباب لذلك وضعنها في جملة شرطية بحيث إنه في حال وجود القيمة إنشيء لي المتغير temp وضع القيمه فيه وفي حال عدم وجود قيمة لا تفعل شيء
الأن عند تشغيل التطبيق سوف تكون النتيجة : 27.22
ممتاز
المفترض الآن تعلم كيف إحضار باقي القيم الخاصة بنسبة الرطوبة وسرعة الرياح هيا حاول ولا تغش من تحت 😉
إذا ما عرفت
طيب ، دعنا نتابع عند وضع باقي القيم سوف يصبح الكود كالتالي :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
func getDataFromUrl() { Alamofire.request(.GET, "http://api.openweathermap.org/data/2.5/weather?id=105343&units=metric&APPID=071913a041f022290a6651f463045c65") .responseJSON { response in if let JSON = response.result.value { if let tempe = JSON["main"]!!["temp"]! { print(tempe) } if let humidity = JSON["main"]!!["humidity"]! { print(humidity) } if let wind = JSON["wind"]!!["speed"]! { print(wind) } } } } |
ممتاز الأن عند التشغيل سوف تظهر لنا القيم الثلاثه في Console أتوقع تعلم كيف وضعها داخل labels بدل القيم الوهميه التي وضعناها ؟ لا تعلم لا مشكلة
قمنا سابقا بربط labels في الكود وذلك عن طريق إنشاء outlets لها والآن ليس علينا سوا تغير قيمها بالطريقة التاليه
self.temp.text = String(tempe)
ولابد أن نقوم بعمل cast لقيمة temp لتصبح String لأن بالآساس القيمة غير معروف نوعها ولأن labels لا يقبل سوا قيم String فكان لابد من عمل Casting لها كما هو موضح بالكود السابق .
وبعد وضع قيم الجميع سوف يصبح كود الدالة كالتالي مع شوية تعديلات لنظهر الوحدات :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
func getDataFromUrl() { Alamofire.request(.GET, "http://api.openweathermap.org/data/2.5/weather?id=105343&units=metric&APPID=071913a041f022290a6651f463045c65") .responseJSON { response in if let JSON = response.result.value { if let temp = JSON["main"]!!["temp"]! { self.temp.text = String(temp) + "°" } if let humidity = JSON["main"]!!["humidity"]! { self.humidity.text = String(humidity) + "%" } if let wind = JSON["wind"]!!["speed"]! { self.windSpeed.text = String(wind) + " km/h" } } } } |
لا تنسى إستدعاء الدالة في دالة viewDidLoad
أي سوف يصبح الكود بشكل كامل كالتالي :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 |
import UIKit import Alamofire class ViewController: UIViewController { @IBOutlet weak var temp: UILabel! @IBOutlet weak var humidity: UILabel! @IBOutlet weak var windSpeed: UILabel! override func viewDidLoad() { super.viewDidLoad() getDataFromUrl() // Do any additional setup after loading the view, typically from a nib. } func getDataFromUrl() { Alamofire.request(.GET, "http://api.openweathermap.org/data/2.5/weather?id=105343&units=metric&APPID=071913a041f022290a6651f463045c65") .responseJSON { response in if let JSON = response.result.value { if let temp = JSON["main"]!!["temp"]! { self.temp.text = String(temp) + "°" } if let humidity = JSON["main"]!!["humidity"]! { self.humidity.text = String(humidity) + "%" } if let wind = JSON["wind"]!!["speed"]! { self.windSpeed.text = String(wind) + " km/h" } } } } override func didReceiveMemoryWarning() { super.didReceiveMemoryWarning() // Dispose of any resources that can be recreated. } } |
الأن عند تشغيل التطبيق على Simulator
واااو نسبة الرطوبة عندنا بجدة 100% !! أتوقع الموقع غلطان شوي 😆
إلي هنا وصلنا إلى نهاية هذا الدرس أتمنى من الله ان تكون أستفدت منه ما ترجوه وبإذن الله يوجد عدة دروس تابعة لمكتبة Alamofire وسوف نتعمق بها بشكل أكبر ومن ثم بإذن الله سوف نتقل لعدة مكاتب مهمه ورائعه تسهل من عملك الكثير .
أتمنى منك دعمي بنشر رابط هذا المقال ولكي تفيد غيرك ويعلم الله وحده الجهد والوقت الذي يتطلبه مني إنشاء هذه المقالات وقد سهلت لك أمر النشر فقط إختر الشبكة التي تود النشر فيها من الأسفل وسوف يتكفل الموقع بكل شيء ، تأكد دعمك لي بالنشر يحمسني أكثر وأكثر للمزيد .
سبحانك اللهم وبحمدك , أشهد أن لا إله إلا أنت , أستغفرك وأتوب إليك ..
الرابط المختصر للموضوع : xd7.me/18
15 October، 2016 at 2:49 pm
ما شاء الله ’ الشرح دسم ’ ويعطيك العافية
و انتظر منك المزيد
15 October، 2016 at 4:23 pm
أسعدني ردك
شكرا لك وبإذن الله القادم أفضل
15 January، 2017 at 7:42 pm
جزاك الله خير، شكراً على مجهودك.
18 August، 2017 at 10:15 am
سويت الشرح وطلع لي خطا error extra argument in call
18 December، 2017 at 6:56 pm
استفدت كثييير شكرا على الشرح الجميل …
26 May، 2018 at 3:25 am
شرح بسيط ووافي
شكرًا لجهدك يالذيب