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

Overlay of two functions leaves gaps

How much cash can I safely carry into the USA and avoid civil forfeiture?

a sore throat vs a strep throat vs strep throat

Do I have an "anti-research" personality?

What does the integral of a function times a function of a random variable represent, conceptually?

How to limit Drive Letters Windows assigns to new removable USB drives

What term is being referred to with "reflected-sound-of-underground-spirits"?

How do I reattach a shelf to the wall when it ripped out of the wall?

Could the terminal length of components like resistors be reduced?

Like totally amazing interchangeable sister outfits II: The Revenge

How can I practically buy stocks?

Coordinate my way to the name of the (video) game

How to stop co-workers from teasing me because I know Russian?

Why didn't the Space Shuttle bounce back into space as many times as possible so as to lose a lot of kinetic energy up there?

What is the smallest unit of eos?

What causes platform events to fail to be published and should I cater for failed platform event creations?

Re-entry to Germany after vacation using blue card

As an international instructor, should I openly talk about my accent?

Which big number is bigger?

Can't get 5V 3A DC constant

bldc motor, esc and battery draw, nominal vs peak

Is the claim "Employers won't employ people with no 'social media presence'" realistic?

"Whatever a Russian does, they end up making the Kalashnikov gun"? Are there any similar proverbs in English?

Are there physical dangers to preparing a prepared piano?



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;








2












$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









New contributor




Shabir jan is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.







$endgroup$


















    2












    $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









    New contributor




    Shabir jan is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
    Check out our Code of Conduct.







    $endgroup$














      2












      2








      2





      $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









      New contributor




      Shabir jan is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
      Check out our Code of Conduct.







      $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









      New contributor




      Shabir jan is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
      Check out our Code of Conduct.











      share|improve this question









      New contributor




      Shabir jan is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
      Check out our Code of Conduct.









      share|improve this question




      share|improve this question








      edited 7 hours ago









      Stephen Rauch

      3,77061630




      3,77061630






      New contributor




      Shabir jan is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
      Check out our Code of Conduct.









      asked 12 hours ago









      Shabir janShabir jan

      1334




      1334




      New contributor




      Shabir jan is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
      Check out our Code of Conduct.





      New contributor





      Shabir jan is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
      Check out our Code of Conduct.






      Shabir jan is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
      Check out our Code of Conduct.




















          3 Answers
          3






          active

          oldest

          votes


















          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$




















            2












            $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$




















              0












              $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
                );



                );






                Shabir jan is a new contributor. Be nice, and check out our Code of Conduct.









                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









                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 11 hours ago

























                    answered 11 hours ago









                    ielyamaniielyamani

                    437314




                    437314























                        2












                        $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$

















                          2












                          $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$















                            2












                            2








                            2





                            $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 8 hours ago









                            Martin RMartin R

                            16.3k12366




                            16.3k12366





















                                0












                                $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$

















                                  0












                                  $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$















                                    0












                                    0








                                    0





                                    $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 5 hours ago









                                    mueschamuescha

                                    1865




                                    1865




















                                        Shabir jan is a new contributor. Be nice, and check out our Code of Conduct.









                                        draft saved

                                        draft discarded


















                                        Shabir jan is a new contributor. Be nice, and check out our Code of Conduct.












                                        Shabir jan is a new contributor. Be nice, and check out our Code of Conduct.











                                        Shabir jan is a new contributor. Be nice, and check out our Code of Conduct.














                                        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

                                        六本木駅

                                        Integral that is continuous and looks like it converges to a geometric seriesTesting if a geometric series converges by taking limit to infinitySummation of arithmetic-geometric series of higher orderGeometric series with polynomial exponentHow to Recognize a Geometric SeriesShowing an integral equality with series over the integersDiscontinuity of a series of continuous functionsReasons why a Series ConvergesSum of infinite geometric series with two terms in summationUsing geometric series for computing IntegralsLimit of geometric series sum when $r = 1$

                                        Redningsselskapet