سؤال عن extension في بيئة Xcode بلغة Swift
لدي مشروع يتعامل مع خدمات AWS خاص بعملية تسجيل دخول المستخدمين، ألقيت نظرة عليه وصعب علي بفهم بعض النقاط نظراً لأني جديد على اللغة والبرمجة بها.
من هذه الأمور مسألة extension حيث وجدت في ملف AppDelegate.swift بعض الأوامر التي صعب علي فهمها منها هذه الإضافة
extension AppDelegate: AWSCognitoIdentityInteractiveAuthenticationDelegate {
func startPasswordAuthentication() -> AWSCognitoIdentityPasswordAuthentication {
if (self.navigationController == nil) {
self.navigationController = self.storyboard?.instantiateViewController(withIdentifier: "signinController") as? UINavigationController
}
if (self.signInViewController == nil) {
self.signInViewController = self.navigationController?.viewControllers[0] as? SignInViewController
}
DispatchQueue.main.async {
self.navigationController!.popToRootViewController(animated: true)
if (!self.navigationController!.isViewLoaded
|| self.navigationController!.view.window == nil) {
self.window?.rootViewController?.present(self.navigationController!,
animated: true,
completion: nil)
}
}
return self.signInViewController!
}
func startMultiFactorAuthentication() -> AWSCognitoIdentityMultiFactorAuthentication {
if (self.mfaViewController == nil) {
self.mfaViewController = MFAViewController()
self.mfaViewController?.modalPresentationStyle = .popover
}
DispatchQueue.main.async {
if (!self.mfaViewController!.isViewLoaded
|| self.mfaViewController!.view.window == nil) {
//display mfa as popover on current view controller
let viewController = self.window?.rootViewController!
viewController?.present(self.mfaViewController!,
animated: true,
completion: nil)
// configure popover vc
let presentationController = self.mfaViewController!.popoverPresentationController
presentationController?.permittedArrowDirections = UIPopoverArrowDirection.left
presentationController?.sourceView = viewController!.view
presentationController?.sourceRect = viewController!.view.bounds
}
}
return self.mfaViewController!
}
func startRememberDevice() -> AWSCognitoIdentityRememberDevice {
return self
}
}
السؤال هو : ما هي شروط تعريف extension ( وما هي قواعد كتابتها ) ؟
وكذلك وهو الأهم : متى يتم تنفيذ هذه الأوامر ؟ هل عندما يعمل البرنامج أو عند وقوع شرط معين ؟ وكيف أعرف هذا الشرط ؟
الإجابة الصحيحة
الـExtensions في Swift عبارة عن أداة تستخدمها لإضافة دوال ومزايا إضافية للكلاس أو حتى الأنواع الأخرى، مثل structure, enumeration, or protocol type
وبالعادة نستخدم الـExtensions لهدفين، الأول لجمع وظائف محددة لغرض معين في مكان محصور بعيدًا عن الكلاس، بمعنى إن كل الدوال اللي في مثالك خاصة بخدمات AWS وتحديدًا لـAWSCognitoIdentityInteractiveAuthenticationDelegate، فبدل ما نحط الدول الثلاثة داخل الكلاس AppDelegate مباشرة نحط Extension منفصل عن الكلاس لإضافة هذي الدوال للكلاس. وهذا الـExtensions ممكن يكون في نفس الملف AppDelegate.swift أو في ملف منفصل.
فلو جربت وأخذت الدوال الثلاثة وحطيتها داخل الكلاس AppDelegate مباشرة (مع إضافة AWSCognitoIdentityInteractiveAuthenticationDelegate لتعريف الكلاس) راح نوصل إلى نفس النتيجة.
الهدف الثاني لاستخدام الـExtensions هو إضافة دوال ومزايا لكلاسات وأنواع لا تمتلك مصدرها للتعديل عليها. فمثلأ في التعامل مع كلاس String في Swift أحتاج أضيف بعض الدوال لمهام دائمًا أستخدمها مع النصوص. ولكن طبعًا ما نقدر نعدل على الكلاس String. اللي نقدر نسويه إننا نضيف Extension للكلاس String بالإضافات اللي أحتاجها.
وكمثال، لنفترض إن تطبيقك يحتاج يحذف المسافات من النصوص ويستخدم الشي هذا بكثرة، ممكن تختصر على نفسك الوقت وتضيف ميزة حذف المسافات للكلاس String باستخدام الـExtensions
// ممكن وضعه في أي ملف
extension String {
//لحذف المسافات computed property إضافة
var withoutSpaces:String {
return self.replacingOccurrences(of: " ", with: "")
}
}
var text = "Some text with spaces"
print(text.withoutSpaces) // Sometextwithspaces
وللمزيد من الأمثلة اطلع على هذا الملف
وبالنسبة لقواعد كتابتها فكل اللي تحتاجه كلمة extension واسم الكلاس أو البروتوكول.. وبين القوسين {} تضيف ما تحتاجه.
ومن الاستخدامات المشهورة إذا حبيت كلاس معين يتوافق مع بروتوكول معين conform to protocol تضيف بعد اسم الكلاس : واسم البروتوكول. مثل الموجود في مثالك.
class MyViewController: UIViewController {
// class stuff here
}
// MARK: - UITableViewDataSource
extension MyViewController: UITableViewDataSource {
// table view data source methods
}
// MARK: - UIScrollViewDelegate
extension MyViewController: UIScrollViewDelegate {
// scroll view delegate methods
}
أيضًا الـExtensions ممكن تضيفها في نفس الملف مع الكلاس أو في ملف مستقل. وفي العادة للكلاسات الخاص بSwift أو بمكتبة من طرف ثالث، تسوي للـExtension ملف مستقبل ويكون اسمها عبارة عن اسم الكلاس + الغرض من الـExtension، مثلا في مثالنا فوق ممكن نحطه في ملف String+Cleaning.swift
وأخيرًا، فيه بعض الاختلافات بين إضافة المزايا للكلاس مباشرة، أو باستخدام الـExtensions. فمثلاً الـExtensions ما تقدر تحط فيها stored properties لكن تقبل computed properties.
وللمزيد يمكنك الاطلاع على دليل Swift Extensions
الإجابات (1)
الـExtensions في Swift عبارة عن أداة تستخدمها لإضافة دوال ومزايا إضافية للكلاس أو حتى الأنواع الأخرى، مثل structure, enumeration, or protocol type
وبالعادة نستخدم الـExtensions لهدفين، الأول لجمع وظائف محددة لغرض معين في مكان محصور بعيدًا عن الكلاس، بمعنى إن كل الدوال اللي في مثالك خاصة بخدمات AWS وتحديدًا لـAWSCognitoIdentityInteractiveAuthenticationDelegate، فبدل ما نحط الدول الثلاثة داخل الكلاس AppDelegate مباشرة نحط Extension منفصل عن الكلاس لإضافة هذي الدوال للكلاس. وهذا الـExtensions ممكن يكون في نفس الملف AppDelegate.swift أو في ملف منفصل.
فلو جربت وأخذت الدوال الثلاثة وحطيتها داخل الكلاس AppDelegate مباشرة (مع إضافة AWSCognitoIdentityInteractiveAuthenticationDelegate لتعريف الكلاس) راح نوصل إلى نفس النتيجة.
الهدف الثاني لاستخدام الـExtensions هو إضافة دوال ومزايا لكلاسات وأنواع لا تمتلك مصدرها للتعديل عليها. فمثلأ في التعامل مع كلاس String في Swift أحتاج أضيف بعض الدوال لمهام دائمًا أستخدمها مع النصوص. ولكن طبعًا ما نقدر نعدل على الكلاس String. اللي نقدر نسويه إننا نضيف Extension للكلاس String بالإضافات اللي أحتاجها.
وكمثال، لنفترض إن تطبيقك يحتاج يحذف المسافات من النصوص ويستخدم الشي هذا بكثرة، ممكن تختصر على نفسك الوقت وتضيف ميزة حذف المسافات للكلاس String باستخدام الـExtensions
// ممكن وضعه في أي ملف
extension String {
//لحذف المسافات computed property إضافة
var withoutSpaces:String {
return self.replacingOccurrences(of: " ", with: "")
}
}
var text = "Some text with spaces"
print(text.withoutSpaces) // Sometextwithspaces
وللمزيد من الأمثلة اطلع على هذا الملف
وبالنسبة لقواعد كتابتها فكل اللي تحتاجه كلمة extension واسم الكلاس أو البروتوكول.. وبين القوسين {} تضيف ما تحتاجه.
ومن الاستخدامات المشهورة إذا حبيت كلاس معين يتوافق مع بروتوكول معين conform to protocol تضيف بعد اسم الكلاس : واسم البروتوكول. مثل الموجود في مثالك.
class MyViewController: UIViewController {
// class stuff here
}
// MARK: - UITableViewDataSource
extension MyViewController: UITableViewDataSource {
// table view data source methods
}
// MARK: - UIScrollViewDelegate
extension MyViewController: UIScrollViewDelegate {
// scroll view delegate methods
}
أيضًا الـExtensions ممكن تضيفها في نفس الملف مع الكلاس أو في ملف مستقل. وفي العادة للكلاسات الخاص بSwift أو بمكتبة من طرف ثالث، تسوي للـExtension ملف مستقبل ويكون اسمها عبارة عن اسم الكلاس + الغرض من الـExtension، مثلا في مثالنا فوق ممكن نحطه في ملف String+Cleaning.swift
وأخيرًا، فيه بعض الاختلافات بين إضافة المزايا للكلاس مباشرة، أو باستخدام الـExtensions. فمثلاً الـExtensions ما تقدر تحط فيها stored properties لكن تقبل computed properties.
وللمزيد يمكنك الاطلاع على دليل Swift Extensions
عبد الله: اشكرك جزيل الشكر على الإجابة الواضحة ولو أن فيه مسألة أخيرة ربما منفصلة عن صلب الموضوع وهي استخدامه لهذا السطر DispatchQueue.main.async ماذا يعني ؟
Alhoqbani: هذي يبغالها اجابة منفصلة 😅. بعض العمليات اللي تاخذ وقت لازم تشتغل في الخلفية. مثل طلب عبر الشبكة او تحميل ملف. النظام فيه عنده Thread أساسي للعمليات الرئيسية. وفيه اكثر من Thread إضافية تعمل في الخلفية. وهذي تعتمد على توزيع العمليات على المعالج cpu الخاص بالايفون. والهدف ان العمليات الاساسية ما تتعطل بالعمليات اللي تشتغل في الخلفية. من اهم العمليات الاساسية واللي ما تشتغل الا على ال Main Thread التغيير على واجهة الاستخدام. وبالتالي في مثالك الدالة يتم استدعائها من Thread ثانوي في الخلفية. لكن وقت الحاجة الى التعديل على واجهة المستخدم (في هذي الحالة اظهار كنترولر) لا بد العلمية تصير على ال main thread وبالتالي يستخدم DispatchQueue.main.async لنقل العمليات الى ال main thread الموضوع شوي معقد وتقدر تبحث عن ios concurrency https://developer.apple.com/library/archive/documentation/General/Conceptual/ConcurrencyProgrammingGuide/Introduction/Introduction.html
عبد الله: اشكرك على التوضيح، المشكلة إن اللغة حاجز يعيق في فهم الكثير من الأمور، فما نستغني عنكم بعد الله في توضيحها لنا بالعربية :) ، يعني هذا الأمر يجعل ما بين أقواسه يتم على المسار الرئيسي للعمليات.
لايوجد لديك حساب في عالم البرمجة؟
تحب تنضم لعالم البرمجة؟ وتنشئ عالمك الخاص، تنشر المقالات، الدورات، تشارك المبرمجين وتساعد الآخرين، اشترك الآن بخطوات يسيرة !