«keyWindow» أصبح مهملاً. ماذا تفعل؟
\n\nإذا كنت قد كتبت من قبل:
\n\nguard let window = UIApplication.shared.keyWindow else { return }\n\n…فمن المؤكد أنك رأيت التحذير الأصفر من Xcode: «'keyWindow' was deprecated in iOS 13.0». هذا أحد أكثر الأسئلة شيوعاً على Stack Overflow (أكثر من 100,000 مشاهدة)، وليس من دون سبب — لقد غيرت Apple قواعد اللعبة حقاً.
\n\nفي هذه المقالة، سنشرح لماذا حدث ذلك، ونقارن 4 طرق للحصول على نافذة التطبيق دون استخدام API المهمل. ستعرف أي طريقة مناسبة لـ UIKit و SwiftUI و SceneDelegate ومتى يجب استخدام كل منها. هيا بنا!
\n\nلماذا تخلت Apple عن keyWindow؟
\n\nقبل iOS 13، كان للتطبيق نافذة رئيسية واحدة — keyWindow. كان الأمر بسيطاً: نأخذها ونعمل بها. ولكن مع ظهور iPadOS وتعدد المهام (Split View, Slide Over)، يمكن أن يكون للتطبيق عدة نوافذ في نفس الوقت. كل نافذة تُدار بواسطة UIWindowScene الخاص بها. أصبح مفهوم «النافذة الرئيسية» غير واضح.
توصي Apple الآن بالحصول على النافذة من خلال المشهد (UIWindowScene) الذي ينتمي إليه المتحكم أو العرض الخاص بك.
\n\nمقارنة الطرق: من البسيط إلى الصحيح
\n\nسنستعرض 4 طرق، من «إسكات التحذير بسرعة» إلى «القيام بذلك بطريقة Apple». اختر الطريقة التي تناسب بنيتك البرمجية.
\n\n1. الإصلاح السريع: UIApplication.shared.windows.first(where:)
\n\nالإجابة الأكثر شيوعاً على Stack Overflow — استخدام الخاصية windows بدلاً من keyWindow:
if let window = UIApplication.shared.windows.first(where: { $0.isKeyWindow }) {\n // نستخدم window\n}\n\nالإيجابيات:
\n- \n
- أقل تغيير في الكود \n
- يعمل على iOS 13+ \n
السلبيات:
\n- \n
- لا يزال غير آمن مع وجود نوافذ متعددة \n
- قد يعيد nil إذا لم يتم إنشاء النافذة بعد \n
- لا تزال Apple تضع علامة «مهمل» عليه في بعض السياقات \n
متى تستخدم: فقط للنموذج الأولي السريع أو إذا كان لديك نافذة واحدة بالتأكيد (مثل تطبيق iPhone بدون تعدد النوافذ).
\n\n2. عبر SceneDelegate: الطريق الصحيح لـ UIKit
\n\nبدءاً من iOS 13، قدمت Apple UISceneDelegate. في الطريقة scene(_:willConnectTo:options:) تحصل على UIWindowScene ويمكنك حفظ مرجع للنافذة.
الخطوة 1: في SceneDelegate.swift أعلن الخاصية window:
class SceneDelegate: UIResponder, UIWindowSceneDelegate {\n\n var window: UIWindow?\n\n func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {\n guard let windowScene = (scene as? UIWindowScene) else { return }\n window = UIWindow(windowScene: windowScene)\n window?.rootViewController = ViewController()\n window?.makeKeyAndVisible()\n }\n}\n\nالخطوة 2: احصل على النافذة من خلال المشهد:
\n\nif let windowScene = view.window?.windowScene,\n let window = windowScene.windows.first {\n // نستخدم window\n}\n\nأو، إذا كنت بحاجة إلى النافذة الرئيسية في أي مكان في التطبيق، قم بتخزين مرجع إلى SceneDelegate و window الخاص به.
الإيجابيات:
\n- \n
- يتوافق تماماً مع توصيات Apple \n
- يعمل بشكل صحيح مع النوافذ المتعددة \n
- آمن لتعدد المهام على iPad \n
السلبيات:
\n- \n
- يتطلب إعداد SceneDelegate (إذا لم تنتقل إليه بعد) \n
- كود أكثر قليلاً \n
3. عبر UIWindowScene.activeWindow (iOS 15+)
\n\nبدءاً من iOS 15، لدى UIWindowScene
المدونات
توصيات الكتب
اقرأ أيضًا