كيف تحسن تجربة المستخدم لتطبيق بحيث تجعل المستخدم يشعر بأنه تطبيق دائما موجود لاستخدامه، ولا يتم اغلاقه من قبل النظام!

في هذا المقال سوف أشرح طريقة بسيطة تحدث فرقاً لمستخدم تطبيقك 👌

بشكل عام من المكونات الأساسية في الاجهزة هو الـ RAM او كما يسموه البعض الـ Memory النظام وجميع التطبيقات تعتمد على الـ Ram لتقوم بعملها بمجرد تشغيل تطبيق يتم استهلاك جزء من الـ Ram لصالحه بما يعني كل ما شغلت تطبيقات أكثر كل ما استهلكت Ram أكثر

وكل ما أصبح الـ Ram ممتلئاً وبالتالي أصبح النظام ابطأ!
لذلك لتجنب هذه المشاكل النظام يعمل على اغلاق التطبيقات بعد فترة طويله من عدم استخدامها وأيضا في حال عدم توفر مساحة كافيه

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

وفي هذا المثال سوف يغلق التطبيق الثالث. بما يعني حتى إذا كان التطبيق في الـ Multitasking لا يعني بأنه يعمل طوال الوقت!

إذا هناك مشكلة وهي قد يتم إغلاق تطبيقك وهو في الخلفية بسبب عدم استخدامه لفتره طويله، لذا عند عودة المستخدم لتطبيقك سيتم إعادة تشغيل من الجديد وهنا تكمن المشكلة !

ماذا إذا كان تطبيقك يتطلب من المستخدم كتابة نصوص، مثلا تطبيق كتابة يوميات او To Do list والمستخدم لم يحفظ النص، وانشغل بتطبيق اخر او مكالمة هاتفيه او غيره، الامر راح يكون مزعج للمستخدم إذا وجد التطبيق اغلق وتم حذف النص الذي كتبه !

مثال اخر إذا فقط اردت المستخدم ان يعود للتطبيق والصفحات الذي فتحها تظل مفتوحة او الخيار الذي اختار يظل مختاره، بمعنى يظل التطبيق كما كان

قبل بداية الشرح يتوجب عليك الذهاب للإعدادات النظام قسم Developer وفعل خيار Fast App Termination بهذه الطريقة تسرع عملية اغلاق النظام للتطبيق ، سوف تجعل النظام يغلق التطبيق في خلال دقيقة واحده فقط !

ملاحظة: الخيار السابق يظهر فقط في حال شبكة جوالك بالـ Xcode وعملت Run لاي مشروع ، بمعنى اخر لن يظهر الخيار لغير المطورين

في هذا الثريد سوف اشرح مثالين، ولكن يجب التوضيح بأن يمكن استخدام بعدة طرق وليس محدودة بهذه الامثله فقط !

المثال الأول : تطبيق ملاحظات، المستخدم يضغط على زر تنفتح صفحة جديدة يكتب الملاحظة الذي يريدها ويضغط حفظ يعود المستخدم للصفحة الرئيسية يجد النص الذي كتبه

struct ContentView: View {
    @State private var isEdit = false
    @State private var note = ""
    
    var body: some View {
        VStack {
            Text ("The Text is:")
            Text (note)
            Button {
                isEdit.toggle()
            } label: {
                Text ("Edit Text")
            }
        }.sheet(isPresented: $isEdit) {
            EditTextView (note: $note)
        }
    }
}

struct EditTextView: View {
    @Binding var note : String
    @Environment (\.dismiss) private var dismiss
    
    var body: some View {
        VStack {
            TextEditor (text: $note)
                .padding ()
                .background (.black)
            Button {
                dismiss ()
            } label: {
                Text ("Save Text" )
            }
        }
    }
}

الان شغل التطبيق واضغط على زر Edit Text وقم بكتابة اي نص ولا تغلق الصفحه اخرج من التطبيق افتح تطبيق الساعه وشغل المؤقت لمدة دقيقه واحده فقط ، لاحظ بعد مرور دقيقه التطبيق اعيد فتحه ! وتم حذف النص المكتوب !

الان سوف نقوم بتغييرين فقط سوف نغير قيمة State الى SceneStorage واهم ملاحظتين الاولى لازم يكون الـ Key فريد بمعنى كل SceneStorage يكون له Key مختلف عن الاخر في كل التطبيق والامر الاخر يجب استخدام SceneStorage في البيانات بسيطه وصغيره فقط

struct ContentView: View {
    @SceneStorage( "isEdit") private var isEdit = false
    @SceneStorage( "note") private var note = ""
    
    var body: some View {
        VStack {
            Text ("The Text is:")
            Text (note)
            Button {
                isEdit.toggle()
            } label: {
                Text ("Edit Text")
            }
        }.sheet(isPresented: $isEdit) {
            EditTextView (note: $note)
        }
    }
}

struct EditTextView: View {
    @Binding var note : String
    @Environment (\.dismiss) private var dismiss
    
    var body: some View {
        VStack {
            TextEditor (text: $note)
                .padding ()
                .background (.black)
            Button {
                dismiss ()
            } label: {
                Text ("Save Text" )
            }
        }
    }
}

الان شغل التطبيق وعيد نفس الخطوات اضغط على زر Edit Text اكتب اي نص تريده ، ولا تقوم بإغلاق الصفحة ، افتح تطبيق الساعه وشغل المؤقت لمدة دقيقة ومن ثم ارجع للتطبيق بعد مرور الدقيقه

لاحظ في المثال السابق ، رغم انه التطبيق تم اغلاقه من قبل النظام الا انه عند العودة له الصفحه ظلت مفتوحه وايضا النص لم يتم حذفه !

تذكر باننا فقط قمنا بتغيير بسيط !
على اي حال الـ SceneStorage تقوم بنفس مبدا عمل الـ State ولو لاحظت تم تمرير كـ Binding بدون مشاكل

الملاحظة المهمه عند استخدام SceneStorage تذكر بأن القيمة تظل محفوظه بشكل مؤقت فقط وفقط في هذا السيناريو بما يعني عند اغلاق التطبيق بشكل كلي سيتم حذف كل شي !

للتوضيح في استخدام اخر لها وهو عند دعم اكثر من Sense لتطبيقات الايباد بمعنى اذا كنت سامح للمستخدم يفتح صفحتين من تطبيقك ايضا تفيدك بحيث تحفظ بيانات كل Sense

في المثال السابق اذا اردت حفظ النص فقط، بدون الاهتمام بجعل الصفحه مفتوحه ، رجع قيمة isEdit الى State بدل من SceneStorage

اتوقع كذا وضحت انه اي متغير تستخدم فيها State تقدر تغيره الى SceneStorage

المثال الثاني : عند استخدام الـ TabBar تقدر تحفظ قيمته بشكل مؤقت بحيث عند رجوع المستخدم للتطبيق بعد اغلاقه من قبل النظام يرجع لنفس الـTab بهذه الطريقة

struct ContentView: View {
    @SceneStorage("selectedTab") private var selectedTab: Tab = .one
    
    var body: some View {
        TabView(selection: $selectedTab) {
            Text ("Tab One" )
                .tabItem {
                    Image( systemName: "car")
                    Text ("Tab One" )
                }.tag (Tab.one)
            
            Text ("Tab Two")
                .tabItem {
                    Image(systemName: "tram.fill")
                    Text ("Tab Two")
                }.tag(Tab.two)
            
            Text("Tab Three")
                .tabItem {
                    Image(systemName: "airplane" )
                    Text ("Tab Three" )
                }.tag(Tab.three)
        }
    }
    
    enum Tab: String {
        case one
        case two
        case three
    }
}