iOS / Swift / أنظمة ميسرة وأدلة الأهداف / الدرس 15
واجهات UIKit الممثلة والمنسقون
اربط الحالة الوصفية بـ UIKit دون إعادة إنشاء التحكم أو تحويل تحديثات المفوض إلى حلقات.
في هذه الصفحة
أهداف الدرس
- اربط قدرة ناقصة محددة
- أنشئ مرة وحدّث من الحالة الحالية
- استخدم منسقا لردود النداء الأمرية
اربط قدرة ناقصة محددة
تتيح UIViewRepresentable استضافة عرض UIKit داخل SwiftUI. استخدمها لقدرة محددة مع مهايئ ضيق وملكية واضحة. قد يعاد إنشاء قيمة الممثل عند تقييم الشجرة، بينما للـ UIView عمر مدار مستقل. لا تستبدل التحكم الأصلي مع كل تحديث لمجرد تجدد البنية. افصل الإنشاء وتحديث الإعداد وردود المفوض والتنظيف. يسهل اختبار مهايئ رقيق أكثر من غلاف يجلب البيانات ويتنقل ويتحقق من المجال أيضا.
أنشئ مرة وحدّث من الحالة الحالية
ينفذ المقتطف الأول ربط UILabel للقراءة. تنشئ makeUIView العرض وتضبط الإعداد المستقر، وتنسخ updateUIView المدخل الحالي إليه عند الحاجة فقط. يمنع الفصل اعتبار كل تحديث وصفي عمرا أصليا جديدا. النص مصطنع وتتطلب الوحدة SwiftUI وUIKit ببيئة iOS متوافقة. ويراجع ربط الإنتاج Dynamic Type والإتاحة والحجم والسمات. لا يثبت عرض نص قصير واجهة متكيفة كاملة.
import SwiftUI
import UIKit
@MainActor
struct NativeLabel: UIViewRepresentable {
let text: String
func makeUIView(context: Context) -> UILabel {
let label = UILabel()
label.numberOfLines = 0
return label
}
func updateUIView(_ label: UILabel, context: Context) {
if label.text != text { label.text = text }
}
}
The existing UILabel reflects the current text input without being recreated for each update.
حُذفت بيئة التطبيق وتكامل الحجم. لم يُنشأ عرض UIKit أثناء التأليف.
استخدم منسقا لردود النداء الأمرية
ينفذ المنسق بروتوكولات مفوض UIKit ويوجه الأحداث إلى رابط أو أمر SwiftUI. لا ينبغي أن يحتفظ بشاشة منتهية عبر مراقب عام طويل العمر. ينسق المقتطف الثاني مسودة UITextView. تجدد updateUIView قيمة الممثل لدى المنسق ليستخدم الرد الرابط الحالي وتتجنب استبدال النص غير اللازم. يشمل التحرير التحديد والنص قيد التركيب لوسائل الإدخال؛ ويحتاج محرر حقيقي إلى مزامنة أدق من الإسناد مع كل تحديث. أظهر حدود المثال.
@MainActor
struct NativeDraft: UIViewRepresentable {
@Binding var text: String
func makeCoordinator() -> Coordinator { Coordinator(self) }
func makeUIView(context: Context) -> UITextView {
let view = UITextView()
view.delegate = context.coordinator
return view
}
func updateUIView(_ view: UITextView, context: Context) {
context.coordinator.parent = self
if view.text != text { view.text = text }
}
static func dismantleUIView(_ view: UITextView, coordinator: Coordinator) {
view.delegate = nil
}
@MainActor final class Coordinator: NSObject, UITextViewDelegate {
var parent: NativeDraft
init(_ parent: NativeDraft) { self.parent = parent }
func textViewDidChange(_ textView: UITextView) {
if parent.text != textView.text { parent.text = textView.text }
}
}
}
Native edits update the binding; external text changes update the existing UITextView.
يتطلب الاستيرادات السابقة. هو ربط مسودة محدود لا محرر كامل أو عقد إدخال مختبر.
امنع حلقات التغذية دون إخفاء التعديلات الصحيحة
قد يحدث رد أصلي حالة SwiftUI فيجدول تحديثا آخر. وإذا كتب كل تحديث الحالة الأصلية وأثار ردا جديدا، تنشأ حلقة أو يتصفّر التحديد. تساعد المساواة للنص البسيط، وقد يحتاج التحكم المعقد إلى تمييز البرنامج من المستخدم صراحة. لا تمنع كل الردود عموما كي لا تفقد تعديلات. أبق تحقق المجال عند الأمر بدلا من تغيير النص عشوائيا أثناء تركيبه. اختبر التحرير السريع والتصفير الخارجي والإلغاء بحسب السياسة.
نظّف الموارد التي يملكها الربط فعلا
تتيح dismantleUIView فك التسجيلات المملوكة وفصل الردود عند إزالة العرض. لا يحرر نموذج يملكه الأب لمجرد اختفاء ممثل مؤقت. وتحتاج المراقبات والمؤقتات والمهام التي يبدأها المهايئ إلى مالك إيقاف. احترم متطلبات UIKit للخيط أو الممثل الرئيسي بحسب الأدوات. لا تنقل العرض إلى مهمة منفصلة لإسكات تحذير. انقل بيانات ثابتة بين حدود التزامن وحدّث الواجهة بعزلها المدعوم.
تحقّق من الاتجاهين والإزالة
اختبر في SDK مصرح به العرض الأول وتحريرا يخرج وتغييرا خارجيا يدخل وتحديثات بلا تحرير والإزالة مع إمكان الردود. أضف العربية وتركيب النص وحفظ التحديد وDynamic Type والإتاحة للمحرر الحقيقي. لا يثبت اختبار رابط نقي توقيت مفوض UIKit أو لوحة المفاتيح. لا تنفذ الدورة الممثلين أو تنشئ عروضا أصلية أو تدعي المحاكي. تبقى الكتل مقتطفات بيئة صريحة كي لا تختلط توقعاتها بدليل جهاز.
الأخطاء الشائعة وإصلاحها
يعاد إنشاء التحكم الأصلي مع كل تحديث
- لماذا يحدث؟
- اختلط الإنشاء بمزامنة الحالة.
- كيف تصلحه؟
- أنشئ في makeUIView وحدّث الكائن المدار في updateUIView.
- كيف تتجنب تكراره؟
- اختبر تحديثات أب متكررة.
تصفّر الكتابة التحديد أو تكرر الردود
- لماذا يحدث؟
- أُسند النص برمجيا دون شرط.
- كيف تصلحه؟
- زامن اللازم وراع تركيب النص والتحديد.
- كيف تتجنب تكراره؟
- اختبر التحرير الأصلي مع التحديث الخارجي.
يتلقى الربط المحذوف عمل المراقب
- لماذا يحدث؟
- لم تُفصل التسجيلات المملوكة للمهايئ.
- كيف تصلحه؟
- نظّف المراقب أو المهمة أو المفوض عند حد عمره.
- كيف تتجنب تكراره؟
- أزل العرض أثناء عمل معلق.
اختبر فهمك
1. لماذا يستبدل المنسق parent بأحدث قيمة ممثل؟
اعرض الحل المشروح
قد يعاد إنشاء البنية برابط أو إعداد مختلف بينما يستمر المنسق. يحفظ تحديث القيمة توجيه الرد بحسب المدخلات الحالية. ولا يبرر الاحتفاظ بشاشة قديمة أو جعله خدمة عامة.
2. لماذا لا يكفي المثال لمحرر متعدد اللغات كامل؟
اعرض الحل المشروح
يوضح مزامنة النص في الاتجاهين، لكن النص قيد التركيب والتحديد والتراجع والتخطيط وأوامر اللوحة والإتاحة تحتاج إلى تصميم واختبار هدف. اجعلها متطلبات صريحة لا افتراضات من رد مفوض بسيط.
أهم ما تعلمته
- اربط قدرة ناقصة محددة
- تحقّق من الاتجاهين والإزالة