1. رغم انه المفترض في هذا الموضوع اتحدث عن طرق الاستخدام الخاطئ للـ Segue وتركيزه ينصب في شرح الـ Unwind Segue الا اني سوف أقوم بشرح الامرين لجعل الموضوع اشمل
     
     
    ما هو الـ Segue ؟
    الـ Segue هو عملية الانتقال بين صفحة (View Controller) الى اخر ويتم عن طريق ربط زر او Action موجود في الصفحة الاولى الى الصفحة الأخرى
     
    اهم قاعده هنا الانتقال يكون من صفحة 1 الى صفحة 2 ولا يحصل انتقال بشكل عكسي أيضا !
    هذا من اكثر الاخطاء شيوعاً عند المطورين الجدد !
    لفهم الـ Segue بشكل صحيح سوف اشرحه على مراحل او طرق بالتدرج
     
    الطريقة الاولى :
    في هذه الطريقة فقط نقوم بالربط بين صفحة وأخرى وتستخدم الطريقة هذه بشكل نادر فقط لغرض عرض صفحة أخرى دون الحاجة لاستخدام اكواد او نقل معلومات من صفحة الاولى الى الثانية
     
    والطريقة تكمن في التالي :

     
    أولا : نقوم اول بإضافة 2 من View Controller
     
    ثانيا : نقوم بإضافة Button في صفحة 1
     
    ثالثا : نقوم بالضغط الـ Button + زر control ونسحب الـ Button الى الـ View Controller الاخر
     
    رابعا : نختار Show
     
    من امثله استخدام الطريقة هذه اذا اردت أن تعرض صفحة اتصل بنا او عن التطبيق, في هذه الصفحات فقط تعرض معلومات ولا تحتاج الا نقل معلومة من صفحة الى أخرى او تحتاج أن تقوم ببعض الامور قبل عملية الانتقال, لذا استخدام الطريقة هذه طريقة نادره
     
    الطريقة الثانية :
     
    الطريقة هذه تعتمد على موضوع الانتقال للصفحة الثانية بعد تنفيذ امر معين وبدون الحاجة الى نقل معلومات من الصفحه 1  الى الصفحة 2
     
    لكي تفهم الفكرة بشكل صحيح ، لنفترض بأنك تعمل على صفحة "التسجيل حساب جديد" راح تحتاج تكتب التالي في Function الـ Button
    تتأكد بأن المستخدم كتب جميع الحقول من اسم المستخدم والايميل والباسورد وإعادة كتابة الباسورد تتأكد بأن هناك تطابق في حقل باسورد مع حقل إعادة كتابة الباسورد تتأكد من تلبية شروط كتابة الباسورد على سبيل المثال بأن تم كتابة ٨ احرف تتصل بالسيرفر في حال تم الاتصال وحفظ بيانات المستخدم بنجاح هنا يتم الانتقال الي الصفحة الثانية !  
    هل لاحظت الفرق ؟
     
    في الطريقة الاولى الانتقال مباشرة الى الصفحة الثانية ولكن في هذه الطريقة هناك أمور كثيره تحدث بمجرد ضغط المستخدم على الـ Button وتتم الانتقال اثناء حدوث امراُ معيناً وليس بشكل مباشر !
    والطريقة تكمن في التالي :
     
    نفس خطوات الطريقة الاولى بالضبط ولكن هنا يتم إضافة مُعرف (Identifier)
     
    لاحظ الصورة التالية :

     
    وفي داخل Function الـ Button
    نكتب التالي :

     
            performSegue(withIdentifier: "toView2", sender: nil)  
    لاحظ في السطر السابق كتبنا نفس المُعرف بالضبط الذي كتبناه في حقل الـ Identifier في الـ Storyboard
     
    وأقصد هنا بالضبط  ، المسافة تفرق ، الحرف الكبتل والسمول أيضا يفرق ! بما يعني الأفضل أن تقوم بنسخه ومن ثم لصقه بدلاً من كتابته .
     
    قد تتسأل ما الفائده من المُعرف ؟
     
    المُعرف هو المسؤول عن توجهيه الـ View Controller الى  الـ View Controller  الصحيح.
     
    في تطوير التطبيقات سوف تحتاج الي عملية انتقال مختلفة من نفس الـ View Controller قد يحتوي تطبيقك مثلا على زرين كل زر يوجه الى صفحه مختلفة فهنا المُعرف يجعل الـ Xcode يوجهك الى الصفحة الصحيحة.
     
    الطريقة الثالثة :
    في هذه الطريقة اذا اردت بأن تقوم بنقل معلومات من الصفحة 1 الى صفحة 2
    الطريقة هذه أيضا نفس الطريقة السابقة من حيث انك تعطي مُعرف (Identifier) الفرق بأنه سوف تحتاج الى استخدام Function معين يقوم بوظيفة نقل المعلومات اثناء عملية الـ Segue.
    هذا هو الـ Functionn الذي سوف تحتاج الى استخدامه:
    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {         }  
    اين تضعه ؟
    تضعه في الصفحة الحالية, فانت تريد نقل معلومة من صفحة 1 الى صفحة 2 فتضعه في صفحة 1
    هنا تحتاج تعرف معلومة :
     
    لنقل بيانات من صفحة الى اخرى سوف تحتاج الي متغير في الصفحة الأخرى لكن تحفظها به ولكي تتضح الصورة الان في صفحة 1 تريد نقل معلومة معينه الى صفحة 2.
     
    المعلومة هذه عباره عن String اذا سوف تقوم بإنشاء متغير من نوع String في صفحة 2 ومن ثم في داخل الـ Function السابق تستدعي المتغير وتحفظ القيمة الموجودة في صفحة1  الي المتغير في صفحة 2.
     
    نعود للشرح
     
    الان في الـ View Controller الاول نضيف Textfield فوق الـ Button ونربطه بملف الأكواد.
     
     
    ومن ثم في الـ View Controller الثاني نضيف Lable لكن قبل ذلك نضيف Class من نوع View Controller ومن ثم نحدد الـ View controller  الثاني في الـ Stroryboard
    ونختار الـ Class الذي أنشأناه بعدها نربط الـ Label بملف الاكواد
     
     
    اصبح لدينا في الـ View Controller الاول فقط Button و Textfield وفي الـ View Controller الثاني لدينا Label
     
    قبل العودة الى Function الذي اضفناه في ملف اكواد الـ View Controller الاول يتوجب علينا إضافة متغير من نوع String لذا نقوم باضافته
     
    فيصبح شكل الـ StroyBoard بالشكل التالي :

     
    ملف اكواد الـ View Controller الاول بالشكل التالي :

     
    import UIKit class ViewController: UIViewController {   @IBOutlet weak var textField: UITextField!    override func viewDidLoad() {     }             override func prepare(for segue: UIStoryboardSegue, sender: Any?) {       } }  
    ملف اكواد الـ View Controller الثاني بالشكل التالي :
     

     
    import UIKit class ViewController2: UIViewController { var  text:String?   @IBOutlet weak var label: UILabel!   override func viewDidLoad() { super.viewDidLoad()     label.text = text            } }  
    كما تلاحظ في الـ viewDidLoad اضفت السطر التالي
    label.text = text لجعل النص الذي سوف نجلبه من View Controller الاول يتم طباعته في View Controller الثاني
    نعودة الان الى Function
     
    الان نعود لملف اكواد الـ View Controller الاول
     
    ونقوم بكتابة التالي
        override func prepare(for segue: UIStoryboardSegue, sender: Any?){ if segue.identifier == "toView2" { if let vc = segue.destination as? ViewController2 {   vc.text = textField.text!      }       }   }  
    لاحظ التالي اول سطر
    segue.identifier  
    نكتب فيه مُعرف الـ segue كما قمنا بكتابته في الـ Stroyboard
     
    السطر الثاني نقوم بكتابة اسمك الكلاس الـ View Controller الثاني في حالتي اسمه ViewController2
    السطر الثالث نستدعي المتغير الذي أنشأناه في الـ View Controller الثاني ونربطه بمحتوى الـ Textfield لذا اثناء عملية الـ Segue سوف ينتقل النص الذي سوف نكتبه في حقل الـ Textfield الى الـ String الموجود في الصفحة الثانية ومن ثم في الـ View Controller الثاني سوف يتم طباعة الـ String في الـ Label
     
    نقوم بتشغيل التطبيق ونرى النتيجة :

     
    هذه الطريقة الصحيحة لنقل البيانات من View Controller الى اخر وهيا الطريقة الأكثر استخداماً
     
    الطريقة الرابعة :
     
    الطريقة هذه هيا عباره عن دمج طريقة الثانية مع الثالثة
    هناك أوقات تحتاج الى الانتقال الي View Controller اخر بعد حدث معين وفي نفس الوقت تريد فيها نقل البيانات الى الـ View Controller اخر
     
    في هذه اللحظة سوف تحتاج الى الطرقتين بحيث تستخدم
            performSegue(withIdentifier: "", sender: nil)  
    وفي نفس الوقت تستخدم
    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {    }  
    الـ Xcode ذكي بما فيه الكفايه
     
    اثناء تنفيذ سطر
            performSegue(withIdentifier: "", sender: nil)  
    سوف يلاحظ وجود Function
    override func prepare(for segue: UIStoryboardSegue, sender: Any?)  
    وبالتالي سوف ينتقل اليه أولا قبل تنفيذ الـ Segue وفقط للمعلومية prepare تعني تجهيز وبالتالي الـ Function يستعد لعملية الـ segue فيتم تنفيذ ما بداخله أولا !
    الان انتهينا من جزء الـ Segue

    --------------------------------------------------------------------------------------------------------------------------------------------------------------------------
     
     
    حان الوقت الانتقال الي موضوع الـ Unwind Segue وهو الموضوع الذي اردت التحدث عنه !
    كل شخص جديد يتعلم برمجة تطبيقات الـ iOS وتحديدا عند تعلمه الـ Segue وطريقة نقل البيانات من صفحة الى أخرى يخطئه هذا الخطأ !!
    اغلبية المبرمجين الجدد يخطئوا نفس الخطأ !
     
    ماهو الخطأ الذي يقع به الكثيرون ؟
     
    استخدام الـ Segue عند الرغبة في الرجوع الى الصفحة السابقة !
    في هذه النقطة سوف أوضح لك الخطأ ولماذا يعتبر مصيبه عند عمله !!
    افتراضاً نملك 4 صفحات و ٣ Button كل Button متصل بـ Segue ينقلك الى الصفحه الأخرى
     
    كما في الصورة التالية :
     

     
    قد تتسأل ماهي المشكلة في الصورة السابقة ؟
     
    الحقيقة هيا لحد الان لا توجد مشكلة !
    لكن في الصورة التالية تكمن المشكلة !
    المشكلة تكمن هنا عندما ينشأ المبرمج زر للرجوع الى الصفحة الرئيسية
     
    كما في الصورة التالية :
     

     
     
    ماذا فعل هنا ؟
     
    قام بربط زر الرجوع الى صفحة رقم 0 عن طريق الـ Segue !!
    هذا هو الخطأ الذي اردت التحدث عنه !
     
    هناك 3 مشاكل تسببه هذه المشكلة!
     
    أولا : كثرة الـ Segue ذهابا وعوده تسبب مشكله لذا المطور في انه لا يعلم هذا الـ Segue مرتبط بأي View Controller ؟
    ثانيا : مشاكل في الأداء واستهلاك موارد الجهاز بما يسبب بطئه عند استخدام التطبيق !!
    ثالثا : مشاكل في Auto Layout ! ، من ضمن المشاكل التي تسببها ، مشاكل في الـ Auto Layout من الامور التي سوف تلاحظها رغم وضعك القيود بشكل صحيح الا انه لايزال يظهر خطأ في القيود !
     
     
    لستُ مقتنعاً ؟
     
    سوف أقوم الان بتشغيل التطبيق واستخدامه ذهاباً وعودة
     
    شاهد الصورة التالية :

     
    الان قم بالتالي ، لا تقوم بإيقاف تشغيل المشروع
     
    واذهب لهذه الخانة :

     
    وحرك باستخدام الماوس لملاحظة هيكل المشروع
     
    لاحظ الصورة التالية :

     
    نقوم الان بعمل Debug لهيكل المشروع من ناحية واجهة المستخدم
     
    هل لاحظت كثرت الطبقات ؟
     
    المفترض أن تظهر فقط 5 صفحات 4 صفحات خاصة بالـ View Controller والصفحه 5 للزر الموجود في اخر صفحة بحكم اني قمت بالتوقف عندها ! ولكن الذي يظهر هو 13 طبقة !
     
    ما السبب ؟؟
     
    السبب هنا بسبب طريقة ربط الـ Segue
     
    ذكرت في بداية الموضوع الـ Segue يذهب من الصفحة 1 الى الصفحة 2 وليس العكس !
    عند عمل العكس هذا ما سوف يحدث !
     
    السبب عند عمل هذا الخطأ يقوم النظام على انشاء الصفحة مره أخرى وأخرى وأخرى كل مره يتم الضغط على زر الرجوع يتم انشاء الصفحة مره أخرى والنتيجة هي استهلاك موارد الجهاز !!
    الان قبل أن اشرح الطريقة سوف انفذ الطريقة الصحيحة ومن ثم سوف اشرحها بعد تغير الطريقة الى الطريقة الصحيحة
     
    لاحظ الصورة التالية في الـ Stroyboard:

     
    هل لاحظت ؟
    لايوجد Segue ، للعودة لصفحة الرئيسية !
     
    الان لاحظ الصورة التالية :

     
    ومن ثم لاحظ هيكل المشروع :
     

     
    اذا عملت مقارنه بين الصورتين هذه والصورتين السابقة
     
    سوف تلاحظ امرين
     
    أولاً : عند الضغط على زر العودة الصفحة الحالية تنزل الى الأسفل وتظهر الصفحة الرئيسية ! ، في حين عند عمل الطريقة الخاطئة تظهر الصفحة الرئيسية من الأسفل الى الأعلى !!
     
    ثانياً : هيكل المشروع اصبح 5 فقط ! لم يتغير ولم يزداد عدده !
     
    لماذا ؟
     
    عند عمل الطريقة الخاطئة ، تقوم على انشاء الصفحة من جديد في كل مره فكل ما زاد وقت استخدامك التطبيق زادت عدد الصفحات وزاد استهلاك موارد الجهاز في حين عند عمل الطريقة الصحيحة ، تقوم على اغلاق الصفحة الحالية والعودة للصفحة التي تريدها ، وبالتالي لا يوجد أي زياده !
     
    بعد فهم الفكرة واتضاح الفرق
     
    نعود الى شرح الطريقة الصحيحة :
     
    لكن قبلها اريد توضيح نقطه معينه اذا اردا الرجوع الصفحة السابقة السابقة هناك 3 طرق
     
    الطريقة الاولى : استخدم هذا السطر بداخل اقواس الـ Button
    dismiss(animated: true, completion: nil)  
    الزر ذا سوف يرجعك الى الصفحة السابقة فقط بما يعني اذا كنت في صفحة 3 سوف يرجعك الى صفحة 2 لا يمكنك العودة الى صفحة 0 او أي صفحة أخرى
     
    الطريقة الثانية : عند استخدام الـ Navigation Bar
    سوف يظهر زر العودة للصفحة السابقة بشكل تلقائي وأيضا مثل الطريقة الاولى سوف تعود فقط الى صفحة السابقة يمكن ملاحظتها في جميع تطبيقات النظام مثال تطبيق الاعدادات عندما تذهب لقسم عام او General سوف تلاحظ وجود زر في الأعلى يرجعك الى صفحة الرئيسية للإعدادات ، هذه تتم بشكل تلقائي بدون تدخل منك
     
    معلومة :
     
    لاحظ الصورة التالي :
     

     
     
    سوف تلاحظ عند استخدام الـ Navigation Bar واختيار نوع Show سوف تكون عملية الانتقال الـ Segue من اليمين الى اليسار والعوده سوف تكون العكس في حين اذا اخترت Present Modally سوف يظهر من الأسفل الى الأعلى والعكس عندها يعود للصفحة السابقة ! كما الحال في تطبيقنا
     
    لكن بدون استخدام الـ Navigation Bar الـ Show يظهر كالـ Present Modally
     
    الطريقة الثالثة :
     
    الطريقة هذه تدعى Unwind Segue
     
    ما الذي يميزها ؟
    الذي يميزها هو التالي :
     
    أولا : يمكنك العودة الى أي صفحة تريدها وليس ملزماً بالعودة الى الصفحة السابقة فقط !
    بما يعني كما هو حال مثالنا سوف يمكنك العودة من صفحة 3 الى صفحة 0 بشكل مباشر
     
    ثانيا:
    يمكنك ارجاع بيانات من الصفحة الحالي الى الصفحة السابقة !
    بما يعني سوف تستطيع ارجاع بيانات موجوده في صفحة 3 الى صفحة 0 او أي صفحة تريدها !!
    معلومة :

    الـ Unwind Segue تعني فك الـ Segue وبالتالي يجب أن يكون هناك Segue لتستخدم هذه الطريقة !
    اذا استخدمتها بدون عمل Segue مسبقاً بين 2 من الـ View Controller او اكثر ، سوف يسبب Crash للتطبيق
     
    الان نبدأ في شرح الطريقة:
     
    كما شرحت الـ Segue سوف اقسم الـ Unwind Segue الى عدة طرق
     
    طريقة الأولى :
    ترغب فقط بالعوده الى صفحة معينه بدون ارجاع أي بيانات
    وبالتالي تحتاج تفهم هذه النقطة :
    اذا رغبت بالرجوع الى صفحة معينه سوف تحتاج الى كتابة كود في صفحة التي تريد الرجوع لها هنا نحن نريد العوده من أي صفحة الى الصفحة الرئيسية View Controller 0
    فسوف نقوم بكتابة الكود التالي :
    @IBAction func unwindToHome(segue:UIStoryboardSegue) {     }  
    في ملف اكواد  View Controller 0
     
    ملاحظة :
    -لا تحتاج الى كتابة أي اكواد في الداخل الاقواس ! على الأقل في الوقت الحالي !
    - تستطيع تسمية الـFunction بأي اسم تريده ، انا قمت بتسميته unwindToHome
     
    ومن ثم ننتقل الى الـ Storyboard ونفعل التالي مع صفحات 1 و  2و 3
    شاهد الصورة :

     
    فقط هذا كل ما نحتاج الى فعله !
    قم بتشغيل التطبيق وسوف تجده يعمل بمجرد الضغط على زر Return to Home سوف تجده يعود الى الصفحة الرئيسية وهيا View Controller 0
     
    الطريقة الثانية :
    ماذا اذا اردت تنفيذ امراً معيناً قبل ان يحدث الـ Unwind Segue ؟
    تحتاج الطريقة دي في بعض الحالات ، مثلا صفحة Login المستخدم بعد ما يكتب اسم المستخدم وكلمة السر ويضغط زر Login سوف تحتاج الى الاتصال بالسيرفر وتتأكد انه المستخدم موجود في قاعدة بياناته وبعد التأكد ، تغلق الصفحة باستخدام  Unwind Segue وتحوله الى الصفحة الرئيسية
    معلومة :
    ما سبق ذكره مجرد مثال ، لأنه تستطيع أيضا استخدام سطر
    dismiss(animated: true, completion: nil)  
    لأغلاق الصفحة فالمثال السابق يعتبر كطريقة أخرى لتنفيذ نفس الأمر, على أي حال الطريقة مشابه لطريقة الـ Segue من حيث تحتاج الى إعطاء مُعرف.
    نعود للشرح :
     
    اهم نقطه هنا هو فصل الربط الذي عملته في الطريقة الاولى بين الـ Button و Exit ولكن لا تحذف الـ  Function الذي كتبناه في View Controller 0
     
    @IBAction func unwindToHome(segue:UIStoryboardSegue) {}  
    في هذه الطريقة سوف نربط الـ Viewcontroller نفسه مع الـ Exit
     
    شاهد الصورة التالية :
     

     
     
    ومن ثم سوف نعطي للـ Unwind Segue مُعرف
    شاهد الصورة التالية :
     

     
    قمت باعطاء مُعرف home الان قم بربط الـ button مع ملف الاكواد ومن ثم استخدم نفس السطر الذي استخدمناه في الـ Segue
    performSegue(withIdentifier: "home", sender: nil)  
    بالطريقة هذه تستطيع عمل أي امر تريده قبل حدوث الـ Unwind Segue
     
    الطريقة الثالثة :
     
    في هذه الطريقة الامر عائد اليك ، يمكنك عمل الطريقة الاولى وتنفذ الطريقة هذه معها او استخدام الطريقة الثانية مع هذه الطريقة.
    فالطريقة الثالثة تشرح طريقة نقل البيانات من الصفحة 3 الى صفحة 1
     
    بنفس درجة حاجتك الى استخدام الى الـ Segue لنقل البيانات أيضا سوف تحتاج استخدام Unwind Segue لنقل البيانات
     
    من امثله استخدام الـ Unwind Segue لنقل البيانات, تطبيقات المحادثه مثل الـ Whatsapp عند استخدامك للتطبيق لأول مره يطلب منك اختيار رمز دولتك فعند الضغط عليه يوجهك لصفحة تختار فيها دولتك ومن ثم عند اختيار دولتك يعود الى صفحة كتابة رقم جوالك هنا حدث Unwind Segue بحيث تم نقل رمز الدولة من صفحة أخرى الى صفحة السابقة
     
    نعود للشرح :
     
    هل تذكر ماذا فعلنا عند نقل معلومات او بيانات من صفحة 1 الى الصفحة 2 باستخدام الـ Segue ؟ الطريقة مشابهه لحد ما ! نحن نريد نقل بيانات من صفحة 3 الى صفحة 0 لذا قبل أنا نبدأ سوف نفعل التالي:
    سوف نضيف Textfield في الصفحة 3 ونضيف Label في صفحة 0 الي هيا الصفحة الرئيسية الذي نريد الرجوع اليها ونقوم بربطهم بملف الاكواد
    شاهد الصورة التالية :

     
    الان حان الوقت للكتابة في Function
    @IBAction func unwindToHome(segue:UIStoryboardSegue) { }  
    الان كما قلنا سابقا نريد نقل النص من الـ Textfield الموجود في View Controller 3 الى الـ Label الموجود في View Controller 0 لذا نقوم بكتابة التالي :
     
     @IBAction func unwindToHome(segue:UIStoryboardSegue) { if segue.identifier == "home" {       let vc = segue.source as! ViewController3 label1.text = vc.text1.text       }      }  
    اول شيء نقوم بالتأكد من اسم المُعرف في حال كنت تتبع الطريقة الاولى لن يكون هناك اسم معرف الا اذا وضعته باختيارك لذا يمكنك حذف هذا السطر
    if segue.identifier == "home" {}  
    وحتى أيضا اذا اتبعت الطريقة الثانية لن تحتاج هذا السطر! الا اذا كنت تريد ارجاع بيانات من صفحتين فأكثر فهنا يتوجب عليك التمييز بينهم عن طريق التأكد من اسم المُعرف على أي حال اذا لاحظت فالكود مشابه جدا من طريقة الـ Segue .
    في الـ Segue نقوم بكتابته بداخل Function يسمى prepare وهنا بداخل Function الـ Unwind وأيضا في الـ Segue نكتب
    segue.destination as اسم الكلاس الذي نريد الانتقال اليه وفي الـ Unwind Segue نكتب
    segue.source as اسم الكلاس الذي سوف نعود منه لذا تقريبا نفس الفكرة الاختلاف في كلمة destination و source
    اخيراً قم بتشغيل التطبيق
     
    وشاهد النتيجة في الصورة التالية :

     
    وبكذا انتهينا من هذا الموضوع
     
    في هذا الموضوع فهمت الطريقة الصحيحة لنقل البيانات بين الـ View Controllers وماهي الاستخدامات الخاطئة والفريق بين Segue و Unwind Segue.
    قد تتسأل هل هذه هيا الطرق الوحيدة لنقل البيانات ؟
    الاجابه هيا لا ، ما تم شرحه في الموضوع هو طرقتين لنقل البيانات Segue و Unwind Segue وهما اشهر واكثر طرقتين لنقل البيانات بين الـ View Controllers استخداماً
    لكن هناك طرق أخرى أيضا !
     
    مستوى المقال: متوسط
  2. بسم الله الرحمن الرحيم
     
    سنتعرف في هذا الدرس على طريقة انشاء تطبيق يدعم تعدد اللغات بحسب لغة الجهاز، سنعتمد اللغتين العربية والانجليزية في هذا التطبيق.
     
    سنبدأ أولا باضافة جميع اللغات التي نريد دعمها في تطبيقنا
    نذهب الى Project Navigator

    ثم نقوم باضافة اللغات المطلوبة من الأسفل

    نلاحظ تقسيم الملفات الى لغتين كما في الصورة

    االآن سنقوم بانشاء ملف من نوع String لنخزن فيه جميع الStrings باللغتين العربية والانجليزية
    اضغط على File > New > File واختر النوع String كما في الصورة

    تأكد من تسمية الملف باسم "Localizable" تماما كما هو ليتعرف عليه الxCode بشكل صحيح
    الآن نختار الملف الجديد من اليسار، ومن قائمة الFile Inspector نضغط على Localize ونختار اللغة الانجليزية مبدئيا

    الآن نختار اللغة العربية أيضا لنقوم بتقسيم ملف الLocalizable.strings الى لغتين

    قم باضافة الStrings المطلوبة الى الملفين بالطريقة التالية

    ليقوم الxCode بعمل Build تأكد من:
    كتابة الkey بشكل موحد بين اللغتين العربية والانجليزية وضع علامة ال= بين الkey والvalue كتابة الvalue بين علامتي تنصيص "" انهاء السطر بSemi-Colon ;  
     
    لنرى طريقة استدعاء الStrings  من ملف Localizable قمت بعمل الواجهة البسيطة التالية:

    وقمت بربط الOutlets والActions كالتالي:

     
    الآن اضف الكود التالي في زر اللغة الانجليزية:
    let path = Bundle.main.path(forResource: "en", ofType: "lproj") let bundle = Bundle.init(path: path!)! as Bundle nameLbl.text = bundle.localizedString(forKey: "WebsiteName", value: nil, table: nil) والتالي لزر اللغة العربية:
    let path = Bundle.main.path(forResource: "ar", ofType: "lproj") let bundle = Bundle.init(path: path!)! as Bundle nameLbl.text = bundle.localizedString(forKey: "WebsiteName", value: nil, table: nil)  
    في السطر الأول: قمنا بتعريف الpath الذي سيوصلنا لكل من ملفات اللغة العربية والانجليزية
    (يمكنك معرفة الResource والType من قائمة الFile Inspector عند الضغط على ملفي العربية والانجليزية)

    في السطر الثاني قمنا بتعريف كل من ملفات اللغتين كVariable يحمل الاسم bundle
    في السطر الثالث قمنا باستدعاء الString المطلوب باستخدام الميثود localizedString(_:String,_:String,_:Strint( 
     
    والآن عند تجربة البرنامج نرى النتيجة التالية (صورة GIF):
     

     
    حتى الآن كنا نحدد ملف اللغة الذي نريد استدعاء الString منه
    والآن سنقوم بتغيير النص اعتمادا على لغة الجهاز باستخدام زر واحد فقط
    لنرى ذلك قمت بتغيير الStoryboard ليحتوي على زر واحد فقط، وقمت باضافة الoutlets والactions كالتالي:


     
    والآن قم باضافة السطرين التاليين للميثود viewDidLoad()
    let btnTitle: String = NSLocalizedString("ButtonText", comment: "") languageBtn.setTitle(btnTitle, for: .normal) والسطر التالي للميثود الخاصة بالbutton action
    nameLbl.text = NSLocalizedString("WebsiteName", comment: "") في هذه الاكواد، قمنا باستعمال الميثود NSLocalizedString لاستدعاء الString المناسب بحسب لغة الجهاز
    لتجربة البرنامج سنقوم بتشغيله على جهاز بلغة انجليزية، ثم سنحولها للعربية ونعيد التجربة
    (صورة GIF):


     
     
    وصلنا الى ختام الدرس، أستودعكم الله الذي لا تضيع ودائعه.
    مستوى المقال: متوسط
  3. ماهو ال Model View Controller (MVC)؟
     
    MVC هو مبدأ او نموذج معماري architectural pattern يستخدم للتعامل مع واجهات المستخدم في تطبيقات iOS.
    هذا المبدا مهم ان تحاول فهمه لانه اساس برمجة تطبيقات ال iOS . فعندما تبدأ برمجه مشروعك عليك تقسيمه الى ثلاثة اقسام كالتالي
    Model : عباره عن مجموعة البيانات أو data في تطبيقك . مثلا لو لدينا تطبيق لعرض موديلات السيارات.  كل المعلومات عن السياره مثل الماركه, اللون وغيرها تعتبر بيانات ويتم تخزينها في كلاس.
    View : عباره عن الواجهه الظاهره لمستخدم تطبيقك.
    في xcode تعتبر  ال view هي العناصر المستخدمه في  storyboard  واللتي نقوم بربطها بالكود مثل UILabel, UIView and UIImage.
    Controller : هو الرابط  او حلقة الوصل بين ال model & view اي بين البيانات والواجهات . فهو يقوم بتزويد ال  view  بالبيانات اللتي تحتاجها من model. ويقوم بتحديث ال model حين يدخل  المستخدم بيانات جديده الى ال view
    هذا الجزء يعتبر الدوال او method او ال action المستخدمه في برمجه العناصر كالازرار مثلا.
     
    الان نستعرض مثال بسيط لشرح الفكره وتعميق فهمها.( من هنا تستطيع البدء والبحث عن المزيد عن هذا المفهوم وتطبيقه).
    لنفرض ان لدينا مشروع  يستعرض ماركة و لون السياره . الان وفقا لهذا المفهوم سنقسم كالتالي
      Model: ننشئ class  نسميه car ونضع فيه بيانات السياره (ماركه brand, لون  color).

    View: هي واجهة المستخدم سننشئها كالتالي:

     
    وننشئ outlet لكل من ال labels كالتالي

     
    Controller: وهي الاوامر المستخدمه لربط عناصر الواجهه بالبيانات.
    - انشأنا object  اسمه car1 من كلاس car حتى نتمكن من الوصول الى خصائص الكلاس (الماركه و اللون ).
    - باستخدام ال object المسمى car1 وصلنا الى خاصية brand ووضعنا فيها قيمه lexus . وخاصية color وضعنا فيها قيمه Red
    - الان مرحله الربط بين  عناصر الواجهه والبيانات فالامر Brand.text يشير الى ان نضع في ال label الموجود في الواجهه  النص الموجود في خاصية Car1.Brand وهو في هذه الحاله lexus. نفس الامر لعنصر اللون.  
     

     
    الشكل النهائي للكود في الصوره التاليه لكن هناك ملاحظه يفضل أن تنشئ ملف سويفت منفصل لتضع فيه كلاسات ال model .

     
    الان نقوم بتشغيل التطبيق لرؤيه النتيجه
     

     
    اتمنى أنني وفقت في شرح هذا المفهوم المهم بطريقه سهله وبسيطه ـ شكرا لكم ولعالم البرمجه
     
     
    مستوى المقال: متوسط
  4. بسم الله الرحمن الرحيم
     
    كما نعرف فإن لغة السويفت Swift تدعم الأنواع الأساسية من المتغيرات مثل : Int - Float - Double - Bool - String - Character
     
    كما تدعم أنواع مختلفة أخرى ، وتدعم ٣ أنواع أساسية تُسمى بـ ( Collection Types )  وهم :
    المصفوفات Arrays - القواميس Dictionaries - المجموعات Set
     
    سأتحدث في هذه المقالة عن ( القواميس Dictionaries ) ، وسأتكلم فيها عن :
     
    ماهي القواميس Dictionaries ؟ كيفية تعريف وإنشاء القواميس Dictionaries : إنشاء قواميس فارغة . إنشاء قواميس بقيم إبتدائية . إضافة عناصر جديدة للقواميس . إزالة قيم القواميس .  
    ماهي القواميس Dictionaries ؟ كما قلنا سابقاً فإن القواميس أو ماتعرف بـ Dictionaries هي إحدى أنواع المتغيرات في لغة السويفت Swift ، يُستخدم هذا النوع في تخزين عدد من القيم (غير المرتبة unorderd) في متغير واحد ،ويتم تخزين كل قيمة باستخدام مُعرف فريد يُعرف بـ ( المفتاح Key) وذلك ليسهل الوصول لهذه القيمة عند الحاجة إليها .
     
    ولتسهيل فكرة القواميس Dictionaries قمت بعمل رسم توضيحي يشرح فكرتها :

    في الرسمه السابقة نرى بأن لدينا ( متغير ) من نوع dictionary بحيث احتوى على ( ٣ مفاتيح ) وكل مفتاح يشير إلى ( قيمة ) ، بحيث نستطيع الوصول مثلاً (للقيمة ١) فقط عن طريق ( المفتاح ١) و (القيمة ٢) عن طريق (المفتاح ٢) و (القيمة ٣) عن طريق ( المفتاح ٣) وهكذا . وبالتالي استطعنا في متغير واحد تخزين أكثر من قيمة والوصول لهذه القيم باستخدام المفاتيح Keys .
     
    سألخص لك الكلام السابق على شكل نقاط :
    القواميس Dictionaries  إحدى أنواع المتغيرات في لغة السويفت Swift . تقوم بتخزين عدد من القيم غير المرتبة unorderd داخل متغير واحد . يتم الوصول لكل قيمة من قيم القواميس عن طريق معرف فريد يعرف بالمفتاح Key .  
    اتمنى أن تكون فكرة القواميس Dictionaries أصبحت واضحة وإن لم تكن كذلك فبإذن الله ستتضح لك أكثر مع الأمثلة 😊 
     
    كيفية تعريف وإنشاء القواميس Dictionaries : قبل أن نقوم بالتعرف على طريقة إنشاء القواميس سأذكر لك عدّة نقاط مهمة جداً يجب عليك أن تضعها في الاعتبار قبل تعريف أي Dictionary :
     
    أولاً : أسماء المفاتيح Keys يجب أن تكون فريدة uniqe .
    ثانياً : في المتغير من نوع Dictionary يجب أن تكون ( كل ) المفاتيح key من نفس النوع ، و ( كل ) القيم من نفس النوع ، مثلاً أن تكون كل المفاتيح من نوع Int والقيم من نوع String فهذا صحيح لأن كل المفاتيح من نفس النوع وهو Int و كل القيم من نفس النوع وهو String .
    ثالثاً : من المسموح أيضاً أن تكون جميع المفاتيح وجميع القيم من نفس النوع مثلاً أن تكون المفاتيح والقيم من نوع String .
     
    والآن فلنبدأ بإنشاء القواميس Dictionaries !
     
    1. إنشاء قواميس فارغة :
    لتعريف القواميس نستخدم مايعرف بالأقواس المربعة [ ] لتحديد نوع المفاتيح والقيم للمتغير :

    مثال (١) :
     
    var  x = [Int : String] ( )  
    في المثال السابق قمنا بتعريف المتغير x وعرّفنا المفاتيح من نوع Int والقيم من نوع String ( وليس العكس ) و استخدمنا الأقواس التالية : ( ) لنقول بأن المتغير هذا لايحتوى على أي قيمة إلى الآن .
     
    مثال (٢) :
    var y = [String : String] ( )  
    قمنا بتعريف المتغيرy وعرّفنا المفاتيح من نوع String والقيم أيضاً من نوع String ،و استخدمنا الأقواس التالية : ( ) لنقول بأن المتغير هذا لايحتوى على أي قيمة إلى الآن .
     
    2. إنشاء قواميس بقيم إبتدائية :
    ولإضافة قيم للقواميس سنتبع الصيغة التالية :

     
    سنقوم الآن بتعديل الأمثلة السابقة ووضع قيم ابتدائية لها، وسيكون ذلك كالتالي :
    مثال (١) :
     
     var x : [Int : String] =  [  1 : "A" ,  2: "B" ,  3 : "C" ]  
    المتغير x يحتوى على المفاتيح التالية : المفتاح 1 والذي يشير للقيمة A والمفتاح 2 والذي يشير للقيمة B والمفتاح 3 والذي يشير للقيمة C .

    مثال (٢) :
     
    var y : [String : String] = [  "One" : "A" , "Two" : "B" , "Three" : "C" ]  
    المتغير y يحتوي على المفاتيح التالية : المفتاح One والذي يشير للقيمة A والمفتاح Two والذي يشير للقيمة B والمفتاح Three والذي يشير للقيمة C .

    من الأمثلة السابقة نلاحظ مايلي :
    لتعيين القيم للمتغير نستخدم ( = ) . نضع القيم بين الأقواس كالتالي :  ] المفتاح : القيمة [ ونفصل بينهم بفاصلة ( , ) . المفاتيح والقيم لها نفس النوع الذي تم تعريفه ، غير ذلك سيظهر لنا خطأ error. ( كل ) المفاتيح في المتغير الواحد كانت من نفس النوع و ( كل ) القيم أيضاً كانت من نفس النوع .  
    إضافة عناصر جديدة للقواميس : من المهم معرفة أن القواميس لا تستخدم الأمر insert أو الأمر append لإدراج عناصر جديدة مثل ماتفعل المصفوفات ،والسبب في ذلك كما ذكرنا بداية هذه المقالة بأن القواميس تتميز بأنها غير مرتبة unordered بعكس المصفوفات التي تتميز بأنها مرتبة orderd 
     
    لذلك لادراج قيم في القواميس سنتبع الطريقة التالية :

    مثال (١) :
     
    x [ 4 ] = "Four"  
    هنا أصبح لدينا في المتغير x مفتاح (4) وقيمته هي  . Four
     
    مثال (٢) :
     
    y ["Four"] = "D"  
    هنا أصبح لدينا في المتغير y مفتاح Four)) وقيمته هي  . D
     
    إزالة قيم القواميس : كما عرفنا فإن القيم في القواميس مرتبطة بمفتاح key خاص فيها لذلك عند حذف أي قيمه فإننا نتعامل مع المفتاح الخاص فيها وذلك بجعله يساوي nil :
     
    Variable-Name [Key] = nil  
    مثال (١) :
     
    x [ 4 ] = nil  
    مثال (٢) :
     
    y ["Four"] = nil  
     
    الطريقة الأخرى وهي استخدام الدالة( removeValue (ForKey :Key_name ، هذه الدالة تقوم بحذف القيمة المطلوبة إن كانت موجودة أو تسترجع القيمة nil في حالة لم تكن موجودة .
     
    Variable-Name.removeValue (ForKey : Key_name)  
    مثال (١) :
     
    x.removeValue (ForKey :4) مثال (٢) :
     
    y.removeValue (ForKey :"Four")  
     
    وصلنا لنهاية المقالة أتمنى أن أكون قد وفقت في إيصال المعلومات بشكل واضح وسهل للجميع ،وبإذن الله سيكون هناك جزء ثاني لهذه المقالة نتعمق فيها أكثر في القواميس .
    مستوى المقال: متوسط
  5. من أكثر الأسباب التي تؤدي الى زيادة معدل تقييم تطبيقك في متجر التطبيقات هو عن طريق سؤال المستخدم من داخل التطبيق !
     
    هناك طرق كثيره ومكتبات متنوعه لفعل ذلك ووظيفتها تكمن في سؤال المستخدم ما اذا اعجبهم التطبيق ويريد كتابة مراجعة له ، فيتم تحويلهم الى متجر التطبيقات
     
    ولكن اليوم سوف نتحدث عن API آبل اضافته في تحديث iOS 10.3
    يطلق عليه SKStoreReviewController
     
    الفكرة في هذا الـ API هو سؤال المستخدم من داخل التطبيق بدون الحاجة الى تحويلهم الى متجر التطبيقات !
    لكن العيب الوحيد هو عدم المقدرة على جعلهم يكتبوا مراجعة للتطبيق ، فقط يستطيعوا تقييم التطبيق عن طريق النجوم .
     
    وطبيعة الحال هناك عدة شروط :
     
         يجب الا يستخدم الـ API بداخل ViewDidLoad  أو ViewWillApper او غيرهم بدون وجود Logic ، فانت لا تريد أن يقيم المستخدم التطبيق بمجرد فتحه لأول مره وهو لم يستخدمه بعد !     يجب ان لا يستخدم الـ API بداخل Button او يتطلب أي Action من المستخدم ، قد يسبب ذلك في رفض تطبيقك اذا وضعته بداخل Action !    تذكر بأن كل شيء يتم تلقائيا اعتماداً على النظام ، من حيث ظهور رسالة طلب التقييم من عدمها ! لهذا السبب وجد الشرط السابق    أهم شرط هو رسالة التقييم سوف تظهر فقط 3 مرات في السنه لكل مستخدم .    اثناء فترة التطوير الرسالة سوف تظهر بشكل دائم     عند ارسال تطبيقك كنسخه تجربيه باستخدام TestFlight الرسالة لن تظهر ! ، بمعنى أخرى سوف تظهر فقط عند نشر تطبيقك في متجر التطبيقات .  
    ومن النصائح اذا اردت تقييم إيجابي للتطبيقك ، اطلب ظهور رسالة التقييم اذا فعل المستخدم امراً إيجابياً !
    ولا تقاطع المستخدم عند عمل مهمه معينه !! ، ولكن اسأله بعد الانتهاء من مهمة محددة
     
    لذا من الأمثله :
     اذا التطبيق متجر الكتروني اطلب رسالة التقييم بعد إتمام الشراء. اذا كان التطبيق لعبة ، اطلب رسالة التقييم بعد تحقيق سكور عالي في اللعبة أو بعد انتهاء من مرحلة او عدة مراحل في اللعبة . اسأله بعدد عدد مرات معينه من استخدام التطبيق وليس من أول مره !
    بحيث تسأل المستخدم لتقييم تطبيقك في وقت يكون في مزاج جيد !  
    اذا كيف يتم استخدامه ؟
     
    كما ذكرت سابقا الأمر بيد المطور
     
    بصورة مختصرة :
     
    الذي يتطلبه هو فقط استدعاء
    import StoreKit  
    في داخل الـ ViewController الذي يريد ظهور الرسالة عليه
     
    ومن ثم استخدام السطر التالي ، في أي مكان يرده المطور
    SKStoreReviewController.requestReview()  
    بصورة افضل هو حساب عدد مرات فتح التطبيق وإظهار الرسالة بعد عدد مرات محدده
    من دراسة قراءتها بأن افضل وقت هو بعد 5 مرات ويفضل بعد 10 مرات
    ولكن ليس أقل من ذلك ، بهذا الوقت بعد 5 مرات او 10 مرات تكون متأكد بأن المستخدم يستخدم التطبيق باستمرار .
     
    اذا كيف تحسب وقت استخدام المستخدم للتطبيق ؟
     
    عن طريق الاستفادة من UserDefaults
     
    اذا لا تعلم ماهو UserDefaults
    فهو طريقة لحفظ البيانات بشكل دائم ويستخدم مع البيانات البسيطة
    كحفظ رقم Integer مثلا
    او حفظ حالة الـ Switch اذا مفعل او مغلق الخ
     
     
    وبالتالي الفكرة هيا بوضع عدد محدد كمتغير وفي هذا المثال سوف نضع المدة 4
    لأننا نريد أن تظهر رسالة التقييم بعد خامس مره ، ولأنه العد يبدأ من 0
    فالرقم 4 = خامس مره
    0 , 1 , 2 , 3 , 4
     
    ونضع متغير اخر يحسب عدد مرات فتح التطبيق (ViewController)
    ومن ثم نعمل مقارنه اذا وصلت عدد المرات الى 5 مرات تظهر الرسالة
    اذا لم يوصل نزود قيمة المتغير ونحفظه في UserDefaults
     
     
     
    الكود يصبح بالشكل التالي :

     
    import UIKit import StoreKit class ViewController: UIViewController {     let minimumRunCount = 4     let userDefaultsKey = "minimumRunCountUserDefaultsKey"     override func viewDidLoad() {         super.viewDidLoad()         if ShowStoreReview() {             SKStoreReviewController.requestReview()         }     }        func ShowStoreReview() -> Bool {         let count = UserDefaults.standard.integer(forKey: userDefaultsKey)         if count >= minimumRunCount {             return true         } else {                        UserDefaults.standard.set((count + 1), forKey: userDefaultsKey)         }         return false     } }  
    اذا كما ذكرنا سابقا
     
    في البداية عرفنا الحد الادنى قبل ظهور الرسالة في  minimumRunCount  
    عرفنا الـ Key للـ userDefault
    يمكنك كتابة أي شي تريده
     
    بالنسبة الى UserDefaults.standard.integer
    القيمة سوف تكون 0 بشكل تلقائي عند استخدامه
    وهذا ما نريده
    لذا قيمة count سوف تكون 0  في اول مره
     
    ومن ثم عملنا مقارنة اذا كانت قيمة count اكبر او يساوي قيمة minimumRunCount  
    تظهر ترجع قيمة true وبالتالي تظهر الرسالة
     
    اذا لم تكون تساوي او اكبر من قيمة  minimumRunCount  
     
    نزود واحد على قيمة count ونحفظها في userDefault
     
    لذا في المره الثانية يفتح فيها التطبيق تكون قيمة count بـ 1
    عوضاً عن 0
     
    وهكذا
     
    وعندما توصل لقيمة 4
    تظهر الرسالة
     
    صورة الرسالة :

     

     
    هذه من الأمثلة التي تستطيع الاستفادة منها
    تستطيع تحسينها حسب احتياجك
     
    اريد أن أوضح نقطة اخيره وهيا الـ SKStoreReviewController
    فقط يظهر لمستخدم نظام 10.3 فأعلى
     
    لذا تستطيع إضافة السطر التالي في ViewDidLoad
     

     
            if #available(iOS 10.3, *) {             SKStoreReviewController.requestReview()                     } else {  وهنا ضع الطريقة القديمة لتحويله الى متجر التطبيقات//         }  
    فيصبح الكود  ViewDidLoad النهائي بالشكل التالي :

     
        override func viewDidLoad() {         super.viewDidLoad()         if ShowStoreReview() {             if #available(iOS 10.3, *) {                 SKStoreReviewController.requestReview()                          } else {             }         }     }  
     
    واخيراً اريد أن اذكر بأن هناك مطور جرب استخدام SKStoreReviewController
    في تطبيقه ، وادى ذلك الي حصوله على 200 تقييم في خلال 8 أيام !
     
    لذا ينصح بشده باستخدام SKStoreReviewController في تطبيقاتكم
     
    فهناك عدد كبير من التطبيقات في المتجر لا تملك أي تقييم !
     
    لذلك آبل إضافة هذا الـ API في نظامها
     
     
    مستوى المقال: محترف
  6. بسم الله الرحمن الرحيم
     

    مقدمة
    عادة يتم استخدام الUIAlertController لعرض نافذة تحذيرية للمستخدم، تحتوي على رسالة وازرار لاتخاذ اجراءات بناء عليها.
    يمكن استخدامها أيضا لتمكين المستخدم من ادخال بيانات تسجيل دخول او حساب جديد، عرض بيانات للمستخدم، أو عرض المزيد من الاعدادات في نافذة خارجية.
    منذ قدوم iOS9، أبل قامت بالغاء الكلاس القديم UIAlertView واستبدلته بUIAlertController، حيث لم تعد تحتاج لضبط الdelegatesـ وتستطيع الآن تخصيص النافذة كما تشاء.
    هناك نوعين من الUIAlertController:
    1- Alert UIAlertController

    2- ActionSheet UIAlertController

     
    والآن سنرى كيفية انشائها وتخصيصها
    (لانشاء النوافذ المطلوبة، يمكنك تضمين جميع الأكواد القادمة في داخل IBAction او TableViewCell أو حتى في viewDidLoad لتقوم بتنفيذ الكود مباشرة) 
     
    - نافذة Alert تحتوي على TextField:
    أول نافذة تحذيرية سنقوم بانشائها، تحتوي على textfield واحد، بالاضافة الى زرين submit و cancel
    سنبدأ أولا باضافة الأسطر التالية:
    let alert = UIAlertController(title: "AlertController Tutorial", message: "Submit some text", preferredStyle: .alert) // Submit button let submitAction = UIAlertAction(title: "Submit", style: .default, handler: { (action) -> Void in // Get 1st TextField's text let textField = alert.textFields![0] print(textField.text!) }) // Cancel button let cancel = UIAlertAction(title: "Cancel", style: .destructive, handler: { (action) -> Void in }) في الثلاث أسطر الأولى، قمنا بانشاء UIAlertController، وحددنا عنوانه والرسالة المضمنة فيه، وحددنا نوعه ليكون alert.
    تاليا قمنا بانشاء أول زر submitAction، وخصصنا عنوانه وستايله، وفي بلوك الhandler الأخير أضفنا الأوامر التي نرغب بتنفيذها عند الضغط على هذا الزر
    أخيرا قمنا بانشاء زر cancel بستايل destructive. ليكون أحمر اللون
     
    الآن بقي لنا أن نضيف هذين الزرين الى النافذة التي أنشأناها أولا، ومن ثم نعرض النافذة للمستخدم.
    ولكن قبل هذا، لا ننسى أن ننشئ و نضيف الTextField الى النافذة، فنكمل باضافة الكود التالي:
    // Add 1 textField and customize it alert.addTextField { (textField: UITextField) in textField.keyboardAppearance = .dark textField.keyboardType = .default textField.autocorrectionType = .default textField.placeholder = "Type something here" textField.clearButtonMode = .whileEditing } // Add action buttons and present the Alert alert.addAction(submitAction) alert.addAction(cancel) present(alert, animated: true, completion: nil) في الأسطر الأولى قمنا بانشاء وتخصيص واضافة الTextField في خطوة واحدة.
    ثم أخيرا قمنا باضافة الزرين السابق انشاؤهما وقمنا بعرض الUIAlertController عن طريق استدعاء الميثود present
     
    النتيجة:

     
     
    - نافذة ActionSheet تحتوي على عدة خيارات:
    بطريقة مشابهة جدا لنوافذ الAlert، سنقوم بانشاء نافذة ActionSheet. أولا سنقوم باضافة الكود التالي:
    let alertController = UIAlertController(title: "Action Sheet", message: "What would you like to do?", preferredStyle: .actionSheet) let sendButton = UIAlertAction(title: "Send", style: .default, handler: { (action) -> Void in print("Send button tapped") }) let deleteButton = UIAlertAction(title: "Delete", style: .destructive, handler: { (action) -> Void in print("Delete button tapped") }) let cancelButton = UIAlertAction(title: "Cancel", style: .cancel, handler: { (action) -> Void in print("Cancel button tapped") }) قمنا أولا بانشاء UIAlertController من نوع ActionSheet، ثم أنشأنا عدة أزرار بستايلات مختلفة وكل زر يحتوي على بلوك الactions الخاص به.
    الآن سنضيف الأزرار الى الUIAlertController ومن ثم سنعرضها:
    alertController.addAction(sendButton) alertController.addAction(deleteButton) alertController.addAction(cancelButton) present(alertController, animated: true, completion: nil)  
    النتيجة:

     
    لاحظ أن ستايلات الأزرار تختلف بالشكل: 
    defaults. يعطيك شكل زر Send now الطبيعي
    destructive. يضيف اللون الأحمر ويستعمل عادة لأوامر الحذف لتنبيه المستخدم
    cancel. يعزل الزر عن باقي الأزرار ويستعمل عادة لزر الالغاء
     
     
    وهنا نصل الى ختام موضوعنا، نلقاكم على خير باذن الله
    سبحانك اللهم وبحمدك أشهد أن لا اله إلا أنت، استغفرك وأتوب اليك
    مستوى المقال: متوسط
  7. في  البرمجة بشكل عام المتغيرات Variabals والثوابت Constant موجودة بهدف ان تتيح لك تخزين البيانات لاعادة استخدامها مره اخرى في البرنامج. وعند تعريفك لمتغير جديد في البرنامج فانت ستقوم بربط اسم محدد مثل name او age بقيمة محددة من نوع محدد. 
     
    تسمية المتغيرات
    لديك كامل الحرية في تسمية المتغيرات ماعدا بعض القيود مثل التالية:
    لا تبدآ برقم لا تتضمن مسافات لا تتضمن رموز عمليات رياضية لا تستخدم الكلمات التي تستخدمها لغه سويفت كجزء منها يجب آن تلتزم بافضل المممارسات في تسمية المتغيرات بحيث تضمن كتابة كود سهل القراءة والفهم، خاصة اذا كنت تعمل في فريق برمجي. اذا اردت اضافة متغير لتخزين اسم فستكون تسميته name مناسبه ومنطقيه اكثر من تسميته n فقط! ولو اردت كتابة اسم متغير بكلمات متعددة فاستخدم اسلوب camel case بحيث اول كلمه من الاسم المتعدد تكون بحروف صغيره ثم اول حرف يكون كبير لاي كلمه اخرى مثل userOneName.
     
    إضافة المتغيرات والثوابت
    عملية اضافة وتعريف المتغيرات والثواتب هي واحدة. اولاً يتم تحديد اما ثابت let او متغير var حسب الحالة، ثم اسم المتغير حتى يمكنك استدعائه به في البرنامج لاحقاً، ثم لديك الخيار اما ان تحدد قيمة للمتغير عند تعريفه اول مره كما في المثال التالي
    var name = "robot" او تترك المتغير فارغ بدون قيمة لتحددها في وقت اخر ولكن عليك حينها استخدام شيئ يدعى في سويفت type annotation وهو كتابة نوع البيانات التي تريد منحها لاحقاً للمتغير. كما في المثال التالي:
    var name: String name = "robot" بالطبع لا يفضل استخدام هذا الاسلوب الثاني اذا كنت ستقوم بكتابة البيانات مباشرة في السطر الثاني لتعريف اسم المتغير. دائما عند تعريف المتغير مع قيمته اكتب المتغير وقيمته في سطر واحد كما في المثال الاول، ولو اردت الحاق نوع المتغير قبل القيمة فلن تمنعك سويفت من ذلك ولكنه امر لا داعي له في معظم الاحوال.
    var name: String = "robot"  
    الفرق بين المتغيرات والثوابت
    الثوابت Constant في سويفت تكون باختصار let وتعني ان القيمة ستصبح ثابته للآبد ولا يمكنك تغييرها مرة اخرى. 
    let name = “robot” اما المتغيرات وتبداء باختصار var تسمح لك بتغيير قيمتها بقدر لا محدود.
    var name = “robot” حينما تحاول ان تغير قيمة الثابت فسوف تحصل على خطآ:
    let age = 22 age = 25 اما المتغيرات فسيكون متاح لها تغييرها بالقدر الذي تريد:
    let age = 22 age = 25 age += 2 print(age) الكود السابق سيطبع 27 لان اخر سطر باضافة + قبل = يعني اضافة 2 على قيمة المتغير الذي بالسطر السابق ثم حفظ المجموع كقيمة للمتغير .
    يمكنك ايضاً نسخ او منح قيمة اي متغير او ثابت معرف مسبقاً الى متغير جديد او اخر:
    let minAge = 18 var userOneAge = minAge  
    لماذا ومتى تستخدم متغير او ثابت؟
    بالتآكيد يمكنك دوماً ادخال كل البيانات كمتغيرات var وان لا تتقيد باستخدام الثوابت let في برنامج٫ سويفت لن تجبرك بل ستسمح لك بذلك، ربما ستقترح عليك احياناً ان تغير بعض البيانات من متغير الى ثابت لانه سيكون من الافضل ذلك حسب طريقة سويفت في انجاز الامور. لكن كمبرمج فعال وخبير عليك ان تهتم باستخدام الثوابت والمتغيرات بنفسك حسب الحالة التي امامك وذلك لعدة اسباب اهمها:
    امان اللغة، لنفرض لو كان في تخطيطك للحل البرمجي حددت ان تلك القيمة يجب ان تكون ثابته دائماً وادخلتها كذلك في الكود ولكن لاحقاً نسيت وحاولت تغييرها فسوف ينبهك Xcode بالخطآ ولن يسمح لك ببناء البرنامج قبل اصلاحه. المترجم الذي يفسر الكود الخاص بس من سويفت الى اللغه التي يفهمها الكمبيوتر سيعرف ان هذه القيمة يجب ان تكون ثابته في الذاكره دائما ويغلق احتمال العوده لتغييرها لاحقاً بالتالي هو يتعامل مع الثوابت بشكل مختلف عن المتغيرات وهذا يجعل لها معالجه مختلفه تنعكس على سرعه وفعالية اداء البرنامج. ولنفرض انك تريد عمل برنامج يستخدم GPS ويحسب المسافه من مدينة لاخرى فسوف تقوم بتمثيل البيانات الرئيسية كالتالي:
    مكان الانطلاق: سيزودك به GPS مره احدة عن انطلاق الرحلة وسيظل كما هو طوال مسيره الرحلة ولن يتغير بالتالي ستقوم بتعريفه كثابت let وجهة الرحلة: ايضاً سيتم تحديده في بداية الرحلة بواسطة GPS ولن يتم تغييره طوال مسيرة الرحلة بالتالي ستقوم بتعريفه كثابت let. الموقع الحالي + المسافة المقطوعة + المسافة المتبقية: كل هذه البيانات ستتغير دائماً وبشكل فوري كلما تحركت بالتالي ستقوم بتعريف كل منها كمتغير var  
    انواع البيانات Data Type
    تملك سويفت كيغرها من لغات البرمجة العديد من انواع البيانات التي يمكن ان تحددها لكل متغير او ثابت تدخله في برنامجك. وعند تعريف انواع البيانات دائما يتم استخدام حرف كبير لاول الكلمة.
    رآينا في الامثله السابقة نوعين من تلك البيانات المستعملة وهي البيانات النصية وتسمى في سويفت String تمثل الحروف او النصوص بشكل عام:
    var name: String name = "robot" والبيانات الرقمية وتسمى Int كاختصار ل integer وتمثل الارقام العادية 1234 الخ:
    var age: Int age = 25 يوجد ايضاً Double وتمثل الارقام التي تملك فاصلة عشرية 1.0 2.0 3.0 4.0 الخ:
    var longitude: Double longitude = -87.244556 والنوع الاخر هو للبيانات المنطقية التي تحتمل اجابة صح true او خطآ false فقط واختصارها Bool بمعنى Boolean:
    var nothingNew: Bool nothingNew = true يوجد أيضاً نوع اخر هو Character ويستخدم اذا اردت اضافة بيانات عبارة عن حرف واحد فقط:
    var blood: Character blood = "A"  
    استنباط الانواع Type inference
    سويفت تملك ميزة قوية مثل type inference التي تقوم باستنتاج نوع البيانات من المتغير حينما تدخل قيمته٬ بالتالي لا داعي لكتابة نوع البيانات الا اذا كنت ستعرف المتغير ولا تنوي ادخال قيمة في نفس السطر كما شرحنا سابقاً. 
    مع type inference سيكون شكل الاكواد السابقة التي شرحنا بها انواع البيانات بالشكل الابسط والافضل كما يلي:
    var name = "robot" var age = 25 var longitude = -87.244556 var nothingNew = true  
    كان هذا كل شيء هام كمقدمة عن المتيغرات والثوابت والبيانات في سويفت. اتمنى ان لا تتردد في مشاركتي بآي استفسار او تعليق على حسابي في تويتر كما اتطلع لانضمام المزيد من المتعلمين على قناة سلاك حتى نستمتع بالتعلم معاً.
     
    اسئلة وتمارين
    أحاول في مجموعة سلاك اعداد تمارين تفاعلية من اعدادي واضيف عليها تمارين كتاب Apple التعليمي حتى ترسخ الفهم للمبتدئين تماماً وسأضع هنا التمارين الخاصة بهذا المقال. بإمكانك ارسال الحل لنا في مجموعة سلاك اطلب دعوة من حسابي في تويتر.
    قم بتعريف جميع المعلومات التالية في متغيرات او ثوابت var/let حسب ما تتطلبه كل معلومه مع ضروره تعريف نوع كل متغير او ثابت تقوم بعمله حسب نوع البيانات اذا كانت نصية او رقمية او منطقية. Name: Christopher Walken Age: 74 Birthplace: Astoria, New York, USA Residence: Wilton, Connecticut, USA Profession: Actor Years active: 1953–present Won Oscar: Yes Blood Type: A Weight: 75.62 Height: 181.3 ----------------------- اسئلة اضافية // اي القيم التالية سيكون من الافضل تمثيلها كثابت؟ let A. اسم اللاعب B. مستوى اللاعب C. درجة اللاعب D. موقع اللاعب // أي القيم التالية سيكون من الافضل تمثيلها كمتغير؟ var A. الاسم B. تاريخ الميلاد C. العمر D. عنوان المنزل // اختار الجمل التي لا يمكن ان تكون سبباً صحيحاً لاستخدام الثابت let? A. استخدام الثابت من الممارسات الجيدة التي يجب على المبرمج الالتزام بها للقيم الثابته التي لا تتغير B. المفسر يقدم معالجة مخصصة للبيانات الثابته تختلف عن المتغيرة C. لدعم أمان اللغة فالمبرمج لا يستطيع بالخطأ تغيير قيمة لا يجب ان تتغير في ذهنه حينما صمم الحل البرمجي D. معظم البيانات التي نتعامل معها لا تتغير // باستخدام استنباط نوع البيانات التلقائي الذي تدعمه سويفت, اي من البيانات التالية ستكون من نوع Double? A. var state = "California" B. let country = "USA" C. let population = 39250017 D. let speedLimit = 75.0 // هل الكود التالي سيعمل بشكل صحيح؟ ولماذا؟ let number: Double = 3 A. نعم لان المفسر سيمنح number القيمة 3.0 B. نعم لان 3 من نوع Double C. لا لأن 3 ليست من نوع Double  
    مستوى المقال: مبتدئ
  8. بسم الله الرحمن الرحيم
     
    في هذا الشرح سوف نتعلم كيف نضع أداة التمرير( scroll view )الى مشروعك . سوف أشرح التمرير العامودي الى الاعلى و الاسفل ( vertical scrolling).
    اذا اتقنت هذه الطريقة البسيطه ستتمكن من اتقان الطرق المتقدمه والتي تعتمد على مفهوم ال  auto layout
    (ربما سأتمكن من شرحه المرات القادمه)
     
    في البداية نبدأ بانشاء المشروع في xcode كالتالي 

     
    نذهب الى storybord  ونقوم بإضافة  UIScrollView الى ViewController
    كالتالي

     
     
    الان نضع القيود هذه القيود تعمل كقيد على أداة التمرير بحيث تقوم بتثبيتها على الواجهة( نضغط على الخطوط الحمراء المتقطعة )كالتالي:
     

     
     
    الان نحدد ال View Controller ونذهب الى القائمة في اليمين size inspector
    ونغير simulated size الى Freeform ونضع الارتفاع ١٠٠٠.
     الهدف من هذه الخطوة حتى نتمكن من رؤية الواجهة بطولها الكامل ونتمكن من وضع الادوات بحرية تامه الى اداة التمرير .  

     
    الان نضع labels في اماكنها  ونغير الخلفية لهما والقيود مثل الصورتين التاليه حتى نختبر هل تعمل أداة التمرير.
     

     


     
    ليكون الشكل النهائي لهما هكذا

     
    الان نبدا مرحلة كتابة الاكواد  woow
     نقوم بسحب وافلات scroll view عن طريق الضغط على الماوس و control من لوحه المفاتيح الى واجهة الكود لتكوين outlet يسمى myScroll 

     
    الان نضيف هذا الكود الى دالة viewDidLoad كما في الصوره
    contentSize تحدد الاتجاهات التي ممكن أن تقوم أداه التمرير بالوصول اليها فاداة التمرير تستطيع الذهاب الى الاعلى والاسفل بارتفاع ١٠٠٠ كما وضعناها في   storyboard . أما العرض فهو ثابت وهو بعرض شاشة الايفون.

     
    الان نقوم بتشغيل ورؤية النتيجه 
     

     
    شكرا لموقع عالم البرمجه لاتاحه الفرصه لمشاركه العطاء مع  المبرمجين الرائعين
    مستوى المقال: متوسط
  9. السلام عليكم ورحمة الله وبركاته
    هذا الشهر بدأت تعليم نفسي البرمجة من الصفر. اخترت بالتحديد برمجة الموبايل لأجهزة iOS بلغة Swift. وسيكون مرجعي للتعلم هو كتب Apple عن لغة Swift، أهمها The Swift Programming Language (Swift 3.1) و App Development with Swift.
    الرحلة ستكون طويلة وصعبة، بالتالي نحتاج لدعم وتحفيز بعضنا البعض للتقدم، ولهذا انشأت حساب تويتر @iosAppsRobot وفتحت مجموعة في Slack، لنتشارك النقاش او الحلول حول المصاعب التي تواجهنا. الانضمام الى مجموعة سلاك سيكون عبر الدعوات حسب نظام سلاك الذي لا يسمح بالتسجيل المتفوح. يمكنك طلب الدعوة بإرسال رسالة تتضمن البريد الالكتروني الخاص بك على حسابي في تويتر @iosAppsRobot.
    ايضاً كنوع من التحدي والالتزام الشخصي سأنشر عن كل شيئ أتعلمه، وسأتعمد البدء من الاساسيات حتى لو كانت سهلة للمبتدئين، ولكن كتابتها باللغة العربية قد تكون مفيدة للجيل الجديد ومن لا يجيد اللغة الانجليزية ويبحث عن مصدر عربي للتعلم والانطلاق. بالطبع لن اتمكن من كتابة دليل جديد باللغة العربية لهذه اللغة او بيئة تطوير تطبيقات  iOS ولكن سأحاول كتابة تدوينة او موضوع عن كل جزء مهم في هذه اللغة حتى يكون مفتاح للنقاش والتواصل والتحفيز مع من يدرس نفس الامر في هذه المرحلة. 
     
    لماذا اخترت iOS Apps؟
    هذا السؤال لا يوجد له اجابة واضحة. الاختيار بين انواع البرمجة مثل موبايل/ويب/ديسكتوب يعبتر خيار شخصي بالدرجة الاولى ولايجب تفسيره. اذا كنت تملك دافع لتعلم البرمجة مثل انتاج تطبيق خاص بك او بدء مسيرة مهنية في هذا المجال الذي تحبه، فلا تقلق ابداً حول المسميات او اللغات التي تجدها امامك لانها كثيرة ولا تنتهي. عليك ان تعمل وتتعلم ماتحب فقط، بعد ان تبحث وتجرب وتقارن بين كل الخيارات التي امامك. بالنسبة لي فأنا املك دافع واهداف لادخل مجال برمجة الموبايل بالتحديد، ولأني مستخدم لـجميع منتجات Apple وتعجبني الثقافة والاتجاه التي تسير عليه الشركة سواء في منتجاتها كهاردوير او تصميم وبرمجة، وحينما اعمل على اي هاتف Android اشعر بأني غريب واتمنى العودة الى موطني بالتالي كان من المستبعد تماماً ان اتعلم تطوير Android. عموماً كل هذه اللغات مجرد  أدوات والمهم هو تعلم البرمجة نفسها ويمكنك الان ان تبدأ بما تحب ومستبقلاً قد تحب شيئ اخر وتكمل معه او تنتقل اليه بسهولة حتى لو كان في مجال اخر مثل الويب او الديسكتوب او غيره. الآن استمتع بالتعلم!
     
    لماذا نتعلم Swift؟
    الاجابة بسيطة.. لانها الخيار الانسب من Apple لبرمجة تطبيقات iOS/macOS/watchOS/tvOS. بالطبع ليست الخيار الوحيد اذ توجد اطر عمل من لغات اخرى تمكنك من برمجة تطبيقات iOS، ولكن طالما هدفك هو iOS فتمسك بلغة Swift ولا تذهب لمكان اخر، لان تلك الاطر والخيارات من وجهة نظري تعتبر موجهه للمطورين الحاليين بتلك اللغات بالتالي يمكنهم بناء تطبيق iOS بما يمكلون حالياً من ادوات وخبرات. ولكن انت كمبتدئ لا داعي ان تاخذ منعطف كبير لبرمجة iOS بل اذهب مباشرة الى اللغة الأم واستمتع ايضاً بالسهولة والمرونة التي توفرها لك أبل في بيئة تطوير تطبيقاتها مثل Xcode والذي يعتبر من اقوى مميزات العمل والانتاجية لمطوري iOS مثلاً ولن تجد مثله في تلك البدائل المختلة.
     
    نبذة عن Swift
    في عام 2014 اعلنت شركة Apple عن لغة Swift كلغة حديثة ومتطورة تكون بديلة للغة objective-c التي اصبحت بعمر 30 سنة والتي تعرف ايضاً بأنها معقدة وصعبة في التعلم، هذا يتضاد مع طموح أبل في توسيع ثقافتها وزيادة عدد المطورين على منصاتها، بالتالي كان الحل او التوقيت المناسب لاخراج لغة جديدة متطورة.
    ميزات سويفت كلغة حديثة تعتبر كثيرة جداً، بالنسبة للمطورين يمكن قراءة كل المميزات في دليل اللغة بموقع الشركة، ولكن بالنسبة للمبتدئين يمكن ان ألخص أهم النقاط التي يمكنهم فهمها في التالي:
    سهولة ووضوح تركيبة كتابة اللغة Syntax بحيث يكون لديك كود نظيف وسهل للقراءة او العمل معه.  Optional اسلوب فريد وجديد للتعبير في حال كانت قيمة المتغير موجودة او لا والهدف ان يضمن لك التحكم في مختلف السيناريوهات المتوقعة للعمل مع القيم التي تدخلها. Type inference تضمن معرفة انواع البيانات وتحديد الأخطاء بشكل سريع وتلقائي مما يحفظ وقتك في العمل ويزيد انتاجيك كمطور. Type safety لغة أمنة تماماً تتطلب تفسير وتحديد نوع كل عنصر تضيفه للكود، بالتالي ابل لن تسمح لك بانتاج وبناء تطبيق به اخطأ وتزعج المستخدم بكثرة انهيارات تطبيقك. اللغة المعتمدة من Apple على الاقل للـ 30 سنة القادمة كما حصل مع لغتها السابقة، مالم يحدث تغيير مفاجئ او منعطف حاد في عالم التقنية وهذا مستبعد بالنظر الى مكانة الشركة ووضوح رؤيتها.  في عام 2015 سويفت أصبحت لغة مفتوحة المصدر بالتالي اصبح لدى اللغة مجتمع اكبر مما انعكس على سرعة تطور اللغة وتوسعها حتى وصلت الى منصات اخرى مثل Linux وخرجت اطر عمل كلغة ويب server-side مثلVapor. كل هذا يعني ان اللغة ستكون اكثر قيمة وفائدة لك كمطور مما لو ظلت محتكرة على منصات الشركة.
     
    Hello world!
    حينما تنخرط في دراسة او تعلم أي لغة برمجة جديدة من اي مصدر، في الغالب سيكون اول شيئ تتعلمه هو طباعة هذه العبارة الشعبية "Hello world!" على الشاشة بالتالي تكون قد انجزت ابسط برنامج بتلك اللغة.
    في البداية يجب ان تعرف بعض المعلومات البسيطة عن كتابة الاكواد البرمجية كالتي:
    الكود البرمجي يكون محفوظ في ملف ينتهي بامتداد .swift كل سطر جديد في الملف يمثل عبارة او سطر برمجي واحدة، او يكون كتلة/قطعة من العبارات والاسطر لتقوم جميعها بتنفيذ أمر واحد. يتم تنفيذ كل الاسطر البرمجية في الملف بالترتيب من الأعلى الى الاسفل. حساسية الآحرف، المسافات، والرموز كلها مهمة جداً في كتابة الاسطر البرمجية. سواء في اسماء المتغيرات او في كتابة القيم. حينما تخطآ في حالة حرف واحد فسيحدث خطآ في برنامج بالكامل وينهار. يتم تغيير المدخلات السابقة المرتبطة به. مثلاً اذا ادخلت متغير جديد في سطر ثم لاحقاً اعدت ادخال الكود التطبيق قد يتضمن الكثير من الملفات المنفصلة التي تتضمن الكثير جداً من العبارات والاسطر بلغة سويفت البرمجية، لاحقاً يتم تجميعها بواسطة المترجم وهو برنامج داخلي يقوم بتحويل اكواد لغة البرمجة الى لغة تفهمها الاجهزة وتستطيع معالجتها.  
    كيف تكتب Hello world! في سويفت؟
    print("Hello world!) print() هي دالة تأخذ أي نص وتطبعه في الكونسول الذي يستخدمه المبرمجون لرؤية حالة البرنامج الذي تتم كتابته بحيث يخرج لهم النتيجة بعد تنفيذ الكود.
    كل شيئ في لغات البرمجة يدور حول البيانات، ادخال البيانات وتخزينها، معالجتها، اخراجها. ولدينا عدة مفاهيم أساسية مرتبطة بالبيانات، مثلاً المتغيرات ونواع البيانات واشياء اخرى سنتكلم عنها في الدرس القادم.
    الان قم بتحميل تطبيق Xcode حتى تكتب برنامج الاول Hello World!
     
    Playground 
    هذه الميزة هي احد افضل مميزات Swift والعمل معها، ليس للمتعلمين فحسب، بل حتى للمطورين الفعليين لانها تسمح بكتابة الاكواد وتنفيذها بشكل سريع لتجربتها ورؤية النتيجة فوراً مع كل تعديل تقوم به، وتسمح لك ايضاً بكتابة عدد لا محدود من الاكواد سواء للتعلم او حتى للاختبار ومقارنة نتائج التعديلات على الكود قبل نقله للمشروع الاصلي. هي بالفعل playground لان كل هذه التجارب تتم بابسط واسهل طريقة ممكنة في شاشة بتصميم مألوف وممتع مقارنة باستخدام كونسل تقليدي او Terminal نظام macOS.
    للتذكير كل تعديل تقوم به في playground سيعيد تنفيذ كل الاكواد من الاعلى للاسفل كما لو كان ملف برمجي حقيقي في مشروع وتطبيق فعلي. نتائج الكود ستظهر في الجانب الايمن من الشاشة، ايضاً يمكنك ان تشاهد النتائج او مخرجات الكود في الجانب الاسفل بإلضغط على ايقونة اظهار الكونسل من الشريط السفلي للتطبيق.
    بعد ان تعمل playground جديد ستجد بشكل افتراضي الكود التالي:
    //: Playground - noun: a place where people can play import UIKit var str = "Hello, playground"  
    الكود في السطر رقم 1 يظهر باللون الاخضر لانه تعليق لن يتم تنفيذه في البرنامج وانما موجود لك انت او لاي شخص اخر سيقرأ الكود من بعدك. وطريقة كتابة التعليقات في سويفت تكون باستخدام // متتالية ثم كتابة نص التعليق في سطر واحد فقط. ويمكنك كتابة تعليق متعدد الاسطر بوضع /* في اول السطر و */ في نهايته.
    // تعليق في سطر واحد /* تعليق متعدد الاسطر بعدد أسطر لا محدود */  
    بالنسبة للكود في السطر الثالث import UIKit فهو مخصص لاستدعاء اطار UIKit واستعمال كل شيئ فيه، وسنتعلم كل شيئ عنه في المستقبل القريب ان شاء الله.
     
    اما الكود في السطر 5 وهو var str = "Hello, playground" فهو كالاتي:
    في بداية السطر يتم انشاء متغير جديد variable (اختصاره var في سويفت) ليكون حاوية لتخزين بيانات جديدة سيتضمنها. ثم مسافة وبعدها يتم كتابة اسم المتغير (في هذه الحالة اسم المتغير str) ثم مسافة ثم علامة = وتعني منح القيمة التي تلي هذه العلامة الى المتغير السابق ثم مسافة تليها علامتي تنصيص "" بداخلها النص، وهي طريقة كتابة النصوص في سويفت "هكذا"  
    المهم ان تفهمه الان انك تستطيع الان تغيير قيمة المتغير باعادة كتابة اسم المتغير ثم = ثم ادخال القيمة الجديدة، وكل هذا يكون في نهاية الكود الجهاز الذي وجدته افتراضياً في playground، وكما قلنا سابقاً ان تنفيذ الاكواد البرمجية يكون من الاعلى للاسفل دائماً واي تغيير تحدثه في الاسفل ويتضمن علامة = مثلاً فهذا يعني انك استبدلت القيمة السابقة التي قمت باضافتها في الاعلى.
     
    الان كمتعلم عليك ان تستخدم الدالة print() لطباعة نص في الكونسل اسفل Xcode ولديك مهمتان محددة:
    اطبع المتغير str الذي وجدته في playground اطبع Hello world! مباشرة الى الدالة بدون استخدام متغير  
    هذا كل شيئ للمقدمة. استمتع بالتجربة واسكتشاف وتعلم كل شيئ بنفسك، لان ما اكتبه انا ليس الا مجرد ملاحظات بسيطة بهدف توثيق تجربة التعلم والتحفيز. وعليك ان تعلم ان اهم المهارات التي يجب ان تتحلى بها كمبرمج هي مهارة البحث والتجربة بنفسك عن اي مشكلة او اي شيئ تجده امامك ولا تفهمه. الكتب او اليوتيوب ان كنت تهوى الفيديو كطريقة تعلم + قوقل هو صديقك الاول في رحلة التعلم. وأنا سأكون صديقك الثاني سواء على تويتر او مجموعة سلاك تفضل بسؤالي عما لا تستطيع بنفسك ان تجد اجابة له.
     
    ....................
     
    # تحديث1: أحاول في مجموعة سلاك اعداد تمارين تفاعلية من اعدادي واضيف عليها تمارين كتاب Apple التعليمي حتى ترسخ الفهم للمبتدئين تماماً وسأضع هنا التمارين الخاصة بهذا المقال. بإمكانك ارسال الحل لنا في مجموعة سلاك اطلب دعوة من حسابي في تويتر.
     
    افتح playground جديدة في Xcode احذف الاكواد الموجودة افتراضياً استخدم الدالة (print) اطبع عبارة "Hello world!" ثم قم بكتابة تعليق متعدد الاسطر يتضمن وصف موجز لهدفك من تعلم البرمجة ------ اسئلة اضافية // سؤال رقم 1: ماهي الميزة التي تجعل سويفت لغة امنة؟ A. Type safety B. Type inference C. Error handling D. Optionals // سؤال رقم 2: ماذا سيطبع الكود التالي let helloWorld = "Hello, world!" let helloPlayground = "Hello, playground!" let goodbyePlayground = "goodbye, playground!" print("Testing, testing, 1-2-3")  
    مستوى المقال: مبتدئ
  10. بسم الله الرحمن الرحيم
    السلام عليكم ورحمة الله وبركاته
     
    في أغلب الأحيان، عندما تقوم بتصميم برنامج يحتوي على أكثر من شاشة View Controller، ستحتاج لإرسال البيانات من شاشة لأخرى (سواء للأمام أو الخلف) ليكتمل تصميم البرنامج.
    في هذه المقالة، سنستعرض احدى اسهل الطرق لارسال البيانات من شاشة الى شاشة تالية، سنسرسل بيانات من انواع مختلفة String, Int, UIImage.
     
    أولا/ بناء المشروع
    1: قم بانشاء مشروع جديد من نوع Single View Application بأي اسم ترغبه
    2: أضف View Controller جديدة الى الStoryboard

     
    3: قم بتحديد الView Controller الأولى واختر Embed In > Navigation Controller

     
    4: أضف الأدوات المطلوبة (Text Field, Image View, Button) كما في الصورة

     
    5:  أنشئ ملف Cocoa Touch Class جديد باسم SecondVC واضفه الى الView Controller الثانية

     
    عند الضغط على الView Controller الثانية، تأكد من اضافة "SecondVC" في خانتي الClass والStoryboard ID كما في الصورة التالية
     

     
    6: لإضافة الIBOutlets للView Controller الأولى قم بفتح الAssistant Editor للStoryboard والViewController.swift

     
    7: مع الضغط على control، قم بسحب الأدوات الى الأيمن واضافتها كIBOutlets : (صورة متحركة، قم بالنقر عليها لمشاهدة الAnimation)

     
    8: عند اضافة الButton تأكد من اضافته كAction وليس كOutlet

     
    9: الآن قم بعمل نفس الشيء مع الشاشة الأخرى، واضف الImage والLabel كOutlets

     
     ثانيا/ كتابة الكود
    أولا قم باضافة التعديلات التالية على الكلاس الثاني (SecondVC) كما في الصورة

     
    قمنا بانشاء متغيرات في الكلاس الثاني، لتكون مستعدة لاستقبال البيانات من الكلاس الأول
    وحالما يبدأ عرض الشاشة، سيقوم السطرين المضافين الى الميثود ()viewDidLoad بعرض هذه البيانات الى المستخدم 
     
    الآن، قم باضافة الكود التالي في داخل الميثود ()sendBtnTapped في الكلاس الأول
    let myVC = storyboard?.instantiateViewController(withIdentifier: "SecondVC") as! SecondVC myVC.stringPassed = textField.text! myVC.imagePassed = imageView.image! navigationController?.pushViewController(myVC, animated: true) في السطر الأول، قمنا بانشاء instance جديدة من الView Controller الثانية
    في السطر الثاني والثالث، استخدمنا هذه الinstance لتمرير المعلومات من الكلاس الأول الى المتغيرات التي أنشأناها في الكلاس الثاني
    وأخيرا في السطر الرابع، قمنا بطلب الانتقال من الشاشة الأولى الى الشاشة الثانية (أو بمعنى أدق، عرض الشاشة الثانية فوق الشاشة الأولى)
     
    بقي أن تضيف صورة الى الUIImageView في الشاشة الأولى باستخدام الStoryboard 
    قمت أنا باضافة لوقو أبل كصورة تجريبية:

     
     
    الآن قم بتشغيل البرنامج، وأضف اي نص في الText Field واضغط على الزر لمشاهدة النتيجة: (صورة متحركة، قم بالنقر عليها لمشاهدة الAnimation)

     
    في الجزء الثاني سنتعرف بإذن الله على طريقة أخرى لارسال البيانات من كلاس لآخر.
    بحفظ الله ورعايته.
     
     
    مستوى المقال: مبتدئ
  11. في هذا الجزء سوف ننتقل الي نوع اخر مختلف عنما اعتدنا عليه سابقا
     
    سوف ننتقل من Animation الـ View الى Animation الـ Layer
     
    بصيغة أخرى هذا الموضوع هو بداية الدخول  الى الـ Core Animation
     
    هناك فروقات كثيره بينهم !
     
    ابرزها :
    كل امر فعلته باستخدام الـ UIView Animation تستطيع عمله باستخدام الـ Layer Animation ولا يمكن فعل العكس لماذا ؟
    لانه الـ Layer يكون خلف الـ View
    وبتالي عند تحريك الـ View مثلا انت أيضا تحرك الـ Layer
    بما يعني أي امر تستطيع عمله بالـ View أيضا تستطيع عمله بالـ Layer
    لانه طبقة الـ layer موجودة خلف الـ View
    ولكن لا يمكن عمل العكس .
     
    ملكيات الـ Layer التي يمكنك عمل لها  Animation  أكثر بكثير من ملكيات الـ UIView ، بمعنى اخر تستطيع فعل الكثير باستخدام Layer Animation الـ Layer Animation ينفذ باستخدام المعالج الرسومي GPU في حين الـ UIView باستخدام المعالج المركزي CPU الـ Layer Animation يمكن عمل Animation بشكل 3D و  2D في حين UIView Animation ، يمكن عمل Animation بشكل 2D فقط الـ UIView Animation اسهل استخداما من الـ Layer Animation يمكن دمج الـ Layer Animation مع الـ UIView Animation  
    مختصر الكلام الـ UIView Animation هو نسخه مخففه من الـ Layer Animation

    بعد معرفة الفروقات لنبدأ الدرس :
     
    لأثبات كلامي السابق
     
    سوف نحاول عمل Animation يقوم بتحويل المربع الى دائرة باستخدام UIView Animation


    بكتابة الكود التالي :
     
     @IBAction func AnimationButton(_ sender: Any) {                  UIView.animate(withDuration: 0.3) {                         self.squareView.layer.cornerRadius = 61         }              }  
    ما فعلته هنا هو غيرت زوايا المربع من 0 الى 61
    لماذا 61 ؟
    لانه الطول والعرض للمربع هو 122 ، وبالتالي لتحويل المربع الى دائره نجعل زواية المربع تساوي
    أضلاع المربع قسمة 2
    بما يعني 122 قسمة 2 = 61
     
    الان نرى النتيجة في الصورة التالية :
     

     
    كما ترى لم يتم حدوث Animation
    ولكن فقط تم تحويل المربع الى دائره بشكل فجائي
     
    والسبب كما ذكرنا سابقا
     
     لا يمكنه عملAnimation للـ Layer باستخدام UIView Animationالـ
     
    اذا ماهو الـ Layer Animation الذي سوف نتحدث عنه اليوم ؟
     
    كما الامر في UIView Animation
    هناك أنواع مختلفة
     
    أيضا في الـ Layer Animation
    هناك أنواع مختلفة
     
    النوع الذي سوف نتحدث عنه اليوم هو CABasicAnimation
     
    سوف نعود الى المربع الأزرق الذي استخدمناه في المواضيع السابقة
     
    لذا قم بإضافة "زر" وقم بربطه بملف الاكواد كـ Action
    باسم AnimationButton
    وقم بإضافة UIView واعطيه لوناً
     
    وقم بربطه بملف الاكواد باسم squareView
     
    الان سوف نبدأ في شرح الـ  Layer Animation
     
    كيف يتم كتابة كود الـ Layer Animation؟
     
    الطريقة مختلفة عن الـ UIView Animation
     
    فهيا تعتمد أولا على تعريف خصائص الـ Animation
    وفي الأخير في سطر واحد يتم تنفيذ الـ Animation
     
    قم بكتابة الكود التالي :
    @IBAction func AnimationButton(_ sender: Any) {    let cornerRadiusAnimation = CABasicAnimation(keyPath: "cornerRadius") cornerRadiusAnimation.duration = 0.3         cornerRadiusAnimation.fromValue = 0                  cornerRadiusAnimation.toValue = 61             squareView.layer.add(cornerRadiusAnimation, forKey: nil) }  
    في المثال السابق :
     
    اول سطر قمنا بتعريف متغير cornerRadiusAnimation
    من نوع  CABasicAnimation
     
     
    لاحظ الـ keypath
    تقوم بالكتابة فيه نوع الـ Animation الذي تريد عمله
     
    هنا نحن نريد عمل Animation للزوايا او بصيغة أخرى الـ cornerRadius
     
    من ثم قمنا بكتابة الـ duration
    الوقت المراد عمل في الـ Animation
    بالثانية (مدة الـ Animation)
     
    ومن ثم نحدد القيمة الاولية و القيمة النهائية
     
    بما يعني في اول قيمة fromValue
    نحدد القيمة الحالية
    قمنا بكتابة 0
    لأننا نعلم بأنه القيمة الاولية هيا 0 وبالتالي يظهر الشكل بشكل مربع !
     
    toValue
    هيا القيمة التي نريد الوصول اليها
    نحن نريد ان تكون قيمة الـ cornerRadius
    تساوي 61 وبالتالي يتغير الشكل من مربع الى دائره
     
    الان انتهينا من وضع الخصائص الخاصة بالـ Animation
     
    يبقى التنفيذ
     
    في اخر سطر نفذنا الـ Animation
    عن طريق استخدام add
       squareView.layer.add(cornerRadiusAnimation, forKey: nil)  
    الان قم بتشغيل الكود
    وسوف تلاحظ الـ Animation
    عند تغيره من مربع الى دائره
     
    كما في الصورة التالية :

     
    لكن هناك مشكلة !!
    عند الانتهاء من الـ Animation تم إعادة الـ View
    الى الشكل المربع ولم يبقى على شكل الدائره
    لماذا ؟؟
     
    لتوضيح المشكلة بأبسط صورة ممكنه
    عند عمل الـ Animation
    الـ Core Animation ينفذها عن طريق استخدام الـ layer.add
    وعندما ينتهي الـ Animation يقوم بحذفها
    بما يعني لا يحدث تغير في القيمة الفعلية للـ Layer
    فيظل الـ View كما كان بدون تغير !
     
    لحل المشكلة
    هناك حلين ، وكلاهما صحيحان
     
    الاول :
     
    نقوم بتغير الـ View الى الوضع الذي نريده عندما ينتهي الـ Animation
     
    نحن نريد جعل الحواف بقيمة 61
    وذلك لتحويله الى دائرة
     
    لذا نقوم بكتابة السطر التالي

     
    squareView.layer.cornerRadius = 61  
    بعد السطر
     
    squareView.layer.add(cornerRadiusAnimation, forKey: nil)  
    وبالتالي تحل المشكلة !
     
     
    الحل الثاني :
     
    نقوم بإضافة السطرين التالين :
    animation.isRemovedOnCompletion = false animation.fillMode = kCAFillModeForwards  
    ضعهم في أي مكان قبل
    squareView.layer.add  
    وستجده أيضا يعمل !
    لكن هذا الحل غير مفضل دائماً !
     
    لماذا ؟
     
    عندما يحدث الـ Animation في الـ Core Animation
    انت في الحقيقة لا تشاهد الـ Layer يحدث له الـ Animation
    ولكن الذي تشاهده هو نسخه طبق الأصل منه ، بما يعني الـ Cache الخاص بالـ Layer
    هو الذي يحدث له Animation
    ويطلق عليه اسم Presentation Layer
     
    وعندما تستخدم الاسطر الماضية فالذي تقوم به هو حفظ الـ Presentation Layer
    وتمنع ازالته من الشاشة
    هذا الامر يسبب مشكلة في الأداء (performance)  !    
    وأيضا سوف يسبب مشكلة اذا كان العنصر التي تحركه يتطلب التفاعل معاه
    كالـ Textfield
    لن تستطيع الضغط على الحقل بعد انتهاء الـ Animation
    اذا كان الظاهر هو Presentation Layer
    وليس الـ Layer الحقيقي الـ Actual Layer
     
    لذا يفضل عدم استخدام الحل ذا قدر الإمكان ، ستحتاجه في بعض الحالات ولكن أغلب الحالات يفضل تغير موقع الـ Actual Layer بعد انتهاء الـ Animation كما تم شرحه في الحل الأول وهو الحل الذي سوف نستمر في استخدامه .
     
     
     
    الان
    قبل الضغط على الزر سوف يكون على شكل مربع
    ومن ثم يحدث الـ Animation
    فيتغير من الشكل المربع الى الدائرة
    وعندما ينتهي الـ Animation
    يظل على الشكل النهائي الذي هو الدائرة !
     
    النتيجة :
     

     
    حان الوقت لتوضيح معلومة =)
     
    أعتقد بأنك لاحظت امراً
    وهو خصائص الـ Aniamtion
    في الـ Layer Animation
    ليست مرتبطة بـ View  معين
    بما يعني يمكنك إعادة عمل الـ Animation
    ذاته على كذا View مختلف
     
    لذا يمكنك إضافة مربع اخر
     
    كما في الصورة التالية :

    قم بتسميته باسم squareView2
    ومن ثم قم بربطة بملف الاكواد
     
    واستخدام نفس السطر التالي

     
       squareView2.layer.add(cornerRadiusAnimation, forKey: nil)  
    لاحظ التغير الوحيد squareView غيرناه الى squareView2
    وهو يساوي اسم الـ view الجديد
     
    ولا تنسى في النهاية تضيف السطر التالي
    squareView2.layer.cornerRadius = 61  
    قم بتشغيل الكود وشاهد النتيجة :

     
    نعود الى الشرح
     
    الان وقد فهمت فكرة الـ Layer Animation
     
    لنتحدث عن الانواع الأخرى :
     
    التلاشي :
     
     let animation = CABasicAnimation(keyPath: "opacity")         animation.duration = 0.5         animation.fromValue = 1         animation.toValue = 0                  squareView.layer.add(animation, forKey: nil)                  squareView.layer.opacity = 0  
    بالنسبة للـ Layer
    فالملكية المسؤولة عن الشفافية هي Opacity
    عوضاً عن Alpha
     
    اخر سطر كما وضحنا سابقا يتوجب علينا تغير القيمة الحقيقية أيضا
    لكي يظل مخفي الـView بعد انتهاء الـ Animation
     
    النتيجة :

     
    إضافة ايطار – تغير حجم الايطار :
     
    من خواص الـ Layer
    الـ ايطار
    يمكن وضع ايطار للـ View
     
    بكتابة التالي في داخل الـ AnimationButton:

     
            let animation = CABasicAnimation(keyPath: "borderWidth")         animation.duration = 0.5         animation.fromValue = 0         animation.toValue = 6                  squareView.layer.add(animation, forKey: nil)                  squareView.layer.borderWidth = 6 بما سبق قمنا بتغير قيمة borderWidth
    من صفر الى 6
     
    النتيجة :

     
    تغير لون الايطار :
     
    الان سوف نضيف ايطار مسبقا في الـ Viewdidload()
    ومن ثم نعمل Aniamtion
    ونغير لونه عند الضغط على الزر
     
    لذا قم بإضافة السطر التالي في Viewdidload()
    squareView.layer.borderWidth = 6 الان بداخل قواس AnimationButton
    قم بكتابة التالي :

     
    let animation = CABasicAnimation(keyPath: "borderColor")         animation.duration = 0.5         animation.fromValue = UIColor.black.cgColor         animation.toValue = UIColor.lightGray.cgColor                  squareView.layer.add(animation, forKey: nil)                  squareView.layer.borderColor = UIColor.lightGray.cgColor قمنا بتغير لون الحدود (الايطار) من اللون الأسود الى اللون الرصاصي الفاتح
     
    ملاحظة مهمه :
    في الـ Layer
    في الألوان نستخدم نوع cgColor
    وليست UIColor
    لذلك نعمل عملية Casting لتحويل اللون الى نوع cgColor
    اذا لم تضيف .cgColor
    سيظهر خطأ !
     
    النتيجة :

     
    عمل Animation للظل ! :
     
    بالنسبة للظل هناك 4 أمور تؤثر على الظل
    shadowOpacity : شفافية الظل ، 0 تعني اختفاء الظل و 1 ظهوره
    shadowOffset : موقع الظل
    shadowRadius : كثافة الظل ، كل ما زاد الرقم اصبح "عرض" الظل اكبر
    shadowColor : لون الظل
     
     
     
     
    قم بكتابة الاكواد التالية :
     
            let animation = CABasicAnimation(keyPath: "shadowOpacity")         animation.duration = 0.5         animation.fromValue = 0         animation.toValue = 1                  squareView.layer.add(animation, forKey: nil)         squareView.layer.shadowOpacity = 1  
    كما ذكرت سابقا قيمة 1 تعني ظهور الظل
    لذا وضعنا قيمة 1
     
    النتيجة :

     
    الان لغرض استخدام الخصائص الأخرى
     
    سوف نقوم بكتابة الكود التالي في viewDidLoad

     
    squareView.layer.shadowOpacity = 1  
    ومن ثم نقوم بكتابة الاكواد التالي  
     
    لتغير موقع الظل :
     
            let animation = CABasicAnimation(keyPath: "shadowOffset")         animation.duration = 0.5         animation.fromValue = CGSize.zero         animation.toValue = CGSize(width: 5, height: 8)                                                                     squareView.layer.add(animation, forKey: nil)                  squareView.layer.shadowOffset = CGSize(width: 5, height: 8)  
    النتيجة :

     
    لاحظ بأن shadowOffset يأخد قمتين وهما العرض width والارتفاع height
     
    لتسهيل فهمها لاحظ الصورة التالية :

    اذا اردت الظل يظهر من الجهة اليمين
    اجعل القيم بالشكل التالي
    CGSize(width: 8, height: 0)  
    من اليسار
    CGSize(width: -8, height: 0)  
    من الأعلى
    CGSize(width: 0, height: -8)  
    من الأسفل
    CGSize(width: 0, height:8)  
    بما يعني اعتبر القيمتين x و y

    وتذكر الصورة التالية :

     

     
    لزيادة مساحة الظل :
     
    قم بكتابة الاكواد التالية :

     
            let animation = CABasicAnimation(keyPath: "shadowRadius")         animation.duration = 0.5         animation.fromValue = 0         animation.toValue = 10                  squareView.layer.add(animation, forKey: nil)                  squareView.layer.shadowRadius = 10  
    النتيجة :

     
    لتغير لون الظل :
     
    قم بكتابة الاكواد التالية :

     
            let animation = CABasicAnimation(keyPath: " shadowColor")         animation.duration = 0.5         animation.fromValue = UIColor.black.cgColor         animation.toValue = UIColor.gray.cgColor                  squareView.layer.add(animation, forKey: nil)                  squareView.layer.shadowColor = UIColor.gray.cgColor  
    النتيجة :

     
    وبكذا نكون انتهينا من خصائص الظل
     
     
    الان نعود الى الامثله التي ذكرناها في المواضيع السابقة عندما تحدثنا عن UIView Animation
    وكيف نفعلها باستخدام الـ Layer Animation
     
    تغير موقع الـ View :
     
    لتغير الموقع نستخدم ملكية تسمى Position
     
    لاجل تغير قيمة y فقط نقوم بكتابة position.y
     
            let animation = CABasicAnimation(keyPath: "position.y")         animation.duration = 0.5         animation.fromValue = 126         animation.toValue = 400                  squareView.layer.add(animation, forKey: nil)                  squareView.layer.position.y = 400  
     
    fromValue
    هو قيمة y الحالية 126
    ونريد تغيرها الى قيمة 400
    لجعل المربع ينزل الى الأسفل
     
    النتيجة :
     

     
     
    لاجل تغير قيمة x فقط نقوم بكتابة position.x

     
            let animation = CABasicAnimation(keyPath: "position.x")                animation.duration = 0.5         animation.fromValue = squareView.center.x         animation.toValue = -20                  squareView.layer.add(animation, forKey: nil)                  squareView.layer.position.x = -20  
    كما تلاحظ في formValue
    قمنا بكتابة squareView.center.x
    والسبب لجلب قيمة x لـ  View الحالية بدلاً من كتابتها بشكل يدوي
     
    النتيجة :

     
    التصغير :
     
       let animation = CABasicAnimation(keyPath: "transform.scale")        animation.isRemovedOnCompletion = false animation.fillMode = kCAFillModeForwards                  animation.duration = 0.5         animation.fromValue = 1         animation.toValue = 0.8                  squareView.layer.add(animation, forKey: nil)  
    النتيجة :

     
    التضخيم :

     
    let animation = CABasicAnimation(keyPath: "transform.scale")        animation.isRemovedOnCompletion = false animation.fillMode = kCAFillModeForwards                  animation.duration = 0.5         animation.fromValue = 1         animation.toValue = 2                  squareView.layer.add(animation, forKey: nil)  
    النتيجة :

     
    معلومة :
     
    اذا اردت فقط تصغير او تضخيم قيمة X دون Y
    قم بكتابة
     
    let animation = CABasicAnimation(keyPath: "transform.scale.x")  
    الأمر أيضا ينطبق على Y اذا اردت تصغير او تضخيم قيمة Y دون x
    قم بكتابة
     
    let animation = CABasicAnimation(keyPath: "transform.scale.x")  
     
    مستوى المقال: متوسط
  12. اللغة المستخدمة : swift3
    البرنامج : xcode 8
     
    السلام عليكم،
    في هذا الدرس سنتحدث عن واحدة من أهم المهارات التي تساعدك في بناء مشروعك في وقت قياسي و بنتائج ممتازة اعتمادا على استخدام مكتبات قام بإنشائها مطورون آخرون لتكون متاحة لجميع المطورين.
    لكن قبل ذلك علينا فهم بعض الأمور الأساسية للبدء  ثم سنتحدث عن طريقة تنزيل المكتبات إلى مشاريعك.
     
    الTermianl : 
    حتى تستطيع التعامل مع الملفات الخارجية يجب أن تتعلم في البداية طريقة التعامل مع الterminal
    Terminal : هي واجهة غير رسومية يمكن استخدامها لتنفيذ الأوامر العادية التي تقوم بها كإنشاء ملف أو حذفه.. الخ.
    للوصول إليها كل ما عليك فعله هو كتابة terminal في شريط البحث للوصول السريع إليها و ستظهر لك كأول نتيجة، قم بفتحها

    كما ذكرنا فإن الterminal هي واجهة غير رسومية يمكن فيها تنفيذ الأوامر عن طريق كتابتها بطريقة معينة و إهم الإوامر التي يجب التعرف عليها لهذا الدرس هي التالية : 
    cd : و هي اختصار ل (change directory ) و هي تستخدم للانتقال إلى أحد المجلدات و هي تشبه فتحك لأي مجلد من المجلدات بالطريقة العادية.
    ls : و هي تستخدم لعرض كل محتويات المجلد الموجود بداخله حاليا.
    الآن قم بفتح الterminal و قم بكتابة : 
    cd Desktop  للانتقال إلى سطح المكتب الخاص بك
    الآن قم بكتابة ls لتظهر محتويات سطح المكتب.
    ستجد أن كل الملفات و المجلدات و التطبيقات الموجودة في سطح المكتب قد تم عرضها لك في الterminal.
    هذه أهم الأمور التي يجب معرفتها فيما يخص وحدة التحكم أو الterminal للمواصلة في هذا الدرس.
     
    الCocoapod :
    و الآن حتى تتمكن من تنزيل المكتبات و الحصول عليها لابد من تنزيل أداة على وحدة التحكم للحصول على إمكانية استخدام أوامر مهمة تمكنك من إضافة المكتبات مباشرة في مشاريعك في الxcode و هذه الأداة تسمى cocoa pod و حتى تقوم بتنزيلها على الterminal الخاص بك قم بزيارة موقعهم:
    https://cocoapods.org/
    و انسخ السطر الموجود في خانة Install
    أو انسخه مباشرة من هنا : 
    sudo gem install cocoapods
    و قم بلصقه في وحدة التحكم (terminal) لديك.
    قد يطلب منك إدخال رقمك سري، قم بإدخاله ثم اضغط زر return أو enter.
    حينها سيبدأ الterminal بتنزيل الcocoa pod.
     
    ملاحظة: قد لا تظهر لك أي إشارة في الterminal تشير إلى أن البرنامج يتم تنزيله حاليا، و لكن يمكنك التأكد إذا ما نظرت إلى الزر الأحمر في الزاوية اليسرى في الشريط العلوي و الخاص بإغلاق البرنامج. حيث يفترض أن تجد بداخله دائرة سوداء و التي تشير إلى أن البرنامج يقوم بتنفيذ أحد العمليات في الوقت الحالي كما في الصورة التالية...

     
    الآن بعد اكتمال التنزيل ستزول النقطة السوداء و ستظهر لك مجموعة من التعليمات تخبرك باكتمال التنزيل كما في الصورة التالية:

    الآن يمكنك أن تتعامل مع المكتبات الموجودة و تنزيلها إلى مشروعك.
     
     
    تنزيل المكتبات
    في الجزء التالي من الدرس سنقوم بتنزيل إحدى المكتبات على مشروع xcode و سنختار JTAppleCalendar و هي تستخدم لإنشاء تقويم و استخدامه في مشروعك، و لكن لن نتحدث عن طريقة إنشاء التقويم و التعامل معه و إنما الغرض شرح طريقة تنزيل المكتبات على مشروعك و استخدام الcocoa pod لذلك يمكنك اختيار أي خيار آخر لتنزيله. و الاختيارات يمكن الوصول إليها من عدة مصادر أهمها و أشهرها الgithup حيث يمكنك البحث هناك عن كل ما تريد.
    و هنا رابط المكتبة التي سنقوم بتنزيلها إلى المشروع :
    https://github.com/patchthecode/JTAppleCalendar
    إذا لنبدأ..
    في البداية قم بإنشاء مشروع xcode جديد و سمه demo مثلا و قم بحفظه على سطح المكتب.
    -- صورة
    الآن قم بفتح الterminal..
    نريد في البداية الوصول إلى موقع المجلد الذي يحوي كل ملفات المشروع لتنزيل المكتبة في ذلك المكان و لذلك يجب علينا استخدام أمر cd ثم إضافة المسار الخاص بالمشروع للوصول إليه من خلال الterminal. ولكن يمكن استخدام طريقة أسهل من عمل ذلك يدويا و هي :
    ١- قم بكتابة cd ثم مسافة
    ٢- قم بسحب المجلد من سطح المكتب و أفلته في الterminal و ستجد أن الterminal قام بإضافة مسار المجلد تلقائيا
    ٣- اضغط enter أو return 
    الآن تم الوصول إلى داخل المجلد و يمكنك التأكد من ذلك عن طريق استعراض الملفات بداخل المجلد بالضغط على ls و ستجد أن الterminal يعرض لك ملفات المشروع الخاصة بك.
    الآن قم بكتابة الأمر التالي على الterminal :
    pod init 
    ثم اضغط enter 
    - هذا الأمر خاص بإنشاء ملف باسم pod file و هو الملف الذي يجب أن يحوي كل المكتبات التي تريد استخدامها في مشروعك. و للتأكد من أن الملف قد تم إنشاؤه قم بإدخال أمر ls مرة أخرى و يجب عليك أن تجد ملف جديد باسم Podfile أو يمكنك فتح المجلد يدويا و ستجد ذلك الملف بالداخل.
    - الآن قم بفتح ملف الpodfile حيث سنقوم بإضافة بعض الأسطر بداخله.
    - الآن عليك إضافة أسماء المكتبات التي ستقوم باستخدامها داخل هذا الملف. لكن من أين نحصل على اسم المكتبات ؟ عليك دائما أن تعود إلى التوجيهات المكتوبة من مصدر التنزيل ذاته للحصول على هذه المعلومات، لذلك قم بالعودة إلى الرابط مرة أخرى
    https://github.com/patchthecode/JTAppleCalendar
    دائما عند تنزيل المكتبات لابد من البحث على خانة الinstallation بطريقة الcocoa pod لذلك توجه إلى خانة installiation via cocoa pod و ستجد أنه يشير إلى أمر تنزيل الcocoa pod حيث قمنا بذلك مسبقا.
    و بعد ذلك يريك المحتويات التي يجب أن تكون بداخل ملف الPodFile لذلك انسخ منها الأشياء التي لا يحويها الملف الموجود عندك و هي التالية : 
    source 'https://github.com/CocoaPods/Specs.git' platform :ios, '10.0' use_frameworks! و هذه التعليمات في الأعلى ضعها في بداية الملف
     
     
    pod 'JTAppleCalendar', '~> 7.0' و هذه ضعها بدلا من : #Pods for demo  
     
    أخيرا ملف الpodFile يجب أن يبدو كالتالي :
    # Uncomment the next line to define a global platform for your project source 'https://github.com/CocoaPods/Specs.git' platform :ios, '10.0' use_frameworks! target 'demo' do # Comment the next line if you're not using Swift and don't want to use dynamic frameworks use_frameworks! pod 'JTAppleCalendar', '~> 7.0' target 'demoTests' do inherit! :search_paths # Pods for testing end target 'demoUITests' do inherit! :search_paths # Pods for testing end end مع ملاحظة النقاط التالية :
    ١- أي سطر يبدأ ب# فهو كالcomment في البرمجة لا تأثير له و لذلك لا مشكلة في حال وجود سطور إضافية من هذا النوع في ملفي أو ملفك.
    ٢- لا مشكلة إذا لم يكن ملفك يحوي السطور التالية :
    target 'demoTests' do inherit! :search_paths     # Pods for testing   end   target 'demoUITests' do     inherit! :search_paths     # Pods for testing   end  
    ٣- قد يكون هناك اختلاف في الاسم إذا لم تقم بتسمية مشروعك باسم demo و لا مشكلة في ذلك.
     
    - الآن أصبح ملف الpodfile جاهزا كل ما عليك فعله هو حفظ التغييرات التي قمت بإجرائها عليه ثم إغلاقه.
    - الآن تبقت خطوة أخيرة.. قم بالعودة للterminal و تأكد أنك ما زلت في مسار المشروع و قم بإدخال : 
    pod install 
    و اضغط enter 
    سيبدأ الآن الterminal بتحميل المكتبات التي طلبتها و عندما يكتمل التحميل سيشعرك بذلك كما في الصورة..

     
    الآن اذهب إلى ملف الxcode الذي كنت تعمل به و قم بإغلاقه ثم توجه إلى مجلد المشروع الخاص بك و ستجد أن هناك ملف xcode جديد ظهر لديك في المجلد..

    حيث أن هذا هو نفس مشروعك الذي كنت تعمل به و لكن الفرق الوحيد أنه يضم كل المكتبات التي طلبت تنزيلها.
    و الآن لتتأكد أن التنزيل تم بطريقة صحيحة.. قم بفتح الملف الجديد و اذهب إلى أي كلاس و في أعلا الملف قم بكتابة أمر :
    import JTAppleCalender إذا لم يظهر البرنامج أي مشكلة فهذا يعني أنك قمت بتضمين المكتبة في مشروعك بنجاح.
     
    ملاحظة : قد يظهر الxcode خطأ في البداية عند كتابتك لهذا الأمر.. حينها قم بمسحه و قم بعمل build عن طريق cmd+b ثم اكتب الأمر مرة أخرى و يجب أن يعمل هذه المرة
     
    إلى هنا نصل إلى نهاية الدرس و إن كنت تود تجربة عمل الcalender و استخدام المكتبة فقم بمتابعة الفيديوهات الموجودة في رابط تنزيل المكتبة و قراءة التوجيهات الموجودة هناك.
     
    إلى اللقاء في دروس قريبة قادمة بإذن الله

    مستوى المقال: متوسط

عالم البرمجة

عالم البرمجة مقالات برمجة و دورات مجانية لإحتراف البرمجة هدفنا تبسيط البرمجة ونشرها بيد الكل بشكل ممتع ومتطور ومحدث بإستمرار لمواكبة جديد تطورات البرمجة الحديثة و المتقدمة بدون مقابل