Showing a welcome screen once per dayData model code review for iOS appShowing a certain screen depending on a particular statusSwitching between view controllers that are loaded in the backgroundQuiz game logicTime manipulation for notification remindersShowing segue after button actionStyling navigationController per viewControllerHandler for a UI to select multiple days of the week for notificationsPresenting and passing data to a modal view controller without using prepare(for:sender:) methodQuiz app with Practice and Exam modes

Some Russian letters overlap the next line of text when used in drop caps

What do you call a painting on a wall?

How to preserve a rare version of a book?

Madam I m Adam..please don’t get mad..you will no longer be prime

Is any special diet an effective treatment of autism?

Gerrymandering Puzzle - Rig the Election

Is there a proof that the set of real numbers can exactly represent distances?

What was the first story to feature the plot "the monsters were human all along"?

Dihedral group D4 composition with custom labels

Endgame puzzle: How to avoid stalemate and win?

In "Avengers: Endgame", what does this name refer to?

How can a hefty sand storm happen in a thin atmosphere like Martian?

As a GM, is it bad form to ask for a moment to think when improvising?

Why would one crossvalidate the random state number?

How to pass hash as password to ssh server

Sci-fi/fantasy book - ships on steel runners skating across ice sheets

Can I hide the part of long lines that exceeds the visual line?

no sense/need/point

What makes an isotope stable?

Sheared off exhasut pipe: How to fix without a welder?

How to deal with employer who keeps me at work after working hours

My large rocket is still flipping over

Why are oscilloscope input impedances so low?

Looking for sci-fi book based on Hinduism/Buddhism



Showing a welcome screen once per day


Data model code review for iOS appShowing a certain screen depending on a particular statusSwitching between view controllers that are loaded in the backgroundQuiz game logicTime manipulation for notification remindersShowing segue after button actionStyling navigationController per viewControllerHandler for a UI to select multiple days of the week for notificationsPresenting and passing data to a modal view controller without using prepare(for:sender:) methodQuiz app with Practice and Exam modes






.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty margin-bottom:0;








1












$begingroup$


I have this method, which first basically shows a Welcome screen to user only once per day. The code I have so far is this



private func showGreetingScreen (tabbar: UITabBarController) 
let defaults = UserDefaults.standard
if defaults.object(forKey: "greetingDate") == nil
defaults.set(Date(), forKey: "greetingDate")
presentWelcomeScreen(tabbar: tabbar)
else
if let greetingDate = defaults.object(forKey: "greetingDate") as? Date
let order = Calendar.current.compare(Date(), to: greetingDate, toGranularity: .day)
if order == .orderedDescending
defaults.set(Date(), forKey: "greetingDate")
presentWelcomeScreen(tabbar: tabbar)






Now as you can see first I am checking whether Welcome Screen was shown in past or not and then I am saving current date. Then next time app will load, it will compare current date and the date Welcome Screen was shown and based on that It will show Welcome screen to User.
I have feeling that this code can be refactored more.










share|improve this question











$endgroup$


















    1












    $begingroup$


    I have this method, which first basically shows a Welcome screen to user only once per day. The code I have so far is this



    private func showGreetingScreen (tabbar: UITabBarController) 
    let defaults = UserDefaults.standard
    if defaults.object(forKey: "greetingDate") == nil
    defaults.set(Date(), forKey: "greetingDate")
    presentWelcomeScreen(tabbar: tabbar)
    else
    if let greetingDate = defaults.object(forKey: "greetingDate") as? Date
    let order = Calendar.current.compare(Date(), to: greetingDate, toGranularity: .day)
    if order == .orderedDescending
    defaults.set(Date(), forKey: "greetingDate")
    presentWelcomeScreen(tabbar: tabbar)






    Now as you can see first I am checking whether Welcome Screen was shown in past or not and then I am saving current date. Then next time app will load, it will compare current date and the date Welcome Screen was shown and based on that It will show Welcome screen to User.
    I have feeling that this code can be refactored more.










    share|improve this question











    $endgroup$














      1












      1








      1





      $begingroup$


      I have this method, which first basically shows a Welcome screen to user only once per day. The code I have so far is this



      private func showGreetingScreen (tabbar: UITabBarController) 
      let defaults = UserDefaults.standard
      if defaults.object(forKey: "greetingDate") == nil
      defaults.set(Date(), forKey: "greetingDate")
      presentWelcomeScreen(tabbar: tabbar)
      else
      if let greetingDate = defaults.object(forKey: "greetingDate") as? Date
      let order = Calendar.current.compare(Date(), to: greetingDate, toGranularity: .day)
      if order == .orderedDescending
      defaults.set(Date(), forKey: "greetingDate")
      presentWelcomeScreen(tabbar: tabbar)






      Now as you can see first I am checking whether Welcome Screen was shown in past or not and then I am saving current date. Then next time app will load, it will compare current date and the date Welcome Screen was shown and based on that It will show Welcome screen to User.
      I have feeling that this code can be refactored more.










      share|improve this question











      $endgroup$




      I have this method, which first basically shows a Welcome screen to user only once per day. The code I have so far is this



      private func showGreetingScreen (tabbar: UITabBarController) 
      let defaults = UserDefaults.standard
      if defaults.object(forKey: "greetingDate") == nil
      defaults.set(Date(), forKey: "greetingDate")
      presentWelcomeScreen(tabbar: tabbar)
      else
      if let greetingDate = defaults.object(forKey: "greetingDate") as? Date
      let order = Calendar.current.compare(Date(), to: greetingDate, toGranularity: .day)
      if order == .orderedDescending
      defaults.set(Date(), forKey: "greetingDate")
      presentWelcomeScreen(tabbar: tabbar)






      Now as you can see first I am checking whether Welcome Screen was shown in past or not and then I am saving current date. Then next time app will load, it will compare current date and the date Welcome Screen was shown and based on that It will show Welcome screen to User.
      I have feeling that this code can be refactored more.







      swift ios






      share|improve this question















      share|improve this question













      share|improve this question




      share|improve this question








      edited Apr 26 at 14:30









      Stephen Rauch

      3,77061630




      3,77061630










      asked Apr 26 at 9:36









      Shabir janShabir jan

      1364




      1364




















          3 Answers
          3






          active

          oldest

          votes


















          4












          $begingroup$

          There is some code duplication for the cases “greeting date has never been set” and “last greeting was yesterday or earlier.” This can be avoided if you use the nil-coalescing operator ?? to set the last greeting date to a default value in the past:



          let defaults = UserDefaults.standard
          let lastGreeting = defaults.object(forKey: "greetingDate") as? Date ?? .distantPast
          let now = Date()
          if Calendar.current.compare(now, to: lastGreeting, toGranularity: .day) == .orderedDescending
          defaults.set(now, forKey: "greetingDate")
          presentWelcomeScreen(tabbar: tabbar)






          share|improve this answer









          $endgroup$




















            3












            $begingroup$


            • You could rearrange the conditions this way :



              if let greetingDate = defaults.object(forKey: "greetingDate") as? Date 
              let order = Calendar.current.compare(date, to: greetingDate, toGranularity: .day)
              if order == .orderedDescending
              defaults.set(date, forKey: "greetingDate")
              presentWelcomeScreen(tabbar: tabbar)

              else
              defaults.set(date, forKey: "greetingDate")
              presentWelcomeScreen(tabbar: tabbar)



            • You could extract Date() as a local variable in this function just in case you are crossing midnight between checks.



            • The parameter name tabbar in both showGreetingScreen and presentWelcomeScreen doesn't seem necessary, you could use a wild card external name _ to avoid being too verbose:



              private func showGreetingScreen (_ tabbar: UITabBarController) 
              ...
              presentWelcomeScreen(tabbar)



            • tabbar isn't used in this function. It is only passed to presentWelcomeScreen, and this calls for refactoring the messaging in your code.



            • Instead of having string literals laying around inside your code, I would prefer to have a struct with all the keys to avoid possible errors:



              struct UDKeys 
              static let greetingDateKey = "greetingDate"
              static let otherKey = "anotherKey"



              Or declare these keys in an extension of UserDefaults itself :



              extension UserDefaults 
              static let greetingDateKey = "greetingDate"
              static let otherKey = "anotherKey"




            Finally, your code would look like this :



            struct UDKeys 
            static let greetingDateKey = "greetingDate"
            static let otherKey = "anotherKey"


            private func showGreetingScreen (_ tabbar: UITabBarController)
            let defaults = UserDefaults.standard
            let date = Date()
            if let greetingDate = defaults.object(forKey: UDKeys.greetingDateKey) as? Date
            let order = Calendar.current.compare(date, to: greetingDate, toGranularity: .day)
            if order == .orderedDescending
            defaults.set(date, forKey: UDKeys.greetingDateKey)
            presentWelcomeScreen(tabbar)

            else
            defaults.set(date, forKey: UDKeys.greetingDateKey)
            presentWelcomeScreen(tabbar)







            share|improve this answer











            $endgroup$




















              1












              $begingroup$

              just some other refactoring hints:



              • encapsulate the check in a own UserUsageController class

              • then you can test it better

              • maybe the check for midnight is dependend on timezone?

              user returning over time zone:



              • show the welcome screen also if the last visit longer then a 8 hours - maybe user comes there at 23:00 and again at 02:00 - then it also not make sense to show the welcome screen

              short time user:



              • maybe only set the lastVisitDate if the user has used the app more then 2 minutes (for example if he enter the app because he accidently tap on a push notification)

              • or set the last visit date only when the user exits the welcome screen

              sample implementation (thanks to @Martin-R for code deduplication):



              import UIKit

              class UserUsageController

              static let greetingDateKey = "greetingDate"

              static func isReturning(now: Date = Date(), minHours: Int = 8) -> Bool

              let lastGreeting = getLastVisit() ?? .distantPast

              let dayBefore = isDayBefore(now: now, last: lastGreeting)
              let leastTime = isLeastTime(now: now, last: lastGreeting, minHours: minHours)
              return dayBefore && leastTime


              private static func isDayBefore(now: Date, last: Date) -> Bool
              return Calendar.current.compare(now, to: last, toGranularity: .day) == .orderedDescending


              private static func isLeastTime(now: Date, last: Date, minHours: Int) -> Bool
              let hours = Calendar.current.dateComponents([.hour], from: last, to: now ).hour ?? 0
              return hours > minHours


              static func setLastVisit(date: Date = Date())
              UserDefaults.standard.set(date, forKey: greetingDateKey)


              static func getLastVisit() -> Date?
              return UserDefaults.standard.object(forKey: greetingDateKey) as? Date




              Tests:



              let df = DateFormatter()
              df.dateFormat = "yyyy/MM/dd HH:mm"

              UserUsageController.setLastVisit(date: df.date(from: "2019/04/20 01:00")! )
              assert(false == UserUsageController.isReturning(now: df.date(from: "2019/04/20 09:00")!))
              assert(false == UserUsageController.isReturning(now: df.date(from: "2019/04/20 23:00")!))

              UserUsageController.setLastVisit(date: df.date(from: "2019/04/20 22:00")! )

              assert(false == UserUsageController.isReturning(now: df.date(from: "2019/04/21 01:00")!))
              assert(true == UserUsageController.isReturning(now: df.date(from: "2019/04/21 01:00")!,
              minHours: 1))
              assert(false == UserUsageController.isReturning(now: df.date(from: "2019/04/21 06:59")!))
              assert(true == UserUsageController.isReturning(now: df.date(from: "2019/04/21 07:00")!))
              assert(true == UserUsageController.isReturning(now: df.date(from: "2019/04/21 08:00")!))
              assert(true == UserUsageController.isReturning(now: df.date(from: "2019/04/22 08:00")!))


              Usage:




              // in calling class

              if UserUsageController.isReturning()
              // OpenWelcomeScreen



              // onClose at welcomeScreen
              UserUsageController.setLastVisit()






              share|improve this answer









              $endgroup$













                Your Answer






                StackExchange.ifUsing("editor", function ()
                StackExchange.using("externalEditor", function ()
                StackExchange.using("snippets", function ()
                StackExchange.snippets.init();
                );
                );
                , "code-snippets");

                StackExchange.ready(function()
                var channelOptions =
                tags: "".split(" "),
                id: "196"
                ;
                initTagRenderer("".split(" "), "".split(" "), channelOptions);

                StackExchange.using("externalEditor", function()
                // Have to fire editor after snippets, if snippets enabled
                if (StackExchange.settings.snippets.snippetsEnabled)
                StackExchange.using("snippets", function()
                createEditor();
                );

                else
                createEditor();

                );

                function createEditor()
                StackExchange.prepareEditor(
                heartbeatType: 'answer',
                autoActivateHeartbeat: false,
                convertImagesToLinks: false,
                noModals: true,
                showLowRepImageUploadWarning: true,
                reputationToPostImages: null,
                bindNavPrevention: true,
                postfix: "",
                imageUploader:
                brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
                contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
                allowUrls: true
                ,
                onDemand: true,
                discardSelector: ".discard-answer"
                ,immediatelyShowMarkdownHelp:true
                );



                );













                draft saved

                draft discarded


















                StackExchange.ready(
                function ()
                StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f219165%2fshowing-a-welcome-screen-once-per-day%23new-answer', 'question_page');

                );

                Post as a guest















                Required, but never shown

























                3 Answers
                3






                active

                oldest

                votes








                3 Answers
                3






                active

                oldest

                votes









                active

                oldest

                votes






                active

                oldest

                votes









                4












                $begingroup$

                There is some code duplication for the cases “greeting date has never been set” and “last greeting was yesterday or earlier.” This can be avoided if you use the nil-coalescing operator ?? to set the last greeting date to a default value in the past:



                let defaults = UserDefaults.standard
                let lastGreeting = defaults.object(forKey: "greetingDate") as? Date ?? .distantPast
                let now = Date()
                if Calendar.current.compare(now, to: lastGreeting, toGranularity: .day) == .orderedDescending
                defaults.set(now, forKey: "greetingDate")
                presentWelcomeScreen(tabbar: tabbar)






                share|improve this answer









                $endgroup$

















                  4












                  $begingroup$

                  There is some code duplication for the cases “greeting date has never been set” and “last greeting was yesterday or earlier.” This can be avoided if you use the nil-coalescing operator ?? to set the last greeting date to a default value in the past:



                  let defaults = UserDefaults.standard
                  let lastGreeting = defaults.object(forKey: "greetingDate") as? Date ?? .distantPast
                  let now = Date()
                  if Calendar.current.compare(now, to: lastGreeting, toGranularity: .day) == .orderedDescending
                  defaults.set(now, forKey: "greetingDate")
                  presentWelcomeScreen(tabbar: tabbar)






                  share|improve this answer









                  $endgroup$















                    4












                    4








                    4





                    $begingroup$

                    There is some code duplication for the cases “greeting date has never been set” and “last greeting was yesterday or earlier.” This can be avoided if you use the nil-coalescing operator ?? to set the last greeting date to a default value in the past:



                    let defaults = UserDefaults.standard
                    let lastGreeting = defaults.object(forKey: "greetingDate") as? Date ?? .distantPast
                    let now = Date()
                    if Calendar.current.compare(now, to: lastGreeting, toGranularity: .day) == .orderedDescending
                    defaults.set(now, forKey: "greetingDate")
                    presentWelcomeScreen(tabbar: tabbar)






                    share|improve this answer









                    $endgroup$



                    There is some code duplication for the cases “greeting date has never been set” and “last greeting was yesterday or earlier.” This can be avoided if you use the nil-coalescing operator ?? to set the last greeting date to a default value in the past:



                    let defaults = UserDefaults.standard
                    let lastGreeting = defaults.object(forKey: "greetingDate") as? Date ?? .distantPast
                    let now = Date()
                    if Calendar.current.compare(now, to: lastGreeting, toGranularity: .day) == .orderedDescending
                    defaults.set(now, forKey: "greetingDate")
                    presentWelcomeScreen(tabbar: tabbar)







                    share|improve this answer












                    share|improve this answer



                    share|improve this answer










                    answered Apr 26 at 13:29









                    Martin RMartin R

                    16.4k12366




                    16.4k12366























                        3












                        $begingroup$


                        • You could rearrange the conditions this way :



                          if let greetingDate = defaults.object(forKey: "greetingDate") as? Date 
                          let order = Calendar.current.compare(date, to: greetingDate, toGranularity: .day)
                          if order == .orderedDescending
                          defaults.set(date, forKey: "greetingDate")
                          presentWelcomeScreen(tabbar: tabbar)

                          else
                          defaults.set(date, forKey: "greetingDate")
                          presentWelcomeScreen(tabbar: tabbar)



                        • You could extract Date() as a local variable in this function just in case you are crossing midnight between checks.



                        • The parameter name tabbar in both showGreetingScreen and presentWelcomeScreen doesn't seem necessary, you could use a wild card external name _ to avoid being too verbose:



                          private func showGreetingScreen (_ tabbar: UITabBarController) 
                          ...
                          presentWelcomeScreen(tabbar)



                        • tabbar isn't used in this function. It is only passed to presentWelcomeScreen, and this calls for refactoring the messaging in your code.



                        • Instead of having string literals laying around inside your code, I would prefer to have a struct with all the keys to avoid possible errors:



                          struct UDKeys 
                          static let greetingDateKey = "greetingDate"
                          static let otherKey = "anotherKey"



                          Or declare these keys in an extension of UserDefaults itself :



                          extension UserDefaults 
                          static let greetingDateKey = "greetingDate"
                          static let otherKey = "anotherKey"




                        Finally, your code would look like this :



                        struct UDKeys 
                        static let greetingDateKey = "greetingDate"
                        static let otherKey = "anotherKey"


                        private func showGreetingScreen (_ tabbar: UITabBarController)
                        let defaults = UserDefaults.standard
                        let date = Date()
                        if let greetingDate = defaults.object(forKey: UDKeys.greetingDateKey) as? Date
                        let order = Calendar.current.compare(date, to: greetingDate, toGranularity: .day)
                        if order == .orderedDescending
                        defaults.set(date, forKey: UDKeys.greetingDateKey)
                        presentWelcomeScreen(tabbar)

                        else
                        defaults.set(date, forKey: UDKeys.greetingDateKey)
                        presentWelcomeScreen(tabbar)







                        share|improve this answer











                        $endgroup$

















                          3












                          $begingroup$


                          • You could rearrange the conditions this way :



                            if let greetingDate = defaults.object(forKey: "greetingDate") as? Date 
                            let order = Calendar.current.compare(date, to: greetingDate, toGranularity: .day)
                            if order == .orderedDescending
                            defaults.set(date, forKey: "greetingDate")
                            presentWelcomeScreen(tabbar: tabbar)

                            else
                            defaults.set(date, forKey: "greetingDate")
                            presentWelcomeScreen(tabbar: tabbar)



                          • You could extract Date() as a local variable in this function just in case you are crossing midnight between checks.



                          • The parameter name tabbar in both showGreetingScreen and presentWelcomeScreen doesn't seem necessary, you could use a wild card external name _ to avoid being too verbose:



                            private func showGreetingScreen (_ tabbar: UITabBarController) 
                            ...
                            presentWelcomeScreen(tabbar)



                          • tabbar isn't used in this function. It is only passed to presentWelcomeScreen, and this calls for refactoring the messaging in your code.



                          • Instead of having string literals laying around inside your code, I would prefer to have a struct with all the keys to avoid possible errors:



                            struct UDKeys 
                            static let greetingDateKey = "greetingDate"
                            static let otherKey = "anotherKey"



                            Or declare these keys in an extension of UserDefaults itself :



                            extension UserDefaults 
                            static let greetingDateKey = "greetingDate"
                            static let otherKey = "anotherKey"




                          Finally, your code would look like this :



                          struct UDKeys 
                          static let greetingDateKey = "greetingDate"
                          static let otherKey = "anotherKey"


                          private func showGreetingScreen (_ tabbar: UITabBarController)
                          let defaults = UserDefaults.standard
                          let date = Date()
                          if let greetingDate = defaults.object(forKey: UDKeys.greetingDateKey) as? Date
                          let order = Calendar.current.compare(date, to: greetingDate, toGranularity: .day)
                          if order == .orderedDescending
                          defaults.set(date, forKey: UDKeys.greetingDateKey)
                          presentWelcomeScreen(tabbar)

                          else
                          defaults.set(date, forKey: UDKeys.greetingDateKey)
                          presentWelcomeScreen(tabbar)







                          share|improve this answer











                          $endgroup$















                            3












                            3








                            3





                            $begingroup$


                            • You could rearrange the conditions this way :



                              if let greetingDate = defaults.object(forKey: "greetingDate") as? Date 
                              let order = Calendar.current.compare(date, to: greetingDate, toGranularity: .day)
                              if order == .orderedDescending
                              defaults.set(date, forKey: "greetingDate")
                              presentWelcomeScreen(tabbar: tabbar)

                              else
                              defaults.set(date, forKey: "greetingDate")
                              presentWelcomeScreen(tabbar: tabbar)



                            • You could extract Date() as a local variable in this function just in case you are crossing midnight between checks.



                            • The parameter name tabbar in both showGreetingScreen and presentWelcomeScreen doesn't seem necessary, you could use a wild card external name _ to avoid being too verbose:



                              private func showGreetingScreen (_ tabbar: UITabBarController) 
                              ...
                              presentWelcomeScreen(tabbar)



                            • tabbar isn't used in this function. It is only passed to presentWelcomeScreen, and this calls for refactoring the messaging in your code.



                            • Instead of having string literals laying around inside your code, I would prefer to have a struct with all the keys to avoid possible errors:



                              struct UDKeys 
                              static let greetingDateKey = "greetingDate"
                              static let otherKey = "anotherKey"



                              Or declare these keys in an extension of UserDefaults itself :



                              extension UserDefaults 
                              static let greetingDateKey = "greetingDate"
                              static let otherKey = "anotherKey"




                            Finally, your code would look like this :



                            struct UDKeys 
                            static let greetingDateKey = "greetingDate"
                            static let otherKey = "anotherKey"


                            private func showGreetingScreen (_ tabbar: UITabBarController)
                            let defaults = UserDefaults.standard
                            let date = Date()
                            if let greetingDate = defaults.object(forKey: UDKeys.greetingDateKey) as? Date
                            let order = Calendar.current.compare(date, to: greetingDate, toGranularity: .day)
                            if order == .orderedDescending
                            defaults.set(date, forKey: UDKeys.greetingDateKey)
                            presentWelcomeScreen(tabbar)

                            else
                            defaults.set(date, forKey: UDKeys.greetingDateKey)
                            presentWelcomeScreen(tabbar)







                            share|improve this answer











                            $endgroup$




                            • You could rearrange the conditions this way :



                              if let greetingDate = defaults.object(forKey: "greetingDate") as? Date 
                              let order = Calendar.current.compare(date, to: greetingDate, toGranularity: .day)
                              if order == .orderedDescending
                              defaults.set(date, forKey: "greetingDate")
                              presentWelcomeScreen(tabbar: tabbar)

                              else
                              defaults.set(date, forKey: "greetingDate")
                              presentWelcomeScreen(tabbar: tabbar)



                            • You could extract Date() as a local variable in this function just in case you are crossing midnight between checks.



                            • The parameter name tabbar in both showGreetingScreen and presentWelcomeScreen doesn't seem necessary, you could use a wild card external name _ to avoid being too verbose:



                              private func showGreetingScreen (_ tabbar: UITabBarController) 
                              ...
                              presentWelcomeScreen(tabbar)



                            • tabbar isn't used in this function. It is only passed to presentWelcomeScreen, and this calls for refactoring the messaging in your code.



                            • Instead of having string literals laying around inside your code, I would prefer to have a struct with all the keys to avoid possible errors:



                              struct UDKeys 
                              static let greetingDateKey = "greetingDate"
                              static let otherKey = "anotherKey"



                              Or declare these keys in an extension of UserDefaults itself :



                              extension UserDefaults 
                              static let greetingDateKey = "greetingDate"
                              static let otherKey = "anotherKey"




                            Finally, your code would look like this :



                            struct UDKeys 
                            static let greetingDateKey = "greetingDate"
                            static let otherKey = "anotherKey"


                            private func showGreetingScreen (_ tabbar: UITabBarController)
                            let defaults = UserDefaults.standard
                            let date = Date()
                            if let greetingDate = defaults.object(forKey: UDKeys.greetingDateKey) as? Date
                            let order = Calendar.current.compare(date, to: greetingDate, toGranularity: .day)
                            if order == .orderedDescending
                            defaults.set(date, forKey: UDKeys.greetingDateKey)
                            presentWelcomeScreen(tabbar)

                            else
                            defaults.set(date, forKey: UDKeys.greetingDateKey)
                            presentWelcomeScreen(tabbar)








                            share|improve this answer














                            share|improve this answer



                            share|improve this answer








                            edited Apr 26 at 10:45

























                            answered Apr 26 at 10:28









                            ielyamaniielyamani

                            444315




                            444315





















                                1












                                $begingroup$

                                just some other refactoring hints:



                                • encapsulate the check in a own UserUsageController class

                                • then you can test it better

                                • maybe the check for midnight is dependend on timezone?

                                user returning over time zone:



                                • show the welcome screen also if the last visit longer then a 8 hours - maybe user comes there at 23:00 and again at 02:00 - then it also not make sense to show the welcome screen

                                short time user:



                                • maybe only set the lastVisitDate if the user has used the app more then 2 minutes (for example if he enter the app because he accidently tap on a push notification)

                                • or set the last visit date only when the user exits the welcome screen

                                sample implementation (thanks to @Martin-R for code deduplication):



                                import UIKit

                                class UserUsageController

                                static let greetingDateKey = "greetingDate"

                                static func isReturning(now: Date = Date(), minHours: Int = 8) -> Bool

                                let lastGreeting = getLastVisit() ?? .distantPast

                                let dayBefore = isDayBefore(now: now, last: lastGreeting)
                                let leastTime = isLeastTime(now: now, last: lastGreeting, minHours: minHours)
                                return dayBefore && leastTime


                                private static func isDayBefore(now: Date, last: Date) -> Bool
                                return Calendar.current.compare(now, to: last, toGranularity: .day) == .orderedDescending


                                private static func isLeastTime(now: Date, last: Date, minHours: Int) -> Bool
                                let hours = Calendar.current.dateComponents([.hour], from: last, to: now ).hour ?? 0
                                return hours > minHours


                                static func setLastVisit(date: Date = Date())
                                UserDefaults.standard.set(date, forKey: greetingDateKey)


                                static func getLastVisit() -> Date?
                                return UserDefaults.standard.object(forKey: greetingDateKey) as? Date




                                Tests:



                                let df = DateFormatter()
                                df.dateFormat = "yyyy/MM/dd HH:mm"

                                UserUsageController.setLastVisit(date: df.date(from: "2019/04/20 01:00")! )
                                assert(false == UserUsageController.isReturning(now: df.date(from: "2019/04/20 09:00")!))
                                assert(false == UserUsageController.isReturning(now: df.date(from: "2019/04/20 23:00")!))

                                UserUsageController.setLastVisit(date: df.date(from: "2019/04/20 22:00")! )

                                assert(false == UserUsageController.isReturning(now: df.date(from: "2019/04/21 01:00")!))
                                assert(true == UserUsageController.isReturning(now: df.date(from: "2019/04/21 01:00")!,
                                minHours: 1))
                                assert(false == UserUsageController.isReturning(now: df.date(from: "2019/04/21 06:59")!))
                                assert(true == UserUsageController.isReturning(now: df.date(from: "2019/04/21 07:00")!))
                                assert(true == UserUsageController.isReturning(now: df.date(from: "2019/04/21 08:00")!))
                                assert(true == UserUsageController.isReturning(now: df.date(from: "2019/04/22 08:00")!))


                                Usage:




                                // in calling class

                                if UserUsageController.isReturning()
                                // OpenWelcomeScreen



                                // onClose at welcomeScreen
                                UserUsageController.setLastVisit()






                                share|improve this answer









                                $endgroup$

















                                  1












                                  $begingroup$

                                  just some other refactoring hints:



                                  • encapsulate the check in a own UserUsageController class

                                  • then you can test it better

                                  • maybe the check for midnight is dependend on timezone?

                                  user returning over time zone:



                                  • show the welcome screen also if the last visit longer then a 8 hours - maybe user comes there at 23:00 and again at 02:00 - then it also not make sense to show the welcome screen

                                  short time user:



                                  • maybe only set the lastVisitDate if the user has used the app more then 2 minutes (for example if he enter the app because he accidently tap on a push notification)

                                  • or set the last visit date only when the user exits the welcome screen

                                  sample implementation (thanks to @Martin-R for code deduplication):



                                  import UIKit

                                  class UserUsageController

                                  static let greetingDateKey = "greetingDate"

                                  static func isReturning(now: Date = Date(), minHours: Int = 8) -> Bool

                                  let lastGreeting = getLastVisit() ?? .distantPast

                                  let dayBefore = isDayBefore(now: now, last: lastGreeting)
                                  let leastTime = isLeastTime(now: now, last: lastGreeting, minHours: minHours)
                                  return dayBefore && leastTime


                                  private static func isDayBefore(now: Date, last: Date) -> Bool
                                  return Calendar.current.compare(now, to: last, toGranularity: .day) == .orderedDescending


                                  private static func isLeastTime(now: Date, last: Date, minHours: Int) -> Bool
                                  let hours = Calendar.current.dateComponents([.hour], from: last, to: now ).hour ?? 0
                                  return hours > minHours


                                  static func setLastVisit(date: Date = Date())
                                  UserDefaults.standard.set(date, forKey: greetingDateKey)


                                  static func getLastVisit() -> Date?
                                  return UserDefaults.standard.object(forKey: greetingDateKey) as? Date




                                  Tests:



                                  let df = DateFormatter()
                                  df.dateFormat = "yyyy/MM/dd HH:mm"

                                  UserUsageController.setLastVisit(date: df.date(from: "2019/04/20 01:00")! )
                                  assert(false == UserUsageController.isReturning(now: df.date(from: "2019/04/20 09:00")!))
                                  assert(false == UserUsageController.isReturning(now: df.date(from: "2019/04/20 23:00")!))

                                  UserUsageController.setLastVisit(date: df.date(from: "2019/04/20 22:00")! )

                                  assert(false == UserUsageController.isReturning(now: df.date(from: "2019/04/21 01:00")!))
                                  assert(true == UserUsageController.isReturning(now: df.date(from: "2019/04/21 01:00")!,
                                  minHours: 1))
                                  assert(false == UserUsageController.isReturning(now: df.date(from: "2019/04/21 06:59")!))
                                  assert(true == UserUsageController.isReturning(now: df.date(from: "2019/04/21 07:00")!))
                                  assert(true == UserUsageController.isReturning(now: df.date(from: "2019/04/21 08:00")!))
                                  assert(true == UserUsageController.isReturning(now: df.date(from: "2019/04/22 08:00")!))


                                  Usage:




                                  // in calling class

                                  if UserUsageController.isReturning()
                                  // OpenWelcomeScreen



                                  // onClose at welcomeScreen
                                  UserUsageController.setLastVisit()






                                  share|improve this answer









                                  $endgroup$















                                    1












                                    1








                                    1





                                    $begingroup$

                                    just some other refactoring hints:



                                    • encapsulate the check in a own UserUsageController class

                                    • then you can test it better

                                    • maybe the check for midnight is dependend on timezone?

                                    user returning over time zone:



                                    • show the welcome screen also if the last visit longer then a 8 hours - maybe user comes there at 23:00 and again at 02:00 - then it also not make sense to show the welcome screen

                                    short time user:



                                    • maybe only set the lastVisitDate if the user has used the app more then 2 minutes (for example if he enter the app because he accidently tap on a push notification)

                                    • or set the last visit date only when the user exits the welcome screen

                                    sample implementation (thanks to @Martin-R for code deduplication):



                                    import UIKit

                                    class UserUsageController

                                    static let greetingDateKey = "greetingDate"

                                    static func isReturning(now: Date = Date(), minHours: Int = 8) -> Bool

                                    let lastGreeting = getLastVisit() ?? .distantPast

                                    let dayBefore = isDayBefore(now: now, last: lastGreeting)
                                    let leastTime = isLeastTime(now: now, last: lastGreeting, minHours: minHours)
                                    return dayBefore && leastTime


                                    private static func isDayBefore(now: Date, last: Date) -> Bool
                                    return Calendar.current.compare(now, to: last, toGranularity: .day) == .orderedDescending


                                    private static func isLeastTime(now: Date, last: Date, minHours: Int) -> Bool
                                    let hours = Calendar.current.dateComponents([.hour], from: last, to: now ).hour ?? 0
                                    return hours > minHours


                                    static func setLastVisit(date: Date = Date())
                                    UserDefaults.standard.set(date, forKey: greetingDateKey)


                                    static func getLastVisit() -> Date?
                                    return UserDefaults.standard.object(forKey: greetingDateKey) as? Date




                                    Tests:



                                    let df = DateFormatter()
                                    df.dateFormat = "yyyy/MM/dd HH:mm"

                                    UserUsageController.setLastVisit(date: df.date(from: "2019/04/20 01:00")! )
                                    assert(false == UserUsageController.isReturning(now: df.date(from: "2019/04/20 09:00")!))
                                    assert(false == UserUsageController.isReturning(now: df.date(from: "2019/04/20 23:00")!))

                                    UserUsageController.setLastVisit(date: df.date(from: "2019/04/20 22:00")! )

                                    assert(false == UserUsageController.isReturning(now: df.date(from: "2019/04/21 01:00")!))
                                    assert(true == UserUsageController.isReturning(now: df.date(from: "2019/04/21 01:00")!,
                                    minHours: 1))
                                    assert(false == UserUsageController.isReturning(now: df.date(from: "2019/04/21 06:59")!))
                                    assert(true == UserUsageController.isReturning(now: df.date(from: "2019/04/21 07:00")!))
                                    assert(true == UserUsageController.isReturning(now: df.date(from: "2019/04/21 08:00")!))
                                    assert(true == UserUsageController.isReturning(now: df.date(from: "2019/04/22 08:00")!))


                                    Usage:




                                    // in calling class

                                    if UserUsageController.isReturning()
                                    // OpenWelcomeScreen



                                    // onClose at welcomeScreen
                                    UserUsageController.setLastVisit()






                                    share|improve this answer









                                    $endgroup$



                                    just some other refactoring hints:



                                    • encapsulate the check in a own UserUsageController class

                                    • then you can test it better

                                    • maybe the check for midnight is dependend on timezone?

                                    user returning over time zone:



                                    • show the welcome screen also if the last visit longer then a 8 hours - maybe user comes there at 23:00 and again at 02:00 - then it also not make sense to show the welcome screen

                                    short time user:



                                    • maybe only set the lastVisitDate if the user has used the app more then 2 minutes (for example if he enter the app because he accidently tap on a push notification)

                                    • or set the last visit date only when the user exits the welcome screen

                                    sample implementation (thanks to @Martin-R for code deduplication):



                                    import UIKit

                                    class UserUsageController

                                    static let greetingDateKey = "greetingDate"

                                    static func isReturning(now: Date = Date(), minHours: Int = 8) -> Bool

                                    let lastGreeting = getLastVisit() ?? .distantPast

                                    let dayBefore = isDayBefore(now: now, last: lastGreeting)
                                    let leastTime = isLeastTime(now: now, last: lastGreeting, minHours: minHours)
                                    return dayBefore && leastTime


                                    private static func isDayBefore(now: Date, last: Date) -> Bool
                                    return Calendar.current.compare(now, to: last, toGranularity: .day) == .orderedDescending


                                    private static func isLeastTime(now: Date, last: Date, minHours: Int) -> Bool
                                    let hours = Calendar.current.dateComponents([.hour], from: last, to: now ).hour ?? 0
                                    return hours > minHours


                                    static func setLastVisit(date: Date = Date())
                                    UserDefaults.standard.set(date, forKey: greetingDateKey)


                                    static func getLastVisit() -> Date?
                                    return UserDefaults.standard.object(forKey: greetingDateKey) as? Date




                                    Tests:



                                    let df = DateFormatter()
                                    df.dateFormat = "yyyy/MM/dd HH:mm"

                                    UserUsageController.setLastVisit(date: df.date(from: "2019/04/20 01:00")! )
                                    assert(false == UserUsageController.isReturning(now: df.date(from: "2019/04/20 09:00")!))
                                    assert(false == UserUsageController.isReturning(now: df.date(from: "2019/04/20 23:00")!))

                                    UserUsageController.setLastVisit(date: df.date(from: "2019/04/20 22:00")! )

                                    assert(false == UserUsageController.isReturning(now: df.date(from: "2019/04/21 01:00")!))
                                    assert(true == UserUsageController.isReturning(now: df.date(from: "2019/04/21 01:00")!,
                                    minHours: 1))
                                    assert(false == UserUsageController.isReturning(now: df.date(from: "2019/04/21 06:59")!))
                                    assert(true == UserUsageController.isReturning(now: df.date(from: "2019/04/21 07:00")!))
                                    assert(true == UserUsageController.isReturning(now: df.date(from: "2019/04/21 08:00")!))
                                    assert(true == UserUsageController.isReturning(now: df.date(from: "2019/04/22 08:00")!))


                                    Usage:




                                    // in calling class

                                    if UserUsageController.isReturning()
                                    // OpenWelcomeScreen



                                    // onClose at welcomeScreen
                                    UserUsageController.setLastVisit()







                                    share|improve this answer












                                    share|improve this answer



                                    share|improve this answer










                                    answered Apr 26 at 17:12









                                    mueschamuescha

                                    1965




                                    1965



























                                        draft saved

                                        draft discarded
















































                                        Thanks for contributing an answer to Code Review Stack Exchange!


                                        • Please be sure to answer the question. Provide details and share your research!

                                        But avoid


                                        • Asking for help, clarification, or responding to other answers.

                                        • Making statements based on opinion; back them up with references or personal experience.

                                        Use MathJax to format equations. MathJax reference.


                                        To learn more, see our tips on writing great answers.




                                        draft saved


                                        draft discarded














                                        StackExchange.ready(
                                        function ()
                                        StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f219165%2fshowing-a-welcome-screen-once-per-day%23new-answer', 'question_page');

                                        );

                                        Post as a guest















                                        Required, but never shown





















































                                        Required, but never shown














                                        Required, but never shown












                                        Required, but never shown







                                        Required, but never shown

































                                        Required, but never shown














                                        Required, but never shown












                                        Required, but never shown







                                        Required, but never shown







                                        Popular posts from this blog

                                        How to write a 12-bar blues melodyI-IV-V blues progressionHow to play the bridges in a standard blues progressionHow does Gdim7 fit in C# minor?question on a certain chord progressionMusicology of Melody12 bar blues, spread rhythm: alternative to 6th chord to avoid finger stretchChord progressions/ Root key/ MelodiesHow to put chords (POP-EDM) under a given lead vocal melody (starting from a good knowledge in music theory)Are there “rules” for improvising with the minor pentatonic scale over 12-bar shuffle?Confusion about blues scale and chords

                                        What if the end-user didn't have the required library?What is setup.py?What is a clean, pythonic way to have multiple constructors in Python?What does Ruby have that Python doesn't, and vice versa?What is the reason for having '//' in Python?How do I create a namespace package in Python?How to package shared objects that python modules depend on?setuptools vs. distutils: why is distutils still a thing?Navigation in Windows 10 vs code not going to virtualenv library when the same library is installed at user levelPython create package for local usePackaging a project that uses multiple python versionsWhy is permission denied on pip install except for when “--user” is included at end of command?

                                        Esgonzo ibérico Índice Descrición Distribución Hábitat Ameazas Notas Véxase tamén "Acerca dos nomes dos anfibios e réptiles galegos""Chalcides bedriagai"Chalcides bedriagai en Carrascal, L. M. Salvador, A. (Eds). Enciclopedia virtual de los vertebrados españoles. Museo Nacional de Ciencias Naturales, Madrid. España.Fotos