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;
$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.
swift ios
$endgroup$
add a comment |
$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.
swift ios
$endgroup$
add a comment |
$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.
swift ios
$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
swift ios
edited Apr 26 at 14:30
Stephen Rauch
3,77061630
3,77061630
asked Apr 26 at 9:36
Shabir janShabir jan
1364
1364
add a comment |
add a comment |
3 Answers
3
active
oldest
votes
$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)
$endgroup$
add a comment |
$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
tabbarin bothshowGreetingScreenandpresentWelcomeScreendoesn't seem necessary, you could use a wild card external name_to avoid being too verbose:private func showGreetingScreen (_ tabbar: UITabBarController)
...
presentWelcomeScreen(tabbar)tabbarisn't used in this function. It is only passed topresentWelcomeScreen, 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
UserDefaultsitself :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)
$endgroup$
add a comment |
$begingroup$
just some other refactoring hints:
- encapsulate the check in a own
UserUsageControllerclass - 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()
$endgroup$
add a comment |
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
);
);
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
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
$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)
$endgroup$
add a comment |
$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)
$endgroup$
add a comment |
$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)
$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)
answered Apr 26 at 13:29
Martin RMartin R
16.4k12366
16.4k12366
add a comment |
add a comment |
$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
tabbarin bothshowGreetingScreenandpresentWelcomeScreendoesn't seem necessary, you could use a wild card external name_to avoid being too verbose:private func showGreetingScreen (_ tabbar: UITabBarController)
...
presentWelcomeScreen(tabbar)tabbarisn't used in this function. It is only passed topresentWelcomeScreen, 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
UserDefaultsitself :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)
$endgroup$
add a comment |
$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
tabbarin bothshowGreetingScreenandpresentWelcomeScreendoesn't seem necessary, you could use a wild card external name_to avoid being too verbose:private func showGreetingScreen (_ tabbar: UITabBarController)
...
presentWelcomeScreen(tabbar)tabbarisn't used in this function. It is only passed topresentWelcomeScreen, 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
UserDefaultsitself :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)
$endgroup$
add a comment |
$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
tabbarin bothshowGreetingScreenandpresentWelcomeScreendoesn't seem necessary, you could use a wild card external name_to avoid being too verbose:private func showGreetingScreen (_ tabbar: UITabBarController)
...
presentWelcomeScreen(tabbar)tabbarisn't used in this function. It is only passed topresentWelcomeScreen, 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
UserDefaultsitself :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)
$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
tabbarin bothshowGreetingScreenandpresentWelcomeScreendoesn't seem necessary, you could use a wild card external name_to avoid being too verbose:private func showGreetingScreen (_ tabbar: UITabBarController)
...
presentWelcomeScreen(tabbar)tabbarisn't used in this function. It is only passed topresentWelcomeScreen, 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
UserDefaultsitself :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)
edited Apr 26 at 10:45
answered Apr 26 at 10:28
ielyamaniielyamani
444315
444315
add a comment |
add a comment |
$begingroup$
just some other refactoring hints:
- encapsulate the check in a own
UserUsageControllerclass - 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()
$endgroup$
add a comment |
$begingroup$
just some other refactoring hints:
- encapsulate the check in a own
UserUsageControllerclass - 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()
$endgroup$
add a comment |
$begingroup$
just some other refactoring hints:
- encapsulate the check in a own
UserUsageControllerclass - 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()
$endgroup$
just some other refactoring hints:
- encapsulate the check in a own
UserUsageControllerclass - 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()
answered Apr 26 at 17:12
mueschamuescha
1965
1965
add a comment |
add a comment |
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.
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
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
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
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