
تحية! اسمي رينات ، أقوم بتطوير خدمة تحليل الاشتراك في iOS - Apphud.
كما تعلمون ، قدمت Apple في WWDC 2019 إطار عمل SwiftUI الجديد ، والذي تم تصميمه في المستقبل ليحل محل UIKit المألوف (أم لا؟). يتيح لك SwiftUI وصف واجهة التطبيق بأسلوب تعريفي ويقلل إلى حد كبير مقدار الشفرة.
لقد قدمت Apple بالفعل بعض البرامج التعليمية المثيرة للاهتمام للغة الإنجليزية مع العديد من الأمثلة. سأحاول التحدث عن الإطار الجديد في شكل أسئلة وإجابات. لذلك دعونا نذهب.
قبل أن تبدأ
للعمل مع SwiftUI ، تحتاج إلى تنزيل Xcode 11 Beta . يجب أن تكون أيضًا مطور Apple مسجلاً. الحصول على أحدث إصدار من نظام التشغيل MacOS Catalina أمر مرغوب فيه ، ولكن ليس ضروريًا. بدونها ، لن يكون Canvas متاحًا.
لذلك ، في Xcode 11 Beta ، قم بإنشاء مشروع جديد وتأكد من تحديد "Use SwiftUI".
سؤال وجواب
أين ذهبت واجهة البناء؟
لم يعد SwiftUI بحاجة إلى Interface Builder - فقد تم استبداله بـ Canvas ، وهو محرر واجهة تفاعلية يرتبط ارتباطًا وثيقًا بالكود. عند كتابة التعليمات البرمجية ، يتم تلقائيًا إنشاء جزءها المرئي في اللوحة القماشية والعكس صحيح. مريحة للغاية ، والأكثر أهمية آمنة. الآن لن @IBOutlet
التطبيق الخاص بك بسبب حقيقة أنك نسيت تحديث @IBOutlet
مع المتغير. في هذه المقالة لن نلمس قماش ، سننظر فقط في الكود.
هل تغير تشغيل التطبيق؟
نعم ، الآن الكائن الأولي في واجهة التطبيق ليس UIWindow
، ولكن فئة UIScene
الجديدة (أو UIWindowScene
المتحدرة UIWindowScene
). وتضاف نافذة إلى مكان الحادث. لا تؤثر هذه التغييرات على SwiftUI فحسب ، بل تؤثر على نظام التشغيل iOS 13 ككل.
عند إنشاء مشروع ، سترى ملفات AppDelegate و SceneDelegate و ContentView . SceneDelegate - مفوض من فئة UIWindowScene
، وتستخدم للسيطرة على المشاهد في التطبيق. تذكر بقوة AppDelegate .

تم تحديد فئة SceneDelegate في Info.plist
في طريقة المفوض ، scene: willConnectTo: options:
ينشئ نافذة وجذر UIHostingController
يحتوي على ContentView
. ContentView
هي الصفحة "الرئيسية" لدينا. سيتم إجراء كل التطوير في هذه الفئة.
كيف تختلف طريقة العرض عن UIView؟
ContentView.swift
فتح ContentView.swift
، سترى إعلان حاوية ContentView. كما فهمت بالفعل ، لا توجد طرق viewDidAppear
أو viewDidLoad
مألوفة viewDidLoad
viewDidAppear
. أساس الشاشات هنا ليس UIViewController
، ولكن طريقة العرض . أول ما يجب ContentView
هو أن ContentView
عبارة عن struct
تقبل بروتوكول View
. نعم ، أصبح View
الآن بروتوكولًا وبسيطًا جدًا. الطريقة الوحيدة التي تحتاج إلى تنفيذها في ContentView
هي وصف النص المتغير. يجب أن تقبل جميع المقابلات الفرعية وطرق العرض المخصصة بروتوكول View
، أي يجب أن يكون هناك متغير نصي .
ما هو الجسم؟
Body
مباشرة حاوية لدينا حيث يتم إضافة جميع الفرعية الأخرى. يشبه هذا إلى حد ما النص الأساسي في صفحة html ، حيث تكون صفحة html هي ContentView
. يجب أن يكون Body
دائمًا سليل واحد تمامًا ، وأي فئة تقبل بروتوكول View
.
struct ContentView: View { var body: some View { Text("Hello, world!") } }
أنواع عودة مبهمة أو ما هو بعض؟
بناء some TypeName
هو ابتكار Swift 5.1 يسمى نوع الإرجاع المعتم . يتم استخدامه للحالات التي لا يكون فيها من المهم بالنسبة لنا أي شيء نعود إليه ، الشيء الرئيسي هو أنه يدعم النوع المحدد ، في هذه الحالة ، بروتوكول View
.
إذا كتبنا ببساطة var body: View
، فهذا يعني أننا يجب أن نعيد View
. لا يعمل Any
فئة أيضًا ، نظرًا لأننا سنضطر إلى إجراء عملية تحويل نوع ( باستخدام as!
Operator ). لذلك ، توصلوا إلى كلمة خاصة some
أمام اسم البروتوكول للإشارة إلى نوع الإرجاع المعتم . بدلاً من View
يمكننا إرجاع Text
أو Image
أو VStack
- أي شيء ، حيث أنهم جميعًا يدعمون بروتوكول View
. ولكن يجب أن يكون هناك عنصر واحد بالضبط: عند محاولة إرجاع أكثر من View
واحدة View
سوف يلقي المترجم خطأ.

خطأ في التحويل البرمجي عند محاولة إرجاع أكثر من عنصر إلى النص
ما هو بناء الجملة داخل الأقواس وأين هو addSubview؟
قدم Swift 5.1 القدرة على تجميع الكائنات في مجموعة واحدة بأسلوب تعريفي. يشبه هذا صفيف داخل كتلة إغلاق ، ولكن يتم تعداد العناصر من سطر جديد بدون فواصل والعودة . هذه الآلية كانت تسمى منشئ الوظيفة .
يستخدم على نطاق واسع في SwiftUI. بناءً على Function Builder ، جعلوا ViewBuilder
- مصمم واجهة ViewBuilder
. باستخدام ViewBuilder
لم نعد بحاجة إلى كتابة addSubview
لكل عنصر - ما addSubview
سوى إدراج كل View
من سطر جديد داخل كتلة الإغلاق . سوف SwiftUI إضافة وتجميع العناصر في حاوية الأم أكثر تعقيدا.
@available(iOS 13.0, OSX 10.15, tvOS 13.0, watchOS 6.0, *) @_functionBuilder public struct ViewBuilder {
إعلان ViewBuilder في إطار SwiftUI
كيفية إضافة UILabel ، UIImageView وغيرها من العناصر؟
يتم إنشاء العناصر بكل بساطة: يحتاج كل View
إلى كتابته من سطر جديد وتغيير المظهر باستخدام وظائف التعديل ( عرض المعدلات ). الفرق بين المعدلات والوظائف المألوفة لنا هو أنها تقوم دائمًا بإرجاع كائن حاوية بدلاً من void
. لذلك ، يمكننا إنشاء سلاسل كاملة من المعدلات من خلال هذه النقطة.
var body: some View { VStack{ Text("World Time").font(.system(size: 30)) Text("Yet another subtitle").font(.system(size: 20)) } }
ومع ذلك ، ليس كل الضوابط وطريقة العرض لها نظائرها في SwiftUI. فيما يلي قائمة جزئية للفصول من UIKit ونظائرها:
UITableView
-> List
UICollectionView
لا يوجد لديه التناظرية
UILabel
-> Text
UITextField
-> TextField
UIImageView
-> Image
UINavigationController
-> NavigationView
UIButton
-> Button
UIStackView
-> HStack
/ VStack
UISwitch
-> Toggle
UISlider
-> Slider
UITextView
لا يوجد لديه التناظرية
UIAlertController
-> Alert
/ ActionSheet
UISegmentedControl
-> SegmentedControl
UIStepper
-> Stepper
UIDatePicker
-> DatePicker
كيف يتم التنقل بين الشاشات؟
يتحكم جهاز التحكم في التنقل في دور NavigationView
الخاص. فقط قم بتغطية الشفرة في NavigationView{}
. ويمكن إضافة إجراء الانتقال نفسه إلى زر NavigationLink
خاص ، والذي يدفع شاشة DetailView
.
var body: some View { NavigationView { Text("World Time").font(.system(size: 30)) NavigationLink(destination: DetailView() { Text("Go Detail") } } }
كيفية تقديم وجهات نظر جديدة مشروط؟ يتم ذلك ، على سبيل المثال ، باستخدام بنية الورقة :
Button(action: { print("Button Pushed") self.show_modal = true }) { Text("Present Modal") }.sheet(isPresented: self.$show_modal) { ModalView() }
كما ذكر أعلاه ، يمكن أن يُرجع النص ليس فقط مثيلًا لـ View
، ولكن أيضًا أي فئة أخرى تقبل هذا البروتوكول. هذا يعطينا الفرصة DetailView
لا DetailView
، ولكن حتى Text
أو Image
!
كيفية ترتيب العناصر على الشاشة؟
يتم ترتيب العناصر بشكل مستقل عن بعضها البعض ويمكن أن تقع عموديًا داخل VStack
، أفقياً HStack
وواحد فوق ZStack
الآخر. ScrollView
و ListView
متاحة لنا أيضا. يمكنك التناوب ومشاركة هذه الحاويات للحصول على أي شبكة من العناصر.
من خلال الجمع بين الحاويات مع بعضها البعض ، يمكنك الحصول على شجرة كبيرة إلى حد ما مع عدد كبير من المرفقات. ومع ذلك ، تم تحسين SwiftUI خصيصًا لهذا الغرض ، لذا فإن تداخل الحاوية العميقة لا يؤثر على الأداء. جاء ذلك في الفيديو باستخدام wwdc ( بدءًا من الساعة 15:32 ).
var body: some View { NavigationView { VStack { NavigationLink(destination: LargeView(timeString: subtitle)) { Text("See Fullscreen") } Text("World Time").font(.system(size: 30)) } } }
كيفية إظهار شريط التنقل؟
إن إعلان NavigationView
لا يكفي ؛ يجب عليك تحديد عنوان التنقل ونمط شريط التنقل .
NavigationView { VStack{}.navigationBarTitle(Text("World Time"), displayMode: .inline) }
لاحظ أن وظيفة navigationBarTitle
لا تُدعى على NavigationView
، ولكن في View
الداخلية. DisplayMode هي معلمة تشير إلى نمط شريط التنقل : كبير أو قياسي.
هل هناك تناظرية لطريقة viewDidLoad؟
إذا كنت تريد تنفيذ التعليمات البرمجية عند تهيئة View
، يمكنك القيام بذلك عن طريق إضافة وظيفة onAppear {}. يمكن إضافة OnAppear إلى أي View
، على سبيل المثال ، إلى VStack
. في هذا المثال ، عندما تظهر الحاوية على الشاشة ، يتم تقديم طلب http إلى الخادم.
struct ContentView : View { @State var statusString : String = "World Time" var body: some View { NavigationView { VStack { NavigationLink(destination:DetailView()) { Text("Go Detail") } Text(statusString).font(.system(size: 30)) }.onAppear { self.loadTime() } } } func loadTime(){ NetworkService().getTime { (time) in if let aTime = time { self.statusString = "\(aTime.date())" } } } }
نحن ندعو وظيفة loadTime
، التي تطلب الوقت الحالي من الخادم وتعيد نموذج WorldTime
. لن نذهب إلى دورات في فئة NetworkService
، يمكنك إلقاء نظرة على جميع التعليمات البرمجية ، بعد تنزيل أكواد المصدر. رابط في نهاية المقال.
تم تقديم متغير var statusString
من أجل تخصيص الوقت الحالي له لاحقًا. المتغير له سمة خاصة @State
. ماذا يعني؟
@State
الممتلكات أو ما هو @State
؟
قدم Swift 5.1 ما يسمى بأغلفة الخصائص (أو مفوضي الممتلكات ). في SwiftUI تُستخدم مغلفات الخصائص لتحديث أو ربط أحد معلمات العرض مع متغيرنا الخاص ، على سبيل المثال ، قيمة مفتاح التبديل.
السمة @State
هي سمة خاصة يتم وضعها قبل إعلان متغير. يتيح لنا ذلك تعقب تغييرات الخاصية تلقائيًا دون رمز إضافي. في المثال أعلاه ، سيتم تغيير النص "التوقيت العالمي" إلى التاريخ الحالي بمجرد تحديث قيمة statusString.
لربط القيم ( ربط الخصائص ) ، يمكننا تحديد حرف خاص $
قبل اسم المتغير في الكود نفسه:
struct DetailsView: View { @State var changeToggle: Bool var body: some View { Toggle(isOn: $changeToggle) { Text("Change Toggle") } } }
عن طريق تغيير موضع التبديل ، سوف تتغير قيمة المتغير أيضًا.
مغلفة الممتلكات هي عنصر مهم للغاية في SwiftUI ، لقد ذكرتها للتو. للتعرف أكثر تفصيلاً على أغلفة الممتلكات ، شاهد الفيديو من wwdc هنا (من الدقيقة 37) ، وهنا (من الدقيقة 12) وهنا (من الدقيقة 19).
كيفية إضافة عرض لوقت التشغيل؟
تجدر الإشارة على الفور إلى أنه لا يمكنك إضافة عرض في أي وقت بالمعنى الحرفي للكلمة. SwiftUI هو إطار إعلاني يعرض الرؤية بالكامل. ومع ذلك ، يمكنك تعيين شروط مختلفة داخل الجسم وتحديث حالة العرض عند تغييرها. في هذا المثال ، نستخدم أبسط مجموعة من @State – if
المتغير isTimeLoaded
.
struct ContentView : View { @State var statusString : String = "World Time" @State var isTimeLoaded : Bool = false var body: some View { NavigationView { VStack { if isTimeLoaded { addNavigationLink() } Text(statusString).font(.system(size: 30)).lineLimit(nil) }.navigationBarTitle(Text("World Time"), displayMode: .inline) }.onAppear { self.loadTime() } } func addNavigationLink() -> some View { NavigationLink(destination: Text("124!!!")) { Text("Go Detail") } } func loadTime(){ NetworkService().getTime { (time) in if let aTime = time { self.statusString = "\(aTime.date().description(with: Locale.current))" self.isTimeLoaded = true } } } } struct DetailView : View { var timeString : String var body : some View { Text(timeString).font(.system(size: 40)).lineLimit(nil) } }
بالمناسبة ، هل لاحظت أن وظيفة addNavigationLink()
تحتوي على كلمة return
؟ هذا يعد ابتكارًا آخر لـ Swift 5.1 - بالنسبة للوظائف ذات التعبير الواحد ، أصبح الآن خيارًا لكتابة return
. ولكن يمكنك الكتابة.
استنتاج
هذا مجرد جزء من SwiftUI Q & A. لقد درست القضايا العامة ، وآمل أن يساعد هذا المقال المبتدئين في فهم النقاط الرئيسية في هذا الإطار. SwiftUI لا يزال خامًا ، لكنه بلا شك سيتم تحسينه.
السؤال المنطقي هو: هل يستحق التعلم UIKit؟ بالطبع نعم . UIKit هي أساس البرمجة على نظام iOS وسوف تتطور أكثر. علاوة على ذلك ، فإن العديد من مكونات SwiftUI عبارة عن غلاف على UIKit. حسنًا ، حتى الآن لا توجد مكتبات ، وأُطُر ، وأيقونات لـ SwiftUI. كل شيء يجب أن تكون مكتوبة من قبل نفسك. لذا ، من الأفضل أن تدرس طريقتي التطوير - لذلك ستكون مطورًا أكثر قيمة.
يمكنك تنزيل مصادر المشروع هنا .
شكرا لك على قراءة المقال حتى النهاية. أتمنى أن تجدها مفيدة.
ماذا تقرأ؟