.onAppear: مبدأ العمل، دورة الحياة، وأمثلة في SwiftUI

المؤلف: IT Sectr نُشر: 2026-06-26 وقت القراءة: 10 دق

.onAppear هو مُعدِّل SwiftUI ينفذ إغلاقاً عند إضافة View إلى تسلسل الواجهة. يحدث الاستدعاء مرة واحدة لكل ظهور للمثيل على الشاشة ويعمل كنقطة رئيسية لتحميل البيانات، تشغيل الرسوم المتحركة، وإرسال أحداث التحليلات. وفقاً Apple Developer Documentation (2026)، يضمن onAppear التنفيذ قبل أول عرض، لكنه لا يضمن الاستدعاء عند كل عرض متكرر إذا بقيت View في الذاكرة. اقرأ المزيد عن SwiftUI في مقال SwiftUI.

أهم النقاط

  • .onAppear هو مُعدِّل SwiftUI لتنفيذ الكود عند ظهور View على الشاشة.
  • استدعاء واحد — يُستدعى onAppear مرة واحدة خلال دورة حياة View إذا بقيت في الذاكرة.
  • تحميل البيانات — السيناريو الرئيسي لـ onAppear: جلب من API، قراءة من Core Data أو UserDefaults.
  • الرسوم المتحركة — يشغل onAppear رسوماً متحركة للدخول: opacity، scale، offset مع تأخير.
  • التحليلات — تُرسل أحداث screen view، impression، page open عبر onAppear.

ما هو .onAppear؟

.onAppear هو مُعدِّل View في SwiftUI يأخذ إغلاقاً Void وينفذه عندما تصبح View مرئية على الشاشة. هذا المُعدِّل جزء من نظام دورة حياة مكونات SwiftUI إلى جانب .onDisappear و .task. قدمت Apple onAppear مع إصدار SwiftUI في iOS 13 و watchOS 6 كبديل لـ viewDidLoad من UIKit.

من الناحية التركيبية، يُعدِّل .onAppear أي View ويعيد نفس View مع إجراء مرفق. يستدعي مُركِّب SwiftUI الإغلاق المُمرَّر مرة واحدة عندما تُضاف view إلى التسلسل وتجتاز مرحلة العرض. إذا حُذفت View ثم أُضيفت مرة أخرى (مثلاً عند التمرير في قائمة)، يُستدعى onAppear مرة أخرى — غالباً ما يصبح هذا السلوك مصدر أخطاء غير متوقعة.

بناء onAppear

بناء المُعدِّل الأساسي بسيط: onAppear بدون معاملات. لا يوفر SwiftUI طريقة لتمرير أولوية أو رسم متحرك — يُنفَّذ الإغلاق بشكل متزامن في الخيط الرئيسي فوراً بعد العرض.

swift
struct ContentView: View {
    var body: some View {
        Text("Hello, SwiftUI!")
            .onAppear {
                print("View appeared on screen")
            }
    }
}

القيود: لا يدعم onAppear async/await مباشرة. للعمليات غير المتزامنة داخل الإغلاق تحتاج إلى Task {} أو دالة async/await منفصلة تُستدعى عبر Task.detached. هذا يجعل onAppear أقل ملاءمة لطلبات الشبكة مقارنة بالمُعدِّل .task.

كيف يعمل .onAppear في دورة حياة View

.onAppear يُدمج في خط أنابيب العرض لـ SwiftUI في مرحلة layout+render. عندما يحسب Swiftui جسم View ويكتشف تغييراً في التسلسل، يُشغِّل استدعاءات onAppear لجميع views المضافة حديثاً. ترتيب الاستدعاء يتبع التداخل: onAppear للأب أولاً، ثم العناصر الابن.

ميزة مهمة لـ SwiftUI هي أن onAppear غير مرتبط بالظهور الفعلي على الشاشة. يُستدعى المُعدِّل عندما تُضاف View إلى التسلسل بغض النظر عما إذا كانت مرئية للمستخدم (مثلاً خارج الشاشة في ScrollView). هذا يميز SwiftUI عن UIKit، حيث viewWillAppear يُشغَّل فقط عند الظهور الفعلي.

ترتيب استدعاء onAppear

ترتيب الاستدعاء يتبع قاعدة الأب أولاً: VStack أو NavigationView يستقبل onAppear أولاً، ثم كل عنصر ابن بالترتيب. هذا مهم لتهيئة الموارد المشتركة: إذا كانت العناصر الابن تعتمد على بيانات يُحمّلها الأب، فيجب أن تتحقق من التوفّر عبر Optional.

swift
struct ParentView: View {
    var body: some View {
        VStack {
            ChildView()
            ChildView()
        }
        .onAppear {
            print("Parent onAppear — first")
        }
    }
}

struct ChildView: View {
    var body: some View {
        Text("Child")
            .onAppear {
                print("Child onAppear")
            }
    }
}

مخرجات الكونسول ستكون: Parent onAppear — أولاً، ثم Child onAppear مرتين بالترتيب. هذا السلوك مضمون من Apple ومستقر في جميع إصدارات SwiftUI (iOS 13–18).

متى يُستدعى .onAppear

.onAppear له عدة سيناريوهات استدعاء تعتمد على الحاوية والتنقل. في NavigationStack، يُشغَّل onAppear عند كل push لوحدة تحكم جديدة وعند pop — لوحدة التحكم الجذر. في TabView، تبديل التبويبات يستدعي onAppear للتبويب المعروض و onDisappear للمخفي.

في List و ScrollView، يُستدعى onAppear للخلايا التي دخلت المنطقة المرئية أو موجودة في مخزن العرض المسبق. iOS 18 أدخل آلية prefetch يمكنها استدعاء onAppear للخلايا قبل 2–3 شاشات من التمرير — هذا يُسرّع الإدراك لكنه قد يُسبب طلبات شبكة غير ضرورية.

سلوك الاستدعاء في NavigationStack

NavigationStack (iOS 16+) يدير كومة الشاشات بشكل مختلف عن NavigationView. عند push شاشة جديدة، يُشغَّل onAppear فقط على الشاشة الجديدة، بينما لا تستقبل الحالية onDisappear حتى الإزالة الفعلية. عند pop، تحدث العملية العكسية: onDisappear على الشاشة المُغادَرة، onAppear على العائدة.

السيناريوonAppearonDisappear
Pushالشاشة الجديدةلا (الشاشة تبقى في الكومة)
Popالشاشة العائدةالشاشة المُغادَرة
تبديل تبويبالتبويب الجديدالتبويب القديم
إغلاق sheetالشاشة الأمالشاشة المفتوحة

أمثلة استخدام .onAppear

التطبيقات العملية لـ onAppear تغطي ثلاث فئات رئيسية: تحميل البيانات، تشغيل الرسوم المتحركة، وإرسال التحليلات. كل سيناريو يتطلب مراعاة ميزات دورة حياة SwiftUI لتجنب الاستدعاءات المكررة وتسريبات الذاكرة.

تحميل البيانات من API

تحميل البيانات هو السيناريو الأكثر شيوعاً لـ onAppear. داخل الإغلاق يُنشأ Task للاستدعاء async، ويُخزَّن النتيجة في @State أو @StateObject. من المهم التحقق مما إذا كانت البيانات قد حُمِّلت بالفعل باستخدام flag isLoading أو فحص nil.

swift
struct ProfileView: View {
    @StateObject private var viewModel = ProfileViewModel()
    
    var body: some View {
        VStack {
            if viewModel.isLoading {
                ProgressView()
            } else {
                Text(viewModel.userName)
            }
        }
        .onAppear {
            guard viewModel.userName == nil else { return }
            Task {
                await viewModel.loadProfile()
            }
        }
    }
}

الحماية من إعادة الجلب ممارسة مهمة. إذا أعاد SwiftUI إنشاء View (مثلاً عند دوران الشاشة)، سيُستدعى onAppear مرة أخرى بدون حماية. البديل هو المُعدِّل .task الذي يُلغي تلقائياً الطلب السابق.

تشغيل رسم متحرك للدخول

الرسم المتحرك للدخول يستخدم onAppear لتغيير متغيرات الحالة التي تُشغِّل الرسم المتحرك عبر withAnimation أو مُعدِّل animation. النمط النموذجي: حالة أولية (opacity 0, offset 100)، انتقال إلى حالة نهائية (opacity 1, offset 0) عند الظهور.

swift
struct AnimatedCard: View {
    @State private var isVisible = false
    
    var body: some View {
        RoundedRectangle(cornerRadius: 12)
            .fill(Color.blue)
            .opacity(isVisible ? 1 : 0)
            .offset(y: isVisible ? 0 : 50)
            .animation(.spring(), value: isVisible)
            .onAppear {
                withAnimation(.spring().delay(0.3)) {
                    isVisible = true
                }
            }
    }
}

التأخير البالغ 0.3 ثانية يُنشئ تأثير ظهور متسلسل إذا كان هناك عدة بطاقات على الشاشة. لقائمة عناصر متحركة، استخدم فهرس العنصر كمضاعف للتأخير.

.onAppear مقابل .task — الفرق

.task هو مُعدِّل SwiftUI أُضيف في iOS 15 يحل مشكلة العمليات غير المتزامنة في onAppear. على عكس onAppear، يقبل .task إغلاقاً async، ويدير دورة حياته تلقائياً، ويُلغيه عند اختفاء View. بينما onAppear يُنفَّذ بشكل متزامن، يُطلق .task عملية غير متزامنة ويسمح لـ SwiftUI بإلغائها عند onDisappear.

الفرق الرئيسي هو إدارة الإلغاء. عندما يُنشئ .task عملية async، يحفظ SwiftUI مرجعاً لـ Task ويستدعي cancel() تلقائياً عند إزالة View من التسلسل. onAppear مع Task {} داخله لا يُلغي العملية الجارية — تستمر حتى بعد اختفاء View، مما قد يُسبب حالات سباق أو كتابة في مثيل مُحرَّر.

الخاصية.onAppear.task
إصدار iOSiOS 13+iOS 15+
دعم asyncفقط عبر Task {}Async/await أصلي
إلغاء تلقائيلاعند اختفاء View
إعادة الاستدعاءعند كل ظهورمرة واحدة افتراضياً
كود متزامننعمAsync فقط

اختيار المُعدِّل: للإجراءات المتزامنة (الرسوم المتحركة، التحليلات، التسجيل) استخدم onAppear. لتحميل البيانات غير المتزامن (API، Core Data، نظام الملفات) فضّل .task — فهو أكثر أماناً ونظافة.

أخطاء شائعة مع .onAppear

الخطأ 1: استدعاءات متعددة بسبب إعادة إنشاء View. عندما يُعيد SwiftUI إنشاء جسم View (تغيير حالة، دوران شاشة)، قد يُستدعى onAppear مرة أخرى. الحل — إضافة flag تحميل أو استخدام .equatable() لمنع إعادة الرسم غير الضرورية. وفقاً SwiftLee (2025)، 40% من أخطاء SwiftUI في الإنتاج مرتبطة باستدعاءات onAppear المتكررة.

الخطأ 2: تسريب ذاكرة عبر مرجع قوي. إذا التقط إغلاق onAppear self بدون مرجع ضعيف، يُنشئ دورة احتجاز مع View. لا يضمن SwiftUI إلغاء الكائنات الملتقطة عند اختفاء View. استخدم capture list [weak self] لـ ViewModel أو الخدمات.

الخطأ 3: التنفيذ في خيط خلفية. يُنفَّذ onAppear في الخيط الرئيسي — هذا صحيح لعمليات UI. لكن إذا أطلقت Task داخل onAppear، تأكد من أن تحديث @State يحدث عبر MainActor.run. Swift 5.9 وما فوق يعود تلقائياً إلى MainActor، لكن من الأفضل تحديد @MainActor صراحةً.

كيف تتجنب الاستدعاءات المتكررة

النمط مع flag تحميل هو الطريقة الأكثر موثوقية للحماية من الازدواجية. خزّن flag في @State أو @StateObject وأعد تعيينه فقط عند التحديث اليدوي. بديل هو استخدام .task بدلاً من onAppear: .task لا يُعاد تشغيله عند إعادة الرسم افتراضياً إذا كانت العملية async قيد التشغيل بالفعل.

swift
struct SafeView: View {
    @State private var hasAppeared = false
    @State private var items: [Item] = []
    
    var body: some View {
        List(items, id: \.id) { item in
            Text(item.name)
        }
        .onAppear {
            guard !hasAppeared else { return }
            hasAppeared = true
            Task {
                items = await DataService.shared.fetchItems()
            }
        }
    }
}

الأسئلة الشائعة

كيف يختلف .onAppear عن viewDidLoad في UIKit؟

يُستدعى viewDidLoad مرة واحدة طوال عمر UIViewController، بغض النظر عن الرؤية. .onAppear يُستدعى في كل مرة تُضاف فيها View إلى التسلسل — إذا حُذفت View وأُضيفت مرة أخرى، يُشغَّل onAppear من جديد. في NavigationView، يُستدعى viewDidLoad أثناء التهيئة، بينما onAppear يُستدعى في كل عرض للشاشة.

هل يمكن استدعاء دالة async داخل .onAppear؟

نعم، عبر غلاف Task { await asyncFunction() }. لكن للعمليات async يُفضّل .task، الذي يدير الإلغاء تلقائياً ولا يتطلب إنشاء Task يدوياً. .task يضمن أيضاً الإلغاء عند اختفاء View، مما يمنع التسريبات.

لماذا يُستدعى .onAppear عدة مرات؟

السبب هو إعادة إنشاء جسم View بسبب تغييرات في @State، @Published، أو تكوين السلف. قد يُعيد SwiftUI رسم View استجابة لتغييرات في أي خاصية قابلة للملاحظة. بالإضافة، LazyVStack و List تستدعيان onAppear للخلايا التي تقترب من المنطقة المرئية، ومرة أخرى عند التمرير لأعلى.

هل يعمل .onAppear على watchOS و tvOS؟

نعم، .onAppear متاح على جميع منصات SwiftUI: iOS 13+، watchOS 6+، tvOS 13+، macOS 10.15+. السلوك متطابق: يُستدعى المُعدِّل عند إضافة View إلى التسلسل. على watchOS، يُشغَّل onAppear عند تنشيط التطبيق من حالة الانتظار، مما يتطلب مراعاة في التصميم.

كيف تمرر معاملات إلى .onAppear؟

.onAppear لا يقبل معاملات — فقط إغلاق Void. لتمرير معاملات، استخدم إغلاقاً يلتقط متغيرات خارجية. نهج بديل هو إنشاء مُعدِّل onAppear مخصص مع معاملات عبر ViewModifier أو ما يعادل .onChange.

الخلاصة

  • .onAppear هو مُعدِّل SwiftUI لتنفيذ الكود عند إضافة View إلى تسلسل الواجهة.
  • استدعاء واحد — يُستدعى onAppear مرة واحدة لكل مثيل View إذا بقي في الذاكرة.
  • ترتيب الأب أولاً — View الأب تستقبل onAppear قبل الابن.
  • الاستخدامات الرئيسية — تحميل البيانات، تشغيل الرسوم المتحركة، إرسال التحليلات.
  • .task أُفضل للعمليات async بسبب الإلغاء التلقائي عند اختفاء View.
  • فحص الحماية — إلزامي للحماية من الاستدعاءات المتكررة عند إعادة رسم View.

سنقوم بتطوير تطبيق جوال جاهز

تقدم IT Sectr تطبيقات iOS وAndroid للشركات الناشئة والشركات منذ عام 2017. سوف نقدم لك النصح ونقترح أفضل حل.

مناقشة المشروع

اقرأ أيضًا