يعرب المصطفى

Members
  • عدد منشوراتي

    5
  • تاريخ الإنضمام

  • تاريخ اخر زياره

السمعه بالموقع

2 Neutral

عن العضو يعرب المصطفى

  • الرتبه
    مبدع جديد
  1. البرنامج المستخدم : xcode 8 اللغة المستخدمة : swift 3 هذا الدرس هو الجزء الثاني من درس الtableview مع الـ Swift إذا كنت لم تشاهد الجزء الأول فقم بمشاهدته الآن من خلال الرابط التالي : في الدرس السابق وصلنا في النهاية إلى هذه النتيجة.. و هي تمثل جدول أو tableview يحوي أسماء الطلاب، و في هذا الدرس سنقوم بتطوير هذا الجدول و تحسينه ليحوي بيانات أكثر عن كل طالب و بالشكل الذي تختاره أنت كمطور. إذا لنبدأ.. الآن إضافةً لعرض أسماء الطلاب نريد عرض بيانات خاصة بهم كالعمر و رقم الجوال و سنقوم بعرض هذه البيانات في الجدول. و بالتالي فأن كل طالب سيكون له ٣ بيانات مختلفة متصلة به و خاصة به و هي الاسم و العمر و رقم الجوال بدلا من الاسم وحده. و بالتالي كيف يمكن أن نربط مجموعة من البيانات لشيء واحد فقط ؟ لو عدنا إلى الarray التي تمثل مصدر البيانات أو الdata source للtableview و التي تحمل اسم students فسنجد أنها تحتوي على أسماء الطلاب فقط و بالتالي هي array من نوع string الآن نحن بحاجة إلى أن نربط كل اسم من هذه الأسماء مع العمر و رقم الهاتف لكل عنصر من العناصر و كأن هذه العناصر ستستبدل بمجموعة تحوي هذه البيانات معا؟ لو فكرنا قليلا.. ما هي الوسيلة المتاحة في swift أو في معظم لغات البرمجة التي تمكنك من ربط عدة بيانات في مجموعة واحدة ؟ الحل ببساطة هو الclass سنقوم بإنشاء كلاس خاص باسم student و سنقوم بوضع الخصائص الخاصة به معا في كلاس واحد : ١- قم بالذهاب إلى file ثم new ثم file ٢- اختر swift file و اضغط على next ٣- قم بتسميته Student و اختر create ملاحظة : من المعتاد دائما البدء بحرف capital لجميع أسماء الكلاسات في المشروع الآن قم بأضافة الكود التالي إلى الملف : //1: class Student { //2: var name:String! var age:Int! var phoneNum:Int! //3: init(name:String,age:Int,phoneNum:Int) { self.name = name self.age = age self.phoneNum = phoneNum } } في الخطوة الأولى قمنا بإنشاء الكلاس Student و في الخطوة الثانية قمنا بإضافة المتغيرات الخاصة بهذا الكلاس و هي الاسم و العمر و رقم الجوال و أخيرا في الخطوة الثالثة قمنا بعمل الinitializer و هي الدالة التي ستستخدم لعمل كائنات أو objects من هذا الكلاس حيث ستستقبل الاسم و العمر و رقم الهاتف لتقوم بعمل أوبجكت جديد يحوي هذه المتغيرات. و الآن قم بالعودة إلى ViewController و قم بتغيير نوع الarray من String إلى Student و قم ببناء العناصر الجديدة لتكون من Students و لتبدو الarray بهذه الطريقة : //1 //var students : [String] = ["محمد","خالد","عمر","أحمد","سامي"] //2 var students : [Student] = [Student(name:"محمد",age:14,phoneNum:054050433), Student(name:"خالد",age:15,phoneNum:054384953), Student(name:"عمر",age:14,phoneNum:054837495), Student(name:"أحمد",age:17,phoneNum:054333874), Student(name:"سامي",age:16,phoneNum:0542030245) ] في الخطوة الأولى قمنا بتحويل الشكل القديم للarray ليكون على شكل comment ( بإمكانك مسحها نهائيا كذلك ) و في الخطوة الثانية قمنا بعمل الarray الجديدة و التي تحوي objects من الStudent class و كل أوبجكت فيها له خصائص الاسم و العمر و رقم الجوال. و الآن نحن بحاجة لقراءة هذه البيانات و وضعها في الtableview. في الشكل السابق للarray كنا فقط بحاجة المتغير الذي يحمل اسم textLabel و الموجود بداخل الcell الخاصة بالtable view حيث نقوم بإسناد قيمة اسم الطالب لهذا المتغير.. لكن المشكلة أن هذا مجرد متغير واحد و نحن بحاجة إلى ٣ متغيرات في كل cell لتحوي الاسم و العمر و رقم الهاتف إذا مالحل ؟ إن الcell أو الخلية التي قمنا باستخدامها هي في الحقيقة الخلية الأساسية في البرنامج و التي لا توفر لك كثير من الخيارات لذا نحن بحاجة إلى عمل cell خاصة بنا و تحوي المتغيرات التي تناسب البرنامج الذي نعمل عليه و سنقوم باستخدامها بدلا من الcell الأساسية. و حتى تقوم بإنشائها : ١- اذهب إلى file ثم new ثم file ٢- هذه المرة سنقوم بعمل cell خاصة بنا لكنها في النهاية ليست إلا cell ترث الخصائص الأساسية من TableViewCell و هو يمثل الكلاس الخاص بالcell الأساسية في الxcode و التي قمنا باستخدامها سابقا ( و بما أننا سنحتاج إلى الوراثة هنا فلن نقوم باختيار swift file و إنشاء كلاس عادي و إنما سنختار cocoa touch class ) ثم اضغط next ٣- في مربع subclass of : قم بتحديد UITableviewCell و قم بتسميتها StudentCell و اختر next ثم create ٤- الآن هذا هو الكلاس الذي سيمثل الcell الجديدة و الذي سيمثل الأكواد التي ستكتب فيها.. لكن أين هي هذه الcell الجديدة في الواجهة ؟ توجه إلى Main storyboard و قم بتحديد الخلية الموجودة في الtableview ملاحطة : إذا لم تكن تظهر لك أي خلية في الtableview فقم بتحديد الtableview و إضافة واحدة من شريط الخصائص كما هو موضح في الصورة التالية : و اجعل هذه الخلية ترث من ال class ( انظر إلى الصورة ) الذي قمنا بعمله للتو و هو StudentCell و ذلك من خلال اختيار شكل المربع ( show the identity inspector ) و من ثم كتابة الاسم في خانة class و بذلك ستمثل هذه الخلية نموذج لشكل كل الخلايا التي سيتم إنشاؤها في الtableview و ما سيجري على شكلها و تصميمها سيجري على كل الخلايا الأخرى في الtableview و لكن حتى تستطيع الوصول إلى هذه الخلية دون غيرها في الكود الخاص بك فأنت بحاجة لإضافة ID خاص بهذه الخلية ليميزها عن غيرها و هذا يتم من خلال تحديد الخلية ثم توجه إلى شريط الخصائص في الجانب الأيمن ستجد خاصية باسم : identifier قم بكتابة الid الذي تجده مناسبا لك مثل : studentCellId على سبيل المثال و لكن تذكره جيدا لأنك ستحتاجه وقت كتابة الكود الخاص بهذه الخلية و الآن قم بتصميم العناصر التي ستحمل بيانات الطلاب و هي تتم بكل بساطة عن طريق إضافة 3 labels للخلية و كل منها سيمثل أحد البيانات ملاحظة : قم بإضافة الأشكال ( labels ) و توزيعها بالطريقة التي تناسبك و لا تنس إضافة الconstraints و إذا أردت إضافتها بسرعة دون الدخول في تفاصيل الconstraints فقم بتحديد العناصر ثم قم بإضافتها كما هو موضح في الصورة : الآن نحن بحاجة لربط الlabels الموجودة في الخلية مع الكلاس الخاص بها حتى تكون لنا قدرة التحكم بها و بقيمها لذلك قم بفتح الكود في نصف الشاشة عن طريق الضغط على أيقونة الدائرتين الموجودة في الزاوية اليمنى من الشريط العلوي تأكد أن الملف المفتوح في النصف الخاص بالكود هو كلاس الStudentCell و إذا لم يكن فتوجه إلى الكلاس من العمود الأيسر الخاص بالملفات و اضغط على alt ثم اسم الكلاس و هو StudentCell توجه الآن إلى أول label و هو الخاص بالاسم و قم بالضغط على ctrl و السحب من الlabel إلى داخل الclass و ستظهر لك نافذة تسأل عن الاسم كما في الصورة قم بتسميته nameLabel و اضغط على connect قم بتكرار نفس العملية للlabel الخاص بالعمر و رقم الهاتف و قم بتسميتهم ageLabel و phoneNumLabel على التوالي. و سيكون الشكل و الكود بهذا الشكل : أخيرا تبقت خطوة أخيرة و هي إضافة القيم المناسبة لكل label في كل خلية و هذا سيتم من خلال الfunction التي تحمل اسم cellForRowAtIndexPath و الموجودة في الكلاس ViewController لذلك توجه إليها و قم بمسح الكود السابق الموجود بداخلها و استبدله بالكود التالي : func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { //1 let cell = tableView.dequeueReusableCell(withIdentifier: "studentCellId") as! StudentCell //2 cell.nameLabel.text = students[indexPath.row].name cell.ageLabel.text = String(students[indexPath.row].age) cell.phoneNumLabel.text = String(students[indexPath.row].phoneNum) return cell } في الخطوة الأولى : قمنا باستخدام الtableview و هو المتغير الذي يمثل الtableview الموجود في الstoryboard و الذي يحوي الخلية و الذي قمنا بإضافته في الدرس السابق و قمنا من خلاله باستدعاء function اسمها dequeueReusableCell و التي تستخدم لجلب الcell من خلال الid الخاص بها و لذلك قمنا بإضافة الid الذي قمنا بإنشائه سابقا إلى الخانة الخاصة به كparameter للfunction ثم أضفنا : as! StudentCell حتى نقوم بعمل casting لهذه الcell لتصبح من نوع StudentCell ملاحظة : إذا كنت لا تعلم ما هو الcasting فيمكنك تجاهله الآن و إضافة الكود كما هو و تعلمه لاحقا و الأن أصبح لدينا cell من نوع StudentCell بمعنى آخر : يمكننا الآن الوصول إلى الlabels الموجودة في الStudentCell و تغيير قيمها اعتمادا على قيم العنصر في الarray و هذا ما قمنا بفعله في الخطوة الثانية و هذا الكود شبيه جدا للكود السابق الذي كان خاصا بإضافة الاسم فقط في كل indexPath من الarray باستثناء إضافة الخصائص الخاصة بكل عنصر للarray و ذلك لأن الarray الآن تحتوي على objects و أنت تريد الوصول إلى متغيرات هذا الobjects فتضيف .name للوصول للاسم مثلا و كذلك الأمر للعمر و رقم الهاتف لاحظ كذلك أننا قمنا بتحويل العمر و رقم الهاتف إلى قيم من نوع String و ذلك لأن القيم الأساسية لها هي في الحقيقة من نوع Int و لابد من تحويلها إلى String لتناسب نوعية المتغير text بداخل الLabel الآن قم بتشغيل البرنامج لتظهر لك بهذا الشكل حيث يظهر الخلية و هوي تحوي عدة بيانات متعلقة بالطالب بدلا من الاسم فقط : إلى هنا نصل معكم إلى نهاية الدرس و أتمنى أن يكون ذا فائدة و نفع للقارئ الكريم و إلى اللقاء في دروس أخرى
  2. البرنامج المستخدم : xcode 8 اللغة المستخدمة : swift 3 هذا الدرس هو الجزء الثاني من درس الtableview في الxcode إذا كنت لم تشاهد الجزء الأول فقم بمشاهدته الآن من خلال الرابط التالي : في الدرس السابق وصلنا في النهاية إلى هذه النتيجة.. و هي تمثل جدول أو tableview يحوي أسماء الطلاب، و في هذا الدرس سنقوم بتطوير هذا الجدول و تحسينه ليحوي بيانات أكثر عن كل طالب و بالشكل الذي تختاره أنت كمطور. إذا لنبدأ.. الآن إضافةً لعرض أسماء الطلاب نريد عرض بيانات خاصة بهم كالعمر و رقم الجوال و سنقوم بعرض هذه البيانات في الجدول. و بالتالي فأن كل طالب سيكون له ٣ بيانات مختلفة متصلة به و خاصة به و هي الاسم و العمر و رقم الجوال بدلا من الاسم وحده. و بالتالي كيف يمكن أن نربط مجموعة من البيانات لشيء واحد فقط ؟ لو عدنا إلى الarray التي تمثل مصدر البيانات أو الdata source للtableview و التي تحمل اسم students فسنجد أنها تحتوي على أسماء الطلاب فقط و بالتالي هي array من نوع string الآن نحن بحاجة إلى أن نربط كل اسم من هذه الأسماء مع العمر و رقم الهاتف لكل عنصر من العناصر و كأن هذه العناصر ستستبدل بمجموعة تحوي هذه البيانات معا؟ لو فكرنا قليلا.. ما هي الوسيلة المتاحة في swift أو في معظم لغات البرمجة التي تمكنك من ربط عدة بيانات في مجموعة واحدة ؟ الحل ببساطة هو الclass سنقوم بإنشاء كلاس خاص باسم student و سنقوم بوضع الخصائص الخاصة به معا في كلاس واحد : ١- قم بالذهاب إلى file ثم new ثم file ٢- اختر swift file و اضغط على next ٣- قم بتسميته Student و اختر create ملاحظة : من المعتاد دائما البدء بحرف capital لجميع أسماء الكلاسات في المشروع الآن قم بأضافة الكود التالي إلى الملف : //1: class Student { //2: var name:String! var age:Int! var phoneNum:Int! //3: init(name:String,age:Int,phoneNum:Int) { self.name = name self.age = age self.phoneNum = phoneNum } } في الخطوة الأولى قمنا بإنشاء الكلاس Student و في الخطوة الثانية قمنا بإضافة المتغيرات الخاصة بهذا الكلاس و هي الاسم و العمر و رقم الجوال و أخيرا في الخطوة الثالثة قمنا بعمل الinitializer و هي الدالة التي ستستخدم لعمل كائنات أو objects من هذا الكلاس حيث ستستقبل الاسم و العمر و رقم الهاتف لتقوم بعمل أوبجكت جديد يحوي هذه المتغيرات. و الآن قم بالعودة إلى ViewController و قم بتغيير نوع الarray من String إلى Student و قم ببناء العناصر الجديدة لتكون من Students و لتبدو الarray بهذه الطريقة : //1 //var students : [String] = ["محمد","خالد","عمر","أحمد","سامي"] //2 var students : [Student] = [Student(name:"محمد",age:14,phoneNum:054050433), Student(name:"خالد",age:15,phoneNum:054384953), Student(name:"عمر",age:14,phoneNum:054837495), Student(name:"أحمد",age:17,phoneNum:054333874), Student(name:"سامي",age:16,phoneNum:0542030245) ] في الخطوة الأولى قمنا بتحويل الشكل القديم للarray ليكون على شكل comment ( بإمكانك مسحها نهائيا كذلك ) و في الخطوة الثانية قمنا بعمل الarray الجديدة و التي تحوي objects من الStudent class و كل أوبجكت فيها له خصائص الاسم و العمر و رقم الجوال. و الآن نحن بحاجة لقراءة هذه البيانات و وضعها في الtableview. في الشكل السابق للarray كنا فقط بحاجة المتغير الذي يحمل اسم textLabel و الموجود بداخل الcell الخاصة بالtable view حيث نقوم بإسناد قيمة اسم الطالب لهذا المتغير.. لكن المشكلة أن هذا مجرد متغير واحد و نحن بحاجة إلى ٣ متغيرات في كل cell لتحوي الاسم و العمر و رقم الهاتف إذا مالحل ؟ إن الcell أو الخلية التي قمنا باستخدامها هي في الحقيقة الخلية الأساسية في البرنامج و التي لا توفر لك كثير من الخيارات لذا نحن بحاجة إلى عمل cell خاصة بنا و تحوي المتغيرات التي تناسب البرنامج الذي نعمل عليه و سنقوم باستخدامها بدلا من الcell الأساسية. و حتى تقوم بإنشائها : ١- اذهب إلى file ثم new ثم file ٢- هذه المرة سنقوم بعمل cell خاصة بنا لكنها في النهاية ليست إلا cell ترث الخصائص الأساسية من TableViewCell و هو يمثل الكلاس الخاص بالcell الأساسية في الxcode و التي قمنا باستخدامها سابقا ( و بما أننا سنحتاج إلى الوراثة هنا فلن نقوم باختيار swift file و إنشاء كلاس عادي و إنما سنختار cocoa touch class ) ثم اضغط next ٣- في مربع subclass of : قم بتحديد UITableviewCell و قم بتسميتها StudentCell و اختر next ثم create ٤- الآن هذا هو الكلاس الذي سيمثل الcell الجديدة و الذي سيمثل الأكواد التي ستكتب فيها.. لكن أين هي هذه الcell الجديدة في الواجهة ؟ توجه إلى Main storyboard و قم بتحديد الخلية الموجودة في الtableview ملاحطة : إذا لم تكن تظهر لك أي خلية في الtableview فقم بتحديد الtableview و إضافة واحدة من شريط الخصائص كما هو موضح في الصورة التالية : و اجعل هذه الخلية ترث من ال class ( انظر إلى الصورة ) الذي قمنا بعمله للتو و هو StudentCell و ذلك من خلال اختيار شكل المربع ( show the identity inspector ) و من ثم كتابة الاسم في خانة class و بذلك ستمثل هذه الخلية نموذج لشكل كل الخلايا التي سيتم إنشاؤها في الtableview و ما سيجري على شكلها و تصميمها سيجري على كل الخلايا الأخرى في الtableview و لكن حتى تستطيع الوصول إلى هذه الخلية دون غيرها في الكود الخاص بك فأنت بحاجة لإضافة ID خاص بهذه الخلية ليميزها عن غيرها و هذا يتم من خلال تحديد الخلية ثم توجه إلى شريط الخصائص في الجانب الأيمن ستجد خاصية باسم : identifier قم بكتابة الid الذي تجده مناسبا لك مثل : studentCellId على سبيل المثال و لكن تذكره جيدا لأنك ستحتاجه وقت كتابة الكود الخاص بهذه الخلية و الآن قم بتصميم العناصر التي ستحمل بيانات الطلاب و هي تتم بكل بساطة عن طريق إضافة 3 labels للخلية و كل منها سيمثل أحد البيانات ملاحظة : قم بإضافة الأشكال ( labels ) و توزيعها بالطريقة التي تناسبك و لا تنس إضافة الconstraints و إذا أردت إضافتها بسرعة دون الدخول في تفاصيل الconstraints فقم بتحديد العناصر ثم قم بإضافتها كما هو موضح في الصورة : الآن نحن بحاجة لربط الlabels الموجودة في الخلية مع الكلاس الخاص بها حتى تكون لنا قدرة التحكم بها و بقيمها لذلك قم بفتح الكود في نصف الشاشة عن طريق الضغط على أيقونة الدائرتين الموجودة في الزاوية اليمنى من الشريط العلوي تأكد أن الملف المفتوح في النصف الخاص بالكود هو كلاس الStudentCell و إذا لم يكن فتوجه إلى الكلاس من العمود الأيسر الخاص بالملفات و اضغط على alt ثم اسم الكلاس و هو StudentCell توجه الآن إلى أول label و هو الخاص بالاسم و قم بالضغط على ctrl و السحب من الlabel إلى داخل الclass و ستظهر لك نافذة تسأل عن الاسم كما في الصورة قم بتسميته nameLabel و اضغط على connect قم بتكرار نفس العملية للlabel الخاص بالعمر و رقم الهاتف و قم بتسميتهم ageLabel و phoneNumLabel على التوالي. و سيكون الشكل و الكود بهذا الشكل : أخيرا تبقت خطوة أخيرة و هي إضافة القيم المناسبة لكل label في كل خلية و هذا سيتم من خلال الfunction التي تحمل اسم cellForRowAtIndexPath و الموجودة في الكلاس ViewController لذلك توجه إليها و قم بمسح الكود السابق الموجود بداخلها و استبدله بالكود التالي : func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { //1 let cell = tableView.dequeueReusableCell(withIdentifier: "studentCellId") as! StudentCell //2 cell.nameLabel.text = students[indexPath.row].name cell.ageLabel.text = String(students[indexPath.row].age) cell.phoneNumLabel.text = String(students[indexPath.row].phoneNum) return cell } في الخطوة الأولى : قمنا باستخدام الtableview و هو المتغير الذي يمثل الtableview الموجود في الstoryboard و الذي يحوي الخلية و الذي قمنا بإضافته في الدرس السابق و قمنا من خلاله باستدعاء function اسمها dequeueReusableCell و التي تستخدم لجلب الcell من خلال الid الخاص بها و لذلك قمنا بإضافة الid الذي قمنا بإنشائه سابقا إلى الخانة الخاصة به كparameter للfunction ثم أضفنا : as! StudentCell حتى نقوم بعمل casting لهذه الcell لتصبح من نوع StudentCell ملاحظة : إذا كنت لا تعلم ما هو الcasting فيمكنك تجاهله الآن و إضافة الكود كما هو و تعلمه لاحقا و الأن أصبح لدينا cell من نوع StudentCell بمعنى آخر : يمكننا الآن الوصول إلى الlabels الموجودة في الStudentCell و تغيير قيمها اعتمادا على قيم العنصر في الarray و هذا ما قمنا بفعله في الخطوة الثانية و هذا الكود شبيه جدا للكود السابق الذي كان خاصا بإضافة الاسم فقط في كل indexPath من الarray باستثناء إضافة الخصائص الخاصة بكل عنصر للarray و ذلك لأن الarray الآن تحتوي على objects و أنت تريد الوصول إلى متغيرات هذا الobjects فتضيف .name للوصول للاسم مثلا و كذلك الأمر للعمر و رقم الهاتف لاحظ كذلك أننا قمنا بتحويل العمر و رقم الهاتف إلى قيم من نوع String و ذلك لأن القيم الأساسية لها هي في الحقيقة من نوع Int و لابد من تحويلها إلى String لتناسب نوعية المتغير text بداخل الLabel الآن قم بتشغيل البرنامج لتظهر لك بهذا الشكل حيث يظهر الخلية و هوي تحوي عدة بيانات متعلقة بالطالب بدلا من الاسم فقط : إلى هنا نصل معكم إلى نهاية الدرس و أتمنى أن يكون ذا فائدة و نفع للقارئ الكريم و إلى اللقاء في دروس أخرى تم ترقية هذا الطرح المميز الى صفحة المقالات
  3. في هذا الدرس سنتعلم كيفية التعامل مع الtableview مع الـ Swift و كيفية إنشائه و بنائه داخل تطبيقك. في البداية ما هو الtableview ؟ الtableview هو أداة من أدوات واجهة المستخدم التي تستخدم لعرض البيانات من خلالها. و تحديدا تستخدم في عرض البيانات التي تكون على شكل مجموعة عناصر مثل قائمة بمحتويات مطعم أو أسماء لطلاب في مدرسة..الخ و الحقيقة أنه لا يكاد يتواجد تطبيق في متجر البرامج دون وجود tableview بما في ذلك التطبيقات الشهيرة كتطبيق facebook فكل البوستات الموجودة في الfacebook و التي تشاهدها في الصفحة الرئيسية عند فتح التطبيق ما هي إلا شرائح من هذا الtableview و كذلك في twitter و instegram... الخ. و لذلك يعتبر الtableview أحد أهم الأدوات الموجودة في برنامج الxcode و من أكثر الأدوات استخداما في بناء التطبيقات إن لم يكن أكثرها لذلك من المهم لمبرمج التطبيقات أن يتعلم طريقة إنشائه و التعامل معه في التطبيق و ما سنقوم بعمله في هذا الدرس هو عرض قائمة لأسماء طلاب في الtableview و لذلك فلنبدأ... في البداية قم بفتح الإكسكود و قم بعمل باختيار create new xcode project ثم single view application و قم بتسميته و حفظه. الآن قم بالتوجه إلى الMain.storyboard لإضافة الtableview إلى تطبيقك. لإدراج الtableview توجه إلى مكتبة العناصر الموجودة على اليسار و قم بالبحث عن tableview كما ثم اسحبه إلى الشاشة كما هو موضح في الصور. ملاحظة: تأكد من سحبك لعنصر الtableview و ليس لعنصر الtableview controller الآن قم بتعديل حجم الtableview ليملأ الشاشة بأكملها قم بإضافة الconstraints كما هو موضح في الصورة إذا كنت لا تعلم ما هي الconstraints فيمكنك تجاهلها الآن، و لكنها باختصار طريقة لإظهار الui أو عناصر واجهة المستخدم كالtableview بشكل مناسب في جميع الشاشات المختلفة الحجم. الآن تم إضافة الtableview إلي التطبيق يمكنك عمل run و تشغيل التطبيق الآن، ستلاحظ وجود جدول محتويات بخلايا فارغة و الآن سنقوم بإكمال العملية لملء هذه الخانات ببيانات معينة: إن الview controller الموجودة في الstoryboard و التي قمنا بإضافة الtableview إليها تمتلك ملف برمجي متصل بها يمكنك من كتابة الأكواد الخاصة بهذا الview controller بداخله و حتى تعرف ما هو هذا الملف البرمجي قم بالضغط على الدائرة الصفراء في زاوية الشريط العلوي للview controller ثم قم باختيار المربع من الشريط الأيمن في البرنامج ثم لاحظ خانة الcustom claass ستجد أن الclass أو ملف الكود المرتبط بهذا الview controller هو ملف ViewController و الذي تم إنشاؤه تلقائيا، لاحظ الصورة: الآن من الشريط العلوي تماما في البرنامج قم باختيار رمز الدائرتين لعرض ملف الكود ViewController بجانب الmain story board الآن قم بالضغط على زر ctrl و قم بالسحب من الtableview الذي قمت بإضافته إلى داخل الكلاس على الجانب الآخر و قم بتسميته studentsTebleview أو namesTableview الآن أصبح لدينا متغير بداخل الviewController باسم studentsTableview ليمثل الtableview على شكل كود. حتى نملأ هذا الtableview بالمحتويات فإننا نحتاج أن نخبر البرنامج أن مصدر هذه المحتويات سيكون هذا الViewController الذي قمنا بإضافة الstudentsTableview إليه، لكن كيف يتم ذلك ؟ اذهب إلى الfunction التي تحمل اسم viewDidLoad و التي يتم استدعاؤها تلقائيا و يتم تنفيذ الكود الذي بداخلها تلقائيا بمجرد تشغيل البرنامج و اكتب بداخلها : override func viewDidLoad() { super.viewDidLoad() // Do any additional setup after loading the view, typically from a nib. studentsTableview.dataSource = self } و بهذا تكون قد عرّفت أن مصدر البيانات سيكون هذا الاوبجكت من الكلاس ViewController لكن ستلاحظ ظهور خطأ و هذا الخطأ يظهر بسبب أن نوع المتغير الذي يجب أن يكون مصدرا لبيانات الtableview يجب أن يكون من نوع UITableViewDataSource بينما نلاحظ أن الكلاس ViewController يرث من الكلاس UIViewController و ليس من UITableViewDataSource لذلك لابد أن يرث كذلك من UITableViewDataSource و بالتالي قم بإضافة هذا إلى الكلاس ViewController ليظهر كما هو موضح في الصورة : كما تلاحظ ما زال هناك خطأ و هذا الخطأ بسبب عدم كتابة الfunctions التي تتطلبها الوراثة من UITableViewDataSource و عدد الfunctions التي يجب كتابتها هو ٣ دوال رئيسية و هم : - numberOfSections : و هي التي ستقوم فيها بإرجاع عدد المجموعات لتحوي التصنيفات المختلفة ( و غالبا ما تستخدم مجموعة واحدة فقط ) - numberOfRowsInSection : و هي التي تستخدم لتحديد عدد الصفوف أو الخلايا في كل مجموعة - cellForRowAtIndexPath : و هي التي تستخدم لتحديد بيانات كل خلية في الtableview و لكتابة هذه الfunctions قم بكتابة العناوين الموضحة في الأعلى و سيقوم الإكمال التلقائي في البرنامج باقتراح خيارات لـإكمالها ثم اضغط على enter حالما تجد الfunction الصحيحة التي تريدها.. سيكون شكل الكود بعد كتابة الfunctions كالتالي : في الfunction الأولى قم بكتابة return 1 لتقوم بعمل مجموعة واحدة للخلايا في الfunction الثانية قم بكتابة return 7 كعدد مبدئي لإعادة ٧ صفوف في الtableview و في الfunction الثالثة كما هو موضح من الfunction أن هذه الfunction يجب أن تقوم بإرجاع قيمة من UITAbleviewCell و هي الشريحة التي سيتم عرضها في الtableview لذلك مبدئيا قم بكتابة : let cell = UITableViewCell() cell.textLabel?.text = "hello" return cell و ما قمنا بفعله هنا هو إنشاء cell من نوع UITableviewCell و قمنا بجعل الtext الخاص بها ليحوي كلمة hello و هذا سيطبق على كل الخلايا السبعة في الtableview و بالتالي سيكون شكل الكود كالتالي : الآن قم بتشغيل البرنامج لاختبار الكود سيظهر لك ٧ خلايا في جدول محتويات و كلها تحتوي على كلمة hello كما يبدو في الصورة.. أخيرا! قمنا بعمل tableview يقوم بعرض محتويات قمنا بتحديدها على الcell و لكن تبقى المشكلة في أن هذه المحتويات كلها متشابهة و لا تحوي مجموعة لأسماء الطلاب كما نريد فكيف نقوم بذلك ؟ عادة عند التعامل مع الtableview لابد أن يكون هناك مصدر للبيانات لأخذ البيانات منه و عادة ما يكون هذا المصدر على شكل array لذلك قم بعمل array من نوع [String] لتحوي أسماء الطلاب و قم بوضع الأسماء كما في الصورة أو كما تريد : الآن قم بالتوجه إلى الfunction التي تحمل الاسم numberOfRowsInSection و قم بإعادة عدد عناصر الarray بدلا من عدد ٧ العشوائي. return students.count الآن توجه إلى الfunction التي تحمل اسم cellForRowAtIndexPath و لاحظ أن هذه الfunction تحتوي على بارامتر باسم indexPath. في الحقيقة.. هذه الfunction يتم استدعؤها عدة مرات و ليس مرة واحدة و عدد المرات التي يتم استدعاؤها فيه يساوي عدد الصفوف التي قمت بإرجاعها في الfunction ذات اسم numberOfRowsInSection و بالتالي عدد مرات استدعائها سيكون مساويا لعدد عناصر الstudents array في هذه الحالة حيث يقوم البرنامج بكل مرة بإعادة خلية لتمثل البيانات التي سيتم عرضها في ذلك الصف. المهم في الأمر أن البارامتر indexPath يحتوي على خاصية باسم row من نوع Int. و هذه الخاصية لاتحمل قيمة ثابتة في كل استدعاء للcellForRowAtIndex function و أنما تبدأ بقيمة 0 و في الاستدعاء التالي تزيد بمقدار ١ فتصبح قيمتها ١ ثم تنتقل إلى الاستدعاء التالي لتصبح قيمتها ٢ ثم ٣ ثم ٤... الخ حتى تنتهي عند آخر رقم و الذي يساوي حسب ما فهمنا في الأعلى عدد عناصر الstudents array ناقص واحد ( لأن العد سيبدأ من 0 )... لعلك بدأت تفهم الفكرة.. يمكننا أن نعتمد على هذا المتغير لأخذ البيانات من الarray بالترتيب و إسنادها إلى الخلايا... لذلك بداخل الcellForRowAtIndex function قم بتعديل الكود ليكون كالتالي.. let cell = UITableViewCell() cell.textLabel?.text = students[indexPath.row] return cell و شكل الكود كاملا سيبدو كالتالي... الآن قم بتشغيل البرنامج و انظر إلى النتيجة النهائية إلى هنا نصل إلى نهاية الدرس و سنتناول الموضوع بطريقة متقدمة مستقبلا إن شاء الله.
  4. في هذا الدرس سنتعلم كيفية التعامل مع الtableview في الxcode و كيفية إنشائه و بنائه داخل تطبيقك. في البداية ما هو الtableview ؟ الtableview هو أداة من أدوات واجهة المستخدم التي تستخدم لعرض البيانات من خلالها. و تحديدا تستخدم في عرض البيانات التي تكون على شكل مجموعة عناصر مثل قائمة بمحتويات مطعم أو أسماء لطلاب في مدرسة..الخ و الحقيقة أنه لا يكاد يتواجد تطبيق في متجر البرامج دون وجود tableview بما في ذلك التطبيقات الشهيرة كتطبيق facebook فكل البوستات الموجودة في الfacebook و التي تشاهدها في الصفحة الرئيسية عند فتح التطبيق ما هي إلا شرائح من هذا الtableview و كذلك في twitter و instegram... الخ. و لذلك يعتبر الtableview أحد أهم الأدوات الموجودة في برنامج الxcode و من أكثر الأدوات استخداما في بناء التطبيقات إن لم يكن أكثرها لذلك من المهم لمبرمج التطبيقات أن يتعلم طريقة إنشائه و التعامل معه في التطبيق و ما سنقوم بعمله في هذا الدرس هو عرض قائمة لأسماء طلاب في الtableview و لذلك فلنبدأ... في البداية قم بفتح الإكسكود و قم بعمل باختيار create new xcode project ثم single view application و قم بتسميته و حفظه. الآن قم بالتوجه إلى الMain.storyboard لإضافة الtableview إلى تطبيقك. لإدراج الtableview توجه إلى مكتبة العناصر الموجودة على اليسار و قم بالبحث عن tableview كما ثم اسحبه إلى الشاشة كما هو موضح في الصور. ملاحظة: تأكد من سحبك لعنصر الtableview و ليس لعنصر الtableview controller الآن قم بتعديل حجم الtableview ليملأ الشاشة بأكملها قم بإضافة الconstraints كما هو موضح في الصورة إذا كنت لا تعلم ما هي الconstraints فيمكنك تجاهلها الآن، و لكنها باختصار طريقة لإظهار الui أو عناصر واجهة المستخدم كالtableview بشكل مناسب في جميع الشاشات المختلفة الحجم. الآن تم إضافة الtableview إلي التطبيق يمكنك عمل run و تشغيل التطبيق الآن، ستلاحظ وجود جدول محتويات بخلايا فارغة و الآن سنقوم بإكمال العملية لملء هذه الخانات ببيانات معينة: إن الview controller الموجودة في الstoryboard و التي قمنا بإضافة الtableview إليها تمتلك ملف برمجي متصل بها يمكنك من كتابة الأكواد الخاصة بهذا الview controller بداخله و حتى تعرف ما هو هذا الملف البرمجي قم بالضغط على الدائرة الصفراء في زاوية الشريط العلوي للview controller ثم قم باختيار المربع من الشريط الأيمن في البرنامج ثم لاحظ خانة الcustom claass ستجد أن الclass أو ملف الكود المرتبط بهذا الview controller هو ملف ViewController و الذي تم إنشاؤه تلقائيا، لاحظ الصورة: الآن من الشريط العلوي تماما في البرنامج قم باختيار رمز الدائرتين لعرض ملف الكود ViewController بجانب الmain story board الآن قم بالضغط على زر ctrl و قم بالسحب من الtableview الذي قمت بإضافته إلى داخل الكلاس على الجانب الآخر و قم بتسميته studentsTebleview أو namesTableview الآن أصبح لدينا متغير بداخل الviewController باسم studentsTableview ليمثل الtableview على شكل كود. حتى نملأ هذا الtableview بالمحتويات فإننا نحتاج أن نخبر البرنامج أن مصدر هذه المحتويات سيكون هذا الViewController الذي قمنا بإضافة الstudentsTableview إليه، لكن كيف يتم ذلك ؟ اذهب إلى الfunction التي تحمل اسم viewDidLoad و التي يتم استدعاؤها تلقائيا و يتم تنفيذ الكود الذي بداخلها تلقائيا بمجرد تشغيل البرنامج و اكتب بداخلها : override func viewDidLoad() { super.viewDidLoad() // Do any additional setup after loading the view, typically from a nib. studentsTableview.dataSource = self } و بهذا تكون قد عرّفت أن مصدر البيانات سيكون هذا الاوبجكت من الكلاس ViewController لكن ستلاحظ ظهور خطأ و هذا الخطأ يظهر بسبب أن نوع المتغير الذي يجب أن يكون مصدرا لبيانات الtableview يجب أن يكون من نوع UITableViewDataSource بينما نلاحظ أن الكلاس ViewController يرث من الكلاس UIViewController و ليس من UITableViewDataSource لذلك لابد أن يرث كذلك من UITableViewDataSource و بالتالي قم بإضافة هذا إلى الكلاس ViewController ليظهر كما هو موضح في الصورة : كما تلاحظ ما زال هناك خطأ و هذا الخطأ بسبب عدم كتابة الfunctions التي تتطلبها الوراثة من UITableViewDataSource و عدد الfunctions التي يجب كتابتها هو ٣ دوال رئيسية و هم : - numberOfSections : و هي التي ستقوم فيها بإرجاع عدد المجموعات لتحوي التصنيفات المختلفة ( و غالبا ما تستخدم مجموعة واحدة فقط ) - numberOfRowsInSection : و هي التي تستخدم لتحديد عدد الصفوف أو الخلايا في كل مجموعة - cellForRowAtIndexPath : و هي التي تستخدم لتحديد بيانات كل خلية في الtableview و لكتابة هذه الfunctions قم بكتابة العناوين الموضحة في الأعلى و سيقوم الإكمال التلقائي في البرنامج باقتراح خيارات لـإكمالها ثم اضغط على enter حالما تجد الfunction الصحيحة التي تريدها.. سيكون شكل الكود بعد كتابة الfunctions كالتالي : في الfunction الأولى قم بكتابة return 1 لتقوم بعمل مجموعة واحدة للخلايا في الfunction الثانية قم بكتابة return 7 كعدد مبدئي لإعادة ٧ صفوف في الtableview و في الfunction الثالثة كما هو موضح من الfunction أن هذه الfunction يجب أن تقوم بإرجاع قيمة من UITAbleviewCell و هي الشريحة التي سيتم عرضها في الtableview لذلك مبدئيا قم بكتابة : let cell = UITableViewCell() cell.textLabel?.text = "hello" return cell و ما قمنا بفعله هنا هو إنشاء cell من نوع UITableviewCell و قمنا بجعل الtext الخاص بها ليحوي كلمة hello و هذا سيطبق على كل الخلايا السبعة في الtableview و بالتالي سيكون شكل الكود كالتالي : الآن قم بتشغيل البرنامج لاختبار الكود سيظهر لك ٧ خلايا في جدول محتويات و كلها تحتوي على كلمة hello كما يبدو في الصورة.. أخيرا! قمنا بعمل tableview يقوم بعرض محتويات قمنا بتحديدها على الcell و لكن تبقى المشكلة في أن هذه المحتويات كلها متشابهة و لا تحوي مجموعة لأسماء الطلاب كما نريد فكيف نقوم بذلك ؟ عادة عند التعامل مع الtableview لابد أن يكون هناك مصدر للبيانات لأخذ البيانات منه و عادة ما يكون هذا المصدر على شكل array لذلك قم بعمل array من نوع [String] لتحوي أسماء الطلاب و قم بوضع الأسماء كما في الصورة أو كما تريد : الآن قم بالتوجه إلى الfunction التي تحمل الاسم numberOfRowsInSection و قم بإعادة عدد عناصر الarray بدلا من عدد ٧ العشوائي. return students.count الآن توجه إلى الfunction التي تحمل اسم cellForRowAtIndexPath و لاحظ أن هذه الfunction تحتوي على بارامتر باسم indexPath. في الحقيقة.. هذه الfunction يتم استدعؤها عدة مرات و ليس مرة واحدة و عدد المرات التي يتم استدعاؤها فيه يساوي عدد الصفوف التي قمت بإرجاعها في الfunction ذات اسم numberOfRowsInSection و بالتالي عدد مرات استدعائها سيكون مساويا لعدد عناصر الstudents array في هذه الحالة حيث يقوم البرنامج بكل مرة بإعادة خلية لتمثل البيانات التي سيتم عرضها في ذلك الصف. المهم في الأمر أن البارامتر indexPath يحتوي على خاصية باسم row من نوع Int. و هذه الخاصية لاتحمل قيمة ثابتة في كل استدعاء للcellForRowAtIndex function و أنما تبدأ بقيمة 0 و في الاستدعاء التالي تزيد بمقدار ١ فتصبح قيمتها ١ ثم تنتقل إلى الاستدعاء التالي لتصبح قيمتها ٢ ثم ٣ ثم ٤... الخ حتى تنتهي عند آخر رقم و الذي يساوي حسب ما فهمنا في الأعلى عدد عناصر الstudents array ناقص واحد ( لأن العد سيبدأ من 0 )... لعلك بدأت تفهم الفكرة.. يمكننا أن نعتمد على هذا المتغير لأخذ البيانات من الarray بالترتيب و إسنادها إلى الخلايا... لذلك بداخل الcellForRowAtIndex function قم بتعديل الكود ليكون كالتالي.. let cell = UITableViewCell() cell.textLabel?.text = students[indexPath.row] return cell و شكل الكود كاملا سيبدو كالتالي... الآن قم بتشغيل البرنامج و انظر إلى النتيجة النهائية إلى هنا نصل إلى نهاية الدرس و سنتناول الموضوع بطريقة متقدمة مستقبلا إن شاء الله. تم ترقية هذا الطرح المميز الى صفحة المقالات
  5. اللغة المستخدمة : swift 3 البرنامج المستخدم : xcode 8 في هذا الدرس سوف نتعلم طريقة تطبيق الsingleton design pattern في برنامج الxcode و في لغة برمجة swift لكن في البداية لمأخذ مقدمة بسيطة عن الdesign pattern ، إذا ما هو الdesign pattern ؟ الdesign pattern هي طريقة معينة أو نمط معين يستخدمه المبرمج لكتابة الكود البرمجي. لكن لماذا يستخدم هذه الطرق عوضا عن أي طريقة أخرى؟ -في البرمجة وارد جدا أن تتعرض للمشكلات و أنا لا أتحدث هنا عن مشكلات الoutput فقط و إنما قد تواجه مشاكل معينة متعلقة بالطريقة التي قمت ببناء الكود عليها و هذه المشكلات غالبا ما تتواجد فيها خاصيتين رئيسيتين : أن هذه المشكلات تحدث مع المبرمجين بشكل متكرر . غالبا عند التعرض لأحد هذه المشكلات فإن إصلاحها سيكون مكلفا بمعنى أن المبرمج سيحتاج إلى إعادة كتابة كمية ليست بالقليلة من الأكواد لإصلاح المشكلة و الوصول إلى حل. و لذلك يتم اسخدام طرق معينة لبناء الكود البرمجي تسمى design patterns. لنفرض أنك تعمل على تطبيق آيفون خاص بإدارة حسابات بنكية و لديك class باسم bankManager حيث يستخدم هذا الكلاس لإدارة كل العمليات المتعلقة بالبنك فعلى سبيل المثال يوجد به function خاصة بإيداع الأموال في حساب ما.. التي تتلقى باراميتر للid الخاص بالحساب و تتلقى بارامتر آخر لكمية المبلغ الذي سيتم إيداعه كذلك يحوي هذا الحساب function لسحب المبلغ و أخرى لتحويل المبلغ لحساب آخر.. الخ و بالتالي فإن هذا الclass سيحوي كل هذه الأوامر المهة التي ستستخدم في التطبيق. و هذه الأوامر سستستخدمها في كل الclasses التي ستقوم بإنشائها في تطبيقك بمعنى آخر.. ستحتاج لأن يكون لديك object من الكلاس bankManager في كل الclasses لديك في التطبيق لأنك ستحتاج حتما لاستخدام الأوامر المهمة في يحويها هذا الclass في أغلب الclasses في تطبيقك. لكن هل إنشاء object من الbankManager في كل الكلاسات التي لديك هي طريقة جيدة للعمل مع هذا الكلاس ؟ بمعنى آخر هل من المناسب إنشاء عدد من الobjects من كلاس الbankManager أم يجب أن يكون لدينا فقط object واحد مشترك بين كل الكلاسات ؟ الحقيقة أن إنشاء object واحد فقط مشترك بين كل الكلاسات هي الطريقة المثلى للتعامل مع ال objects من هذا الكلاس و لذلك فإنك بطريقة ما تحتاج لأن تجبر الكلاس على إنشاء object واحد فقط و إرجاع نفس الobject في كل مرة يتم فيها محاولة عمل object جديد من هذا الكلاس. لكن كيف يتم ذلك ؟ ذلك يتم من خلال ما يعرف بالsingleton object أو الsingleton design pattern إذا لنبدأ تطبيق ذلك عمليا : -في البداية افتح الxcode قم بإنشاء مشروع جديد (create new xcode project > single view application ) و قم بتسميته Singleton. - الآن قم بعمل كلاس جديد و قم بتسميته bankManager. - في البداية و كما تعلم نحن بحاجة إلى استخدام object مشترك بين كل الكلاسات و لعل كلمة مشترك ستقودك الى التفكير ب static variable، بالفعل سنحتاج إلى عمل static variable لذلك توجه إلى الbankManager و قم بإضافة object من نوع الكلاس نفسه و هو الbankManager و قم بجعله static و لأن هذا الobject سيبدأ بقيمة nil ثم سيكون ذا قيمة من نوعBankManager عندما يتم استدعاؤه لذلك يجب أن يكون هذا الobject من نوع optional لذلك لا تنس إضافة ( ؟ ) في نهاية تعريفه. - الآن أصبح لدينا أوبجكت مشترك أو يمكن أن يكون مشتركا بين كل الكلاسات لأنه من نوع static. هل هذا يكفي ؟ بالطبع لا. من الذي سيحدد فيما إذا كان الobject قد تم إنشاؤه و بالتالي إعادته نفسه أو إنشاء object جديد في حال أن قيمة الobject في الحقيقة تساوي nil لذا هل يمكنك التفكير بالخطوة القادمة ؟ - الحل هو عمل function تقوم بالمطلوب حيث ستقوم هذه الfunction بالتأكد أن الobject قد تم إنشاؤه و في حال كان الobject قد تم إنشاؤه بالفعل فإنها ستعيد هذا الobject bankManager الذي قمنا بإنشائه في الأعلى و إلا فإنها ستقوم بإنشائه إولا ثم إرجاعه بعد إنشائه. ولأن هذه الfunction سوف تقوم باستخدام object من نوع static إذا هي بحاجة أن تكون static كذلك و بالتالي ستكون الfunction كالتالي : -ملاحظة: من الشائع في برمجة - بعض الأحيان - الآيفون تسمية هذه الfunction اسم مشابه لsharedObject أو sharedManager - قد يرد إلى ذهنك الآن أننا سنستخدم هذه الfunction دائما إذا ما أردنا الوصول إلى الobject مما يعني أننا لن نصل إلى الobject مباشرة عن طريق استدعائه بشكل مباشر باستخدام BankManager.bankManager و الحقيقة أن استدعاءه بهذه الطريقة قد يسبب بعض المشاكل، مثلا: قد تقوم باستدعائه في أحد الكلاسات بهذه الطريقة و قيمته في ذلك التوقيت تساوي nil و فور محاولتك استخدام اي متغير أو function بداخل الكلاس BankManager فأن البرنامج سيتوقف لمحاولتك استدعاء function لعنصر قيمته في الحقيقة تساوي nil و لحل هذه المشكلة و حتى تقطع أي مجال لاستدعاء الobject بهذه الطريقة المباشرة قم بعمل الstatic object ليكون private و بالتالي سيظهر الكود بهذه الطريقة - هل انتهى الأمر تماما؟ في الحقيقة ليس بعد. ماذا إن قمت خطأً بعمل object من كلاس الBankManager بالطريقة العادية لأنشاء Object من الكلاسات في سويفت ؟ أو افرض أنك تعمل في فريق من المبرمجين و قام مبرمج آخر باستكمال العمل من بعدك حينها ستحتاج إلى منعه من عمل object بالطريقة العادية حتى لا تسبب مشاكل أثناء العمل؟ لكن كيف يتم ذلك ؟ كل ما عليك فعله هو أن تجعل الfunction التي تثوم بعمل الobject بطريقة عادية لتكون من نوع private و بالتالي لن يكون بالإمكان استدعاءها خارج الكلاس و سيكون المبرمج مجبرا على استخدام الfunction المسماة sharedObject و الآن هل انتهى الأمر ؟ نعم انتهى الأمر هنا و أصبح الsingleton object جاهزا للاستخدام أخيرا. بقي الإشارة إلى نقطة مهمة، إن كنت من مبرمجيswift المتمرسين، فلعلك لاحظت أن بعض الclasses التي تقوم باستخدامها هي في الحقيقة تطبق الsingleton pattern و من هذه الكلاسات : NSUserDefaults ----> var userDefaults = NSUserDefaults.standardUserDefaults() UIScreen ----> var mainSecreen = UIScreen.mainScreen UIApplication ----> var application = UIApplication.sharedApplication -- لاحظ أن الوصول للshared object يمكن أن يكون عن طريق static method كما شرحنا في هذا الدرس و قد يكون عن طريق static variable ختاما.. أتمنى أن أكون وفقت في الشرح و إيصال الفكرة و أسأل الله أن يجعله من العلم الذي يُنتفع به .
  6. اللغة المستخدمة : swift 3 البرنامج المستخدم : xcode 8 في هذا الدرس سوف نتعلم طريقة تطبيق الsingleton design pattern في برنامج الxcode و في لغة برمجة swift لكن في البداية لمأخذ مقدمة بسيطة عن الdesign pattern ، إذا ما هو الdesign pattern ؟ الdesign pattern هي طريقة معينة أو نمط معين يستخدمه المبرمج لكتابة الكود البرمجي. لكن لماذا يستخدم هذه الطرق عوضا عن أي طريقة أخرى؟ -في البرمجة وارد جدا أن تتعرض للمشكلات و أنا لا أتحدث هنا عن مشكلات الoutput فقط و إنما قد تواجه مشاكل معينة متعلقة بالطريقة التي قمت ببناء الكود عليها و هذه المشكلات غالبا ما تتواجد فيها خاصيتين رئيسيتين : أن هذه المشكلات تحدث مع المبرمجين بشكل متكرر . غالبا عند التعرض لأحد هذه المشكلات فإن إصلاحها سيكون مكلفا بمعنى أن المبرمج سيحتاج إلى إعادة كتابة كمية ليست بالقليلة من الأكواد لإصلاح المشكلة و الوصول إلى حل. و لذلك يتم اسخدام طرق معينة لبناء الكود البرمجي تسمى design patterns. لنفرض أنك تعمل على تطبيق آيفون خاص بإدارة حسابات بنكية و لديك class باسم bankManager حيث يستخدم هذا الكلاس لإدارة كل العمليات المتعلقة بالبنك فعلى سبيل المثال يوجد به function خاصة بإيداع الأموال في حساب ما.. التي تتلقى باراميتر للid الخاص بالحساب و تتلقى بارامتر آخر لكمية المبلغ الذي سيتم إيداعه كذلك يحوي هذا الحساب function لسحب المبلغ و أخرى لتحويل المبلغ لحساب آخر.. الخ و بالتالي فإن هذا الclass سيحوي كل هذه الأوامر المهة التي ستستخدم في التطبيق. و هذه الأوامر سستستخدمها في كل الclasses التي ستقوم بإنشائها في تطبيقك بمعنى آخر.. ستحتاج لأن يكون لديك object من الكلاس bankManager في كل الclasses لديك في التطبيق لأنك ستحتاج حتما لاستخدام الأوامر المهمة في يحويها هذا الclass في أغلب الclasses في تطبيقك. لكن هل إنشاء object من الbankManager في كل الكلاسات التي لديك هي طريقة جيدة للعمل مع هذا الكلاس ؟ بمعنى آخر هل من المناسب إنشاء عدد من الobjects من كلاس الbankManager أم يجب أن يكون لدينا فقط object واحد مشترك بين كل الكلاسات ؟ الحقيقة أن إنشاء object واحد فقط مشترك بين كل الكلاسات هي الطريقة المثلى للتعامل مع ال objects من هذا الكلاس و لذلك فإنك بطريقة ما تحتاج لأن تجبر الكلاس على إنشاء object واحد فقط و إرجاع نفس الobject في كل مرة يتم فيها محاولة عمل object جديد من هذا الكلاس. لكن كيف يتم ذلك ؟ ذلك يتم من خلال ما يعرف بالsingleton object أو الsingleton design pattern إذا لنبدأ تطبيق ذلك عمليا : -في البداية افتح الxcode قم بإنشاء مشروع جديد (create new xcode project > single view application ) و قم بتسميته Singleton. - الآن قم بعمل كلاس جديد و قم بتسميته bankManager. - في البداية و كما تعلم نحن بحاجة إلى استخدام object مشترك بين كل الكلاسات و لعل كلمة مشترك ستقودك الى التفكير ب static variable، بالفعل سنحتاج إلى عمل static variable لذلك توجه إلى الbankManager و قم بإضافة object من نوع الكلاس نفسه و هو الbankManager و قم بجعله static و لأن هذا الobject سيبدأ بقيمة nil ثم سيكون ذا قيمة من نوعBankManager عندما يتم استدعاؤه لذلك يجب أن يكون هذا الobject من نوع optional لذلك لا تنس إضافة ( ؟ ) في نهاية تعريفه. - الآن أصبح لدينا أوبجكت مشترك أو يمكن أن يكون مشتركا بين كل الكلاسات لأنه من نوع static. هل هذا يكفي ؟ بالطبع لا. من الذي سيحدد فيما إذا كان الobject قد تم إنشاؤه و بالتالي إعادته نفسه أو إنشاء object جديد في حال أن قيمة الobject في الحقيقة تساوي nil لذا هل يمكنك التفكير بالخطوة القادمة ؟ - الحل هو عمل function تقوم بالمطلوب حيث ستقوم هذه الfunction بالتأكد أن الobject قد تم إنشاؤه و في حال كان الobject قد تم إنشاؤه بالفعل فإنها ستعيد هذا الobject bankManager الذي قمنا بإنشائه في الأعلى و إلا فإنها ستقوم بإنشائه إولا ثم إرجاعه بعد إنشائه. ولأن هذه الfunction سوف تقوم باستخدام object من نوع static إذا هي بحاجة أن تكون static كذلك و بالتالي ستكون الfunction كالتالي : -ملاحظة: من الشائع في برمجة - بعض الأحيان - الآيفون تسمية هذه الfunction اسم مشابه لsharedObject أو sharedManager - قد يرد إلى ذهنك الآن أننا سنستخدم هذه الfunction دائما إذا ما أردنا الوصول إلى الobject مما يعني أننا لن نصل إلى الobject مباشرة عن طريق استدعائه بشكل مباشر باستخدام BankManager.bankManager و الحقيقة أن استدعاءه بهذه الطريقة قد يسبب بعض المشاكل، مثلا: قد تقوم باستدعائه في أحد الكلاسات بهذه الطريقة و قيمته في ذلك التوقيت تساوي nil و فور محاولتك استخدام اي متغير أو function بداخل الكلاس BankManager فأن البرنامج سيتوقف لمحاولتك استدعاء function لعنصر قيمته في الحقيقة تساوي nil و لحل هذه المشكلة و حتى تقطع أي مجال لاستدعاء الobject بهذه الطريقة المباشرة قم بعمل الstatic object ليكون private و بالتالي سيظهر الكود بهذه الطريقة - هل انتهى الأمر تماما؟ في الحقيقة ليس بعد. ماذا إن قمت خطأً بعمل object من كلاس الBankManager بالطريقة العادية لأنشاء Object من الكلاسات في سويفت ؟ أو افرض أنك تعمل في فريق من المبرمجين و قام مبرمج آخر باستكمال العمل من بعدك حينها ستحتاج إلى منعه من عمل object بالطريقة العادية حتى لا تسبب مشاكل أثناء العمل؟ لكن كيف يتم ذلك ؟ كل ما عليك فعله هو أن تجعل الfunction التي تثوم بعمل الobject بطريقة عادية لتكون من نوع private و بالتالي لن يكون بالإمكان استدعاءها خارج الكلاس و سيكون المبرمج مجبرا على استخدام الfunction المسماة sharedObject و الآن هل انتهى الأمر ؟ نعم انتهى الأمر هنا و أصبح الsingleton object جاهزا للاستخدام أخيرا. بقي الإشارة إلى نقطة مهمة، إن كنت من مبرمجيswift المتمرسين، فلعلك لاحظت أن بعض الclasses التي تقوم باستخدامها هي في الحقيقة تطبق الsingleton pattern و من هذه الكلاسات : NSUserDefaults ----> var userDefaults = NSUserDefaults.standardUserDefaults() UIScreen ----> var mainSecreen = UIScreen.mainScreen UIApplication ----> var application = UIApplication.sharedApplication -- لاحظ أن الوصول للshared object يمكن أن يكون عن طريق static method كما شرحنا في هذا الدرس و قد يكون عن طريق static variable ختاما.. أتمنى أن أكون وفقت في الشرح و إيصال الفكرة و أسأل الله أن يجعله من العلم الذي يُنتفع به . تم ترقية هذا الطرح المميز الى صفحة المقالات
  7. بسم الله
  8. إصدار الxcode المستخدم : 8.0 لغة سويفت 3 في هذا الدرس سنتعلم طريقة إضافة خصائص إضافية في شريط الخصائص ( properties inspector ) في برنامج الxcode بطريقة سهلة و بسيطة حيث ستتمكن من إضافة مؤثرات بصرية إضافية لعناصر واجهة المستخدم كالحد (stroke or border ) و الزوايا الدائرية للأشكال.. مثلا سيكون بإمكانك عمل الظل و الحدود مع الزوايا الدائرية للview و ال label كما هو موضح في الصورة التالية. لاحظ وجود خيارات جديدة في الشريط الأيمن للتحكم بقيم الحد و الظل و الزوايا الدائرية إذن لنبدأ الدرس.. -في البداية.. قم بفتح الxcode و اختر create new xcode project ثم اختر single view application - قم بعمل كلاس جديد عن طريق File > New > File أو بالضغط على cmd+n ثم اختر cocoa touch class -قم بتسمية الclass بأي اسم يناسبك و تأكد من اختيار UIView عند Subclass of: كما هو موضح في الصورة ثم اضغط next الآن قم بإضافة IBDesignable قبل بداية التعريف بالكلاس في كلاس CustomizableView ليبدو بهذه الطريقة: import UIKit @IBDesignable class CustomizableView: UIView { } هذه الكلمة التي قمت بإضافتها تعطيك إمكانية ربط الكلاس مع الmain story board بحيث يقوم الاكس كود بمزامنة التغييرات التي تجريها على هذا الكلاس مع ال story board و إظهار النتائج مباشرة دون الحاجة إلى تشغيل الsimulator الاختبار النتيجة التي توصلت إليها الآن قم بإضافة الكود التالي إلى الكلاس.. @IBInspectable var cornerRadius:CGFloat = 0{ didSet{ self.layer.cornerRadius = cornerRadius } } -كما تلاحظ في البداية قمنا بإضافة @IBInspectable وهذه الكلمة تسبق المتغير الذي يحمل اسم cornerRadius و هذا أيضا يربط الكلاس مع الstory obard بطريقة أخرى بحيث يمكنك الآن التحكم بقيمة هذا المتغير من شريط الخصائص في الstory board مما سيؤدي إلى تغير قيمة هذا المتغير بناء على القيم المحددة في ال stroy board - بعد ذلك قمنا بإضافة المتغير cornerRadius و هو الذي سنستخدمه لتغيير الزوايا المنحنية في الview إلى زوايا دائرية و اخترنا نوع القيمة لتكون CGFloat و هو النوع المناسب لهذه الخاصية. - قمنا بإسناد القيمة 0 للمتغير كقيمة ابتدائية ثم بعد ذلك اضفنا الأقواس و هذه الأقواس تساعدك في إضافة تفاصيل أخرى للمتغير. - بداخل الأقواس قمنا بإضافة كلمة didSet متبوعة بأقواس و هذه الكلمة تمثل مجموعة من الأوامر يحددها المستخدم بحيث تطبق هذه الأوامر مباشرة بمجرد تغيير قيمة المتغير ، و هي يمكن تشبهها بالدالة function بحيث يقوم المبرمج بتحديد الأوامر التي ستوقوم هذه الدالة بها حالما يتم تغيير قيمة المتغير cornerRadius -اذن ما هي هذه الأوامر التي سيتم استدعاؤها ؟ self.layer.cornerRadius = cornerRadius كما هو موضح فإن self تمثل الاوبجكت من هذا الكلاس customizableView و بما أن هذا الكلاس يرث من الView فإنه سيرث خصائصها و التي منها layer ليقوم باستخدام الخاصية cornerRadius التي بداخل الlayer و التي تتحكم بمدى استدارة زوايا الشكل ثم يقوم بتغيير قيمتها لتساوي المتغير cornerRadius الذي نتحكم بقيمته من الstory board كما ذكرنا سابقا بفضل الخاصية @IBInspectable اذن مالذي سيحدث بالضبط؟ بمجرد إضافة عنصر view في الاكس كود و جعله يرث من الكلاس customizableView ستظهر لك الخواص المعروفة لهذا الview في شريط الخصائص كاللون و الحجم و المحاذاة ..الخ بالإضافة إلى خاصية مميزة جديدة لهذا الview فقط و هي الcornerRadius حيث ستظهر لك في شريط الخصائص بفضل كلمة @IBInspectable ثم سيكون بإمكانك تعديل قيمة ال cornerRadius و بمجرد تعديلها ستستدعى دالة didSet التي قمنا بإضافتها سابقا و بالتالي سيطبق أمر تغيير الcornerRadius الخاص بالشكل لتتغير قيمته من 0 إلى القيمة التي قمت بتحديدها له في شريط الخصائص و أخيرا سترى أن زوايا الview بالفعل أصبحت تتغير مباشرة و هذا بفضل كلمة @IBDesignable التي قمنا بإضافتها للكلاس customizableView لنطبق ذلك عمليا.. - قم بالذهاب إلى الstory board وإضافة view إليها و قم بتلوين هذا الview باللون الذي يناسبك. - الآن اذهب إلى الأيقونة التي بجانب أيقونة الخصائص و التي تسمى identity inspector و قم بتغيير الكلاس الخاص بالview إلى CustomizableView كما هو موضح في الصورة - انتظر قليلا ثم عد إلى الخصائص ستلاحظ و جود الخاصية الجديدة cornerRadius في أعلا شريط الخصائص كما هو واضح في الصورة.. - الآن قم بتغيير القيم لتلاحظ تغير زوايا الشكل بطريقة جميلة يمكنك إضافة المزيد من الخصائص التي بإمكانك التحكم بها بنفس الطريقة.. لإضافة خاصية الحد (border) : @IBInspectable var border:CGFloat = 0{ didSet{ self.layer.borderWidth = border } } لإضافة خاصية الظل ( لا أنصح بها لأنها قد تؤدي إلى بطء البرنامج بسبب معالجة الظل التي تستهلك الكثير من الأداء): @IBInspectable var shadow:CGFloat = 0{ didSet{ self.layer.shadowRadius = shadow } } @IBInspectable var opacity:Float = 0{ didSet{ self.layer.shadowOpacity = opacity/20 } } @IBInspectable var offset:CGFloat = 0{ didSet{ self.layer.shadowOffset.height = offset self.layer.shadowOffset.width = offset } } هذه الإضافات ليست خاصة للview فقط و إنما يمكنك إضافتها لأي عنصر رسومي في البرنامج فمثلا: بإمكانك فعل المثل للlabel كل ما عليك فعله : - قم بعمل كلاس جديد باسم customizableLabel على سبيل المثال - اجعله يرث من UILabel في خيار subclass of عند إنشاء الكلاس - قم بإضافة كلمة @IBDesignable عند بداية الكلاس -قم بنسخ نفس الكود الخاص بالcustomizableView و لصقه في كلاس customizableLabel - استمتع
  9. إصدار الxcode المستخدم : 8.0 لغة سويفت 3 في هذا الدرس سنتعلم طريقة إضافة خصائص إضافية في شريط الخصائص ( properties inspector ) في برنامج الxcode بطريقة سهلة و بسيطة حيث ستتمكن من إضافة مؤثرات بصرية إضافية لعناصر واجهة المستخدم كالحد (stroke or border ) و الزوايا الدائرية للأشكال.. مثلا سيكون بإمكانك عمل الظل و الحدود مع الزوايا الدائرية للview و ال label كما هو موضح في الصورة التالية. لاحظ وجود خيارات جديدة في الشريط الأيمن للتحكم بقيم الحد و الظل و الزوايا الدائرية إذن لنبدأ الدرس.. -في البداية.. قم بفتح الxcode و اختر create new xcode project ثم اختر single view application - قم بعمل كلاس جديد عن طريق File > New > File أو بالضغط على cmd+n ثم اختر cocoa touch class -قم بتسمية الclass بأي اسم يناسبك و تأكد من اختيار UIView عند Subclass of: كما هو موضح في الصورة ثم اضغط next الآن قم بإضافة IBDesignable قبل بداية التعريف بالكلاس في كلاس CustomizableView ليبدو بهذه الطريقة: import UIKit @IBDesignable class CustomizableView: UIView { } هذه الكلمة التي قمت بإضافتها تعطيك إمكانية ربط الكلاس مع الmain story board بحيث يقوم الاكس كود بمزامنة التغييرات التي تجريها على هذا الكلاس مع ال story board و إظهار النتائج مباشرة دون الحاجة إلى تشغيل الsimulator الاختبار النتيجة التي توصلت إليها الآن قم بإضافة الكود التالي إلى الكلاس.. @IBInspectable var cornerRadius:CGFloat = 0{ didSet{ self.layer.cornerRadius = cornerRadius } } -كما تلاحظ في البداية قمنا بإضافة @IBInspectable وهذه الكلمة تسبق المتغير الذي يحمل اسم cornerRadius و هذا أيضا يربط الكلاس مع الstory obard بطريقة أخرى بحيث يمكنك الآن التحكم بقيمة هذا المتغير من شريط الخصائص في الstory board مما سيؤدي إلى تغير قيمة هذا المتغير بناء على القيم المحددة في ال stroy board - بعد ذلك قمنا بإضافة المتغير cornerRadius و هو الذي سنستخدمه لتغيير الزوايا المنحنية في الview إلى زوايا دائرية و اخترنا نوع القيمة لتكون CGFloat و هو النوع المناسب لهذه الخاصية. - قمنا بإسناد القيمة 0 للمتغير كقيمة ابتدائية ثم بعد ذلك اضفنا الأقواس و هذه الأقواس تساعدك في إضافة تفاصيل أخرى للمتغير. - بداخل الأقواس قمنا بإضافة كلمة didSet متبوعة بأقواس و هذه الكلمة تمثل مجموعة من الأوامر يحددها المستخدم بحيث تطبق هذه الأوامر مباشرة بمجرد تغيير قيمة المتغير ، و هي يمكن تشبهها بالدالة function بحيث يقوم المبرمج بتحديد الأوامر التي ستوقوم هذه الدالة بها حالما يتم تغيير قيمة المتغير cornerRadius -اذن ما هي هذه الأوامر التي سيتم استدعاؤها ؟ self.layer.cornerRadius = cornerRadius كما هو موضح فإن self تمثل الاوبجكت من هذا الكلاس customizableView و بما أن هذا الكلاس يرث من الView فإنه سيرث خصائصها و التي منها layer ليقوم باستخدام الخاصية cornerRadius التي بداخل الlayer و التي تتحكم بمدى استدارة زوايا الشكل ثم يقوم بتغيير قيمتها لتساوي المتغير cornerRadius الذي نتحكم بقيمته من الstory board كما ذكرنا سابقا بفضل الخاصية @IBInspectable اذن مالذي سيحدث بالضبط؟ بمجرد إضافة عنصر view في الاكس كود و جعله يرث من الكلاس customizableView ستظهر لك الخواص المعروفة لهذا الview في شريط الخصائص كاللون و الحجم و المحاذاة ..الخ بالإضافة إلى خاصية مميزة جديدة لهذا الview فقط و هي الcornerRadius حيث ستظهر لك في شريط الخصائص بفضل كلمة @IBInspectable ثم سيكون بإمكانك تعديل قيمة ال cornerRadius و بمجرد تعديلها ستستدعى دالة didSet التي قمنا بإضافتها سابقا و بالتالي سيطبق أمر تغيير الcornerRadius الخاص بالشكل لتتغير قيمته من 0 إلى القيمة التي قمت بتحديدها له في شريط الخصائص و أخيرا سترى أن زوايا الview بالفعل أصبحت تتغير مباشرة و هذا بفضل كلمة @IBDesignable التي قمنا بإضافتها للكلاس customizableView لنطبق ذلك عمليا.. - قم بالذهاب إلى الstory board وإضافة view إليها و قم بتلوين هذا الview باللون الذي يناسبك. - الآن اذهب إلى الأيقونة التي بجانب أيقونة الخصائص و التي تسمى identity inspector و قم بتغيير الكلاس الخاص بالview إلى CustomizableView كما هو موضح في الصورة - انتظر قليلا ثم عد إلى الخصائص ستلاحظ و جود الخاصية الجديدة cornerRadius في أعلا شريط الخصائص كما هو واضح في الصورة.. - الآن قم بتغيير القيم لتلاحظ تغير زوايا الشكل بطريقة جميلة يمكنك إضافة المزيد من الخصائص التي بإمكانك التحكم بها بنفس الطريقة.. لإضافة خاصية الحد (border) : @IBInspectable var border:CGFloat = 0{ didSet{ self.layer.borderWidth = border } } لإضافة خاصية الظل ( لا أنصح بها لأنها قد تؤدي إلى بطء البرنامج بسبب معالجة الظل التي تستهلك الكثير من الأداء): @IBInspectable var shadow:CGFloat = 0{ didSet{ self.layer.shadowRadius = shadow } } @IBInspectable var opacity:Float = 0{ didSet{ self.layer.shadowOpacity = opacity/20 } } @IBInspectable var offset:CGFloat = 0{ didSet{ self.layer.shadowOffset.height = offset self.layer.shadowOffset.width = offset } } هذه الإضافات ليست خاصة للview فقط و إنما يمكنك إضافتها لأي عنصر رسومي في البرنامج فمثلا: بإمكانك فعل المثل للlabel كل ما عليك فعله : - قم بعمل كلاس جديد باسم customizableLabel على سبيل المثال - اجعله يرث من UILabel في خيار subclass of عند إنشاء الكلاس - قم بإضافة كلمة @IBDesignable عند بداية الكلاس -قم بنسخ نفس الكود الخاص بالcustomizableView و لصقه في كلاس customizableLabel - استمتع تم ترقية هذا الطرح المميز الى صفحة المقالات

عالم البرمجة

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