How to unwrap an optional into a variable and then use that variable in the next iteration of a while loop?
I have a method below called createNotifications() in which I try to do some fancy stuff when the recurrence of an alarm is daily
. I first call self.createNotificationForToday(), which goes fine, and then start a while loop and call self.createNotificationForTomorrowAndReturnNewDateComponents() in each iteration, each time returning the new date components and using it as the input for the next iteration. This allows me to call one method each time and every time, iterate to "tomorrow" and create a notification for that day. The problem is with this part:
var newDateComponents = dateComponents
while numberOfCreatableNotifications > 0 {
guard var newDateComponents = self.createNotificationForTomorrowAndReturnNewDateComponents(dateComponents: newDateComponents) else {
os_log("Could not unwrap newDateComponents in createNotifications() in Alarm.swift", log: OSLog.default, type: .debug)
return
}
numberOfCreatableNotifications = numberOfCreatableNotifications - 1
}
What I'm attempting to do is reinitialize the newDateComponents
variable each time I go through the while loop and call the createNotificationForTomorrowAnd...() method, and use those newDateComponents as input for the next call to that method. Is there something fundamentally wrong with how I'm trying to do this? Is there a better way?
createNotifications():
private func createNotifications(dateComponents: DateComponents) {
if recurrence == .today {
createNotificationForToday(dateComponents: dateComponents)
} else if recurrence == .tomorrow {
let _ = createNotificationForTomorrowAndReturnNewDateComponents(dateComponents: dateComponents)
} else if recurrence == .daily {
let center = UNUserNotificationCenter.current()
center.getPendingNotificationRequests { (notifications) in
var numberOfCreatableNotifications = 64 - notifications.count
self.createNotificationForToday(dateComponents: dateComponents)
var newDateComponents = dateComponents
while numberOfCreatableNotifications > 0 {
guard var newDateComponents =
self.createNotificationForTomorrowAndReturnNewDateComponents(dateComponents: newDateComponents) else {
os_log("Could not unwrap newDateComponents in createNotifications() in Alarm.swift", log: OSLog.default, type: .debug)
return
}
numberOfCreatableNotifications = numberOfCreatableNotifications - 1
}
}
} else {}
}
createNotificationForToday():
private func createNotificationForToday(dateComponents: DateComponents) {
let center = UNUserNotificationCenter.current()
let content = UNMutableNotificationContent()
content.title = "Random Alarm"
content.subtitle = "It's time!"
content.body = self.note
content.sound = UNNotificationSound.default
let trigger = UNCalendarNotificationTrigger(dateMatching: dateComponents, repeats: false)
let uuidString = UUID().uuidString
let request = UNNotificationRequest(identifier: uuidString, content: content, trigger: trigger)
center.add(request) { (error) in
if error != nil {
print("error (String(describing: error))")
}
}
}
createNotificationForTomorrowAndReturnNewDateComponents():
private func createNotificationForTomorrowAndReturnNewDateComponents(dateComponents: DateComponents) -> DateComponents? {
let center = UNUserNotificationCenter.current()
let content = UNMutableNotificationContent()
content.title = "Random Alarm"
content.subtitle = "It's time!"
content.body = self.note
content.sound = UNNotificationSound.default
let calendar = Calendar.current
guard let date = calendar.date(from: dateComponents) else {
os_log("Could not unwrap date in createNotificationForTomorrow() in Alarm.swift", log: OSLog.default, type: .debug)
return nil
}
guard let tomorrow = calendar.date(byAdding: .day, value: 1, to: date) else {
os_log("Could not unwrap tomorrow in createNotificationForTomorrow() in Alarm.swift", log: OSLog.default, type: .debug)
return nil
}
let newDateComponents = calendar.dateComponents([.year, .month, .day, .timeZone, .hour, .minute], from: tomorrow)
let trigger = UNCalendarNotificationTrigger(dateMatching: newDateComponents, repeats: false)
let uuidString = UUID().uuidString
let request = UNNotificationRequest(identifier: uuidString, content: content, trigger: trigger)
center.add(request) { (error) in
if error != nil {
print("error (String(describing: error))")
}
}
return newDateComponents
}
ios swift
add a comment |
I have a method below called createNotifications() in which I try to do some fancy stuff when the recurrence of an alarm is daily
. I first call self.createNotificationForToday(), which goes fine, and then start a while loop and call self.createNotificationForTomorrowAndReturnNewDateComponents() in each iteration, each time returning the new date components and using it as the input for the next iteration. This allows me to call one method each time and every time, iterate to "tomorrow" and create a notification for that day. The problem is with this part:
var newDateComponents = dateComponents
while numberOfCreatableNotifications > 0 {
guard var newDateComponents = self.createNotificationForTomorrowAndReturnNewDateComponents(dateComponents: newDateComponents) else {
os_log("Could not unwrap newDateComponents in createNotifications() in Alarm.swift", log: OSLog.default, type: .debug)
return
}
numberOfCreatableNotifications = numberOfCreatableNotifications - 1
}
What I'm attempting to do is reinitialize the newDateComponents
variable each time I go through the while loop and call the createNotificationForTomorrowAnd...() method, and use those newDateComponents as input for the next call to that method. Is there something fundamentally wrong with how I'm trying to do this? Is there a better way?
createNotifications():
private func createNotifications(dateComponents: DateComponents) {
if recurrence == .today {
createNotificationForToday(dateComponents: dateComponents)
} else if recurrence == .tomorrow {
let _ = createNotificationForTomorrowAndReturnNewDateComponents(dateComponents: dateComponents)
} else if recurrence == .daily {
let center = UNUserNotificationCenter.current()
center.getPendingNotificationRequests { (notifications) in
var numberOfCreatableNotifications = 64 - notifications.count
self.createNotificationForToday(dateComponents: dateComponents)
var newDateComponents = dateComponents
while numberOfCreatableNotifications > 0 {
guard var newDateComponents =
self.createNotificationForTomorrowAndReturnNewDateComponents(dateComponents: newDateComponents) else {
os_log("Could not unwrap newDateComponents in createNotifications() in Alarm.swift", log: OSLog.default, type: .debug)
return
}
numberOfCreatableNotifications = numberOfCreatableNotifications - 1
}
}
} else {}
}
createNotificationForToday():
private func createNotificationForToday(dateComponents: DateComponents) {
let center = UNUserNotificationCenter.current()
let content = UNMutableNotificationContent()
content.title = "Random Alarm"
content.subtitle = "It's time!"
content.body = self.note
content.sound = UNNotificationSound.default
let trigger = UNCalendarNotificationTrigger(dateMatching: dateComponents, repeats: false)
let uuidString = UUID().uuidString
let request = UNNotificationRequest(identifier: uuidString, content: content, trigger: trigger)
center.add(request) { (error) in
if error != nil {
print("error (String(describing: error))")
}
}
}
createNotificationForTomorrowAndReturnNewDateComponents():
private func createNotificationForTomorrowAndReturnNewDateComponents(dateComponents: DateComponents) -> DateComponents? {
let center = UNUserNotificationCenter.current()
let content = UNMutableNotificationContent()
content.title = "Random Alarm"
content.subtitle = "It's time!"
content.body = self.note
content.sound = UNNotificationSound.default
let calendar = Calendar.current
guard let date = calendar.date(from: dateComponents) else {
os_log("Could not unwrap date in createNotificationForTomorrow() in Alarm.swift", log: OSLog.default, type: .debug)
return nil
}
guard let tomorrow = calendar.date(byAdding: .day, value: 1, to: date) else {
os_log("Could not unwrap tomorrow in createNotificationForTomorrow() in Alarm.swift", log: OSLog.default, type: .debug)
return nil
}
let newDateComponents = calendar.dateComponents([.year, .month, .day, .timeZone, .hour, .minute], from: tomorrow)
let trigger = UNCalendarNotificationTrigger(dateMatching: newDateComponents, repeats: false)
let uuidString = UUID().uuidString
let request = UNNotificationRequest(identifier: uuidString, content: content, trigger: trigger)
center.add(request) { (error) in
if error != nil {
print("error (String(describing: error))")
}
}
return newDateComponents
}
ios swift
add a comment |
I have a method below called createNotifications() in which I try to do some fancy stuff when the recurrence of an alarm is daily
. I first call self.createNotificationForToday(), which goes fine, and then start a while loop and call self.createNotificationForTomorrowAndReturnNewDateComponents() in each iteration, each time returning the new date components and using it as the input for the next iteration. This allows me to call one method each time and every time, iterate to "tomorrow" and create a notification for that day. The problem is with this part:
var newDateComponents = dateComponents
while numberOfCreatableNotifications > 0 {
guard var newDateComponents = self.createNotificationForTomorrowAndReturnNewDateComponents(dateComponents: newDateComponents) else {
os_log("Could not unwrap newDateComponents in createNotifications() in Alarm.swift", log: OSLog.default, type: .debug)
return
}
numberOfCreatableNotifications = numberOfCreatableNotifications - 1
}
What I'm attempting to do is reinitialize the newDateComponents
variable each time I go through the while loop and call the createNotificationForTomorrowAnd...() method, and use those newDateComponents as input for the next call to that method. Is there something fundamentally wrong with how I'm trying to do this? Is there a better way?
createNotifications():
private func createNotifications(dateComponents: DateComponents) {
if recurrence == .today {
createNotificationForToday(dateComponents: dateComponents)
} else if recurrence == .tomorrow {
let _ = createNotificationForTomorrowAndReturnNewDateComponents(dateComponents: dateComponents)
} else if recurrence == .daily {
let center = UNUserNotificationCenter.current()
center.getPendingNotificationRequests { (notifications) in
var numberOfCreatableNotifications = 64 - notifications.count
self.createNotificationForToday(dateComponents: dateComponents)
var newDateComponents = dateComponents
while numberOfCreatableNotifications > 0 {
guard var newDateComponents =
self.createNotificationForTomorrowAndReturnNewDateComponents(dateComponents: newDateComponents) else {
os_log("Could not unwrap newDateComponents in createNotifications() in Alarm.swift", log: OSLog.default, type: .debug)
return
}
numberOfCreatableNotifications = numberOfCreatableNotifications - 1
}
}
} else {}
}
createNotificationForToday():
private func createNotificationForToday(dateComponents: DateComponents) {
let center = UNUserNotificationCenter.current()
let content = UNMutableNotificationContent()
content.title = "Random Alarm"
content.subtitle = "It's time!"
content.body = self.note
content.sound = UNNotificationSound.default
let trigger = UNCalendarNotificationTrigger(dateMatching: dateComponents, repeats: false)
let uuidString = UUID().uuidString
let request = UNNotificationRequest(identifier: uuidString, content: content, trigger: trigger)
center.add(request) { (error) in
if error != nil {
print("error (String(describing: error))")
}
}
}
createNotificationForTomorrowAndReturnNewDateComponents():
private func createNotificationForTomorrowAndReturnNewDateComponents(dateComponents: DateComponents) -> DateComponents? {
let center = UNUserNotificationCenter.current()
let content = UNMutableNotificationContent()
content.title = "Random Alarm"
content.subtitle = "It's time!"
content.body = self.note
content.sound = UNNotificationSound.default
let calendar = Calendar.current
guard let date = calendar.date(from: dateComponents) else {
os_log("Could not unwrap date in createNotificationForTomorrow() in Alarm.swift", log: OSLog.default, type: .debug)
return nil
}
guard let tomorrow = calendar.date(byAdding: .day, value: 1, to: date) else {
os_log("Could not unwrap tomorrow in createNotificationForTomorrow() in Alarm.swift", log: OSLog.default, type: .debug)
return nil
}
let newDateComponents = calendar.dateComponents([.year, .month, .day, .timeZone, .hour, .minute], from: tomorrow)
let trigger = UNCalendarNotificationTrigger(dateMatching: newDateComponents, repeats: false)
let uuidString = UUID().uuidString
let request = UNNotificationRequest(identifier: uuidString, content: content, trigger: trigger)
center.add(request) { (error) in
if error != nil {
print("error (String(describing: error))")
}
}
return newDateComponents
}
ios swift
I have a method below called createNotifications() in which I try to do some fancy stuff when the recurrence of an alarm is daily
. I first call self.createNotificationForToday(), which goes fine, and then start a while loop and call self.createNotificationForTomorrowAndReturnNewDateComponents() in each iteration, each time returning the new date components and using it as the input for the next iteration. This allows me to call one method each time and every time, iterate to "tomorrow" and create a notification for that day. The problem is with this part:
var newDateComponents = dateComponents
while numberOfCreatableNotifications > 0 {
guard var newDateComponents = self.createNotificationForTomorrowAndReturnNewDateComponents(dateComponents: newDateComponents) else {
os_log("Could not unwrap newDateComponents in createNotifications() in Alarm.swift", log: OSLog.default, type: .debug)
return
}
numberOfCreatableNotifications = numberOfCreatableNotifications - 1
}
What I'm attempting to do is reinitialize the newDateComponents
variable each time I go through the while loop and call the createNotificationForTomorrowAnd...() method, and use those newDateComponents as input for the next call to that method. Is there something fundamentally wrong with how I'm trying to do this? Is there a better way?
createNotifications():
private func createNotifications(dateComponents: DateComponents) {
if recurrence == .today {
createNotificationForToday(dateComponents: dateComponents)
} else if recurrence == .tomorrow {
let _ = createNotificationForTomorrowAndReturnNewDateComponents(dateComponents: dateComponents)
} else if recurrence == .daily {
let center = UNUserNotificationCenter.current()
center.getPendingNotificationRequests { (notifications) in
var numberOfCreatableNotifications = 64 - notifications.count
self.createNotificationForToday(dateComponents: dateComponents)
var newDateComponents = dateComponents
while numberOfCreatableNotifications > 0 {
guard var newDateComponents =
self.createNotificationForTomorrowAndReturnNewDateComponents(dateComponents: newDateComponents) else {
os_log("Could not unwrap newDateComponents in createNotifications() in Alarm.swift", log: OSLog.default, type: .debug)
return
}
numberOfCreatableNotifications = numberOfCreatableNotifications - 1
}
}
} else {}
}
createNotificationForToday():
private func createNotificationForToday(dateComponents: DateComponents) {
let center = UNUserNotificationCenter.current()
let content = UNMutableNotificationContent()
content.title = "Random Alarm"
content.subtitle = "It's time!"
content.body = self.note
content.sound = UNNotificationSound.default
let trigger = UNCalendarNotificationTrigger(dateMatching: dateComponents, repeats: false)
let uuidString = UUID().uuidString
let request = UNNotificationRequest(identifier: uuidString, content: content, trigger: trigger)
center.add(request) { (error) in
if error != nil {
print("error (String(describing: error))")
}
}
}
createNotificationForTomorrowAndReturnNewDateComponents():
private func createNotificationForTomorrowAndReturnNewDateComponents(dateComponents: DateComponents) -> DateComponents? {
let center = UNUserNotificationCenter.current()
let content = UNMutableNotificationContent()
content.title = "Random Alarm"
content.subtitle = "It's time!"
content.body = self.note
content.sound = UNNotificationSound.default
let calendar = Calendar.current
guard let date = calendar.date(from: dateComponents) else {
os_log("Could not unwrap date in createNotificationForTomorrow() in Alarm.swift", log: OSLog.default, type: .debug)
return nil
}
guard let tomorrow = calendar.date(byAdding: .day, value: 1, to: date) else {
os_log("Could not unwrap tomorrow in createNotificationForTomorrow() in Alarm.swift", log: OSLog.default, type: .debug)
return nil
}
let newDateComponents = calendar.dateComponents([.year, .month, .day, .timeZone, .hour, .minute], from: tomorrow)
let trigger = UNCalendarNotificationTrigger(dateMatching: newDateComponents, repeats: false)
let uuidString = UUID().uuidString
let request = UNNotificationRequest(identifier: uuidString, content: content, trigger: trigger)
center.add(request) { (error) in
if error != nil {
print("error (String(describing: error))")
}
}
return newDateComponents
}
ios swift
ios swift
asked Nov 26 '18 at 6:15
Tyler CheekTyler Cheek
639
639
add a comment |
add a comment |
2 Answers
2
active
oldest
votes
The scope of a variable created by a guard
statement is the block that contains the guard
statement, which is the body of your while
loop.
This means that the newDateComponents
you are creating with your guard
statement is not the same as the newDateComponents
you created outside the while
and the inner newDateComponents
will be discarded after each iteration of the while
loop.
You don't actually need the guard
statement; you can build the unwrap into your while
:
var newDateComponents: DateComponents? = dateComponents
while numberOfCreatableNotifications > 0, let currentDateComponents = newDateComponents {
newDateComponents = self.createNotificationForTomorrowAndReturnNewDateComponents(dateComponents: currentDateComponents)
numberOfCreatableNotifications -= 1
}
if numberOfCreateableNotifications > 0 {
os_log("Could not create all notifications
}
You can probably refactor this to be a bit more efficient and have one less function:
- Use a
Calendar
property so that you don't need to keep instantiating the calendar - Have a function to return "tomorrow"
- Have a function to schedule a notification
let calendar = Calendar.autoUpdatingCurrent
private func createNotifications(dateComponents: DateComponents) {
switch (recurrence) {
case .today:
createNotification(for: dateComponents)
case .tomorrow:
createNotification(for: day(after: dateComponents))
case .daily:
let center = UNUserNotificationCenter.current()
center.getPendingNotificationRequests { (notifications) in
var numberOfCreatableNotifications = 64 - notifications.count
var currentDay: DateComponents? = dateComponents
while numberOfCreatableNotifications > 0, current = currentDay {
createNotification(for: current)
currentDay = day(after: current)
numberOfCreateableNotification -= 1
}
if numberOfCreateableNotifications > 0 {
os_log("Could not create all notifications", type: .debug)
}
}
}
}
private func createNotification(for dateComponents: DateComponents) {
let center = UNUserNotificationCenter.current()
let content = UNMutableNotificationContent()
content.title = "Random Alarm"
content.subtitle = "It's time!"
content.body = self.note
content.sound = UNNotificationSound.default
let trigger = UNCalendarNotificationTrigger(dateMatching: dateComponents, repeats: false)
let uuidString = UUID().uuidString
let request = UNNotificationRequest(identifier: uuidString, content: content, trigger: trigger)
center.add(request) { (error) in
if let err = error {
print("error (err.localizedDescription)")
}
}
}
private func day(after dateComponents: DateComponents) -> DateComponents? {
guard let date = calendar.date(from: dateComponents),
let tomorrow = calendar.date(byAdding: .day, value: 1, to: date)
else {
os_log("Could not calculate tomorrow in Alarm.swift", log: OSLog.default, type: .debug)
return nil
}
let newDateComponents = calendar.dateComponents([.year, .month, .day, .timeZone, .hour, .minute], from: tomorrow)
return newDateComponents
}
One final note, it would probably be nicer to pass Date
instances rather than DateComponent
instances and convert to DateComponent
once when you need to actually schedule the notification.
Thanks! This is exactly what I needed to see. The only problems: 1. GettingValue of optional type 'DateComponents?' must be unwrapped to a value of type 'DateComponents'
error on linecreateNotification(for: day(after: dateComponents))
. How best to fix that? 2.current
isn't defined anywhere. Can I just initialize that anywhere above the while loop? 3.while numberOfCreatableNotifications > 0, current = currentDay
doesn't seem to be playing nicely with the compiler. Should it becurrent == currentDay
? 4. How do I unwrapcurrent
forcreateNotification(for: current)
– Tyler Cheek
Nov 27 '18 at 1:52
add a comment |
You cannot directly bind to the variable newDateComponents
from the
outer scope in the guard-statement. You can bind to a new variable and
then assign that to newDateComponents
:
var newDateComponents = dateComponents
while numberOfCreatableNotifications > 0 {
guard let nextDateComponents =
self.createNotificationForTomorrowAndReturnNewDateComponents(dateComponents: newDateComponents) else {
os_log("Could not unwrap newDateComponents in createNotifications() in Alarm.swift", log: OSLog.default, type: .debug)
return
}
newDateComponents = nextDateComponents
numberOfCreatableNotifications = numberOfCreatableNotifications - 1
}
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: "1"
};
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: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
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%2fstackoverflow.com%2fquestions%2f53475632%2fhow-to-unwrap-an-optional-into-a-variable-and-then-use-that-variable-in-the-next%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
2 Answers
2
active
oldest
votes
2 Answers
2
active
oldest
votes
active
oldest
votes
active
oldest
votes
The scope of a variable created by a guard
statement is the block that contains the guard
statement, which is the body of your while
loop.
This means that the newDateComponents
you are creating with your guard
statement is not the same as the newDateComponents
you created outside the while
and the inner newDateComponents
will be discarded after each iteration of the while
loop.
You don't actually need the guard
statement; you can build the unwrap into your while
:
var newDateComponents: DateComponents? = dateComponents
while numberOfCreatableNotifications > 0, let currentDateComponents = newDateComponents {
newDateComponents = self.createNotificationForTomorrowAndReturnNewDateComponents(dateComponents: currentDateComponents)
numberOfCreatableNotifications -= 1
}
if numberOfCreateableNotifications > 0 {
os_log("Could not create all notifications
}
You can probably refactor this to be a bit more efficient and have one less function:
- Use a
Calendar
property so that you don't need to keep instantiating the calendar - Have a function to return "tomorrow"
- Have a function to schedule a notification
let calendar = Calendar.autoUpdatingCurrent
private func createNotifications(dateComponents: DateComponents) {
switch (recurrence) {
case .today:
createNotification(for: dateComponents)
case .tomorrow:
createNotification(for: day(after: dateComponents))
case .daily:
let center = UNUserNotificationCenter.current()
center.getPendingNotificationRequests { (notifications) in
var numberOfCreatableNotifications = 64 - notifications.count
var currentDay: DateComponents? = dateComponents
while numberOfCreatableNotifications > 0, current = currentDay {
createNotification(for: current)
currentDay = day(after: current)
numberOfCreateableNotification -= 1
}
if numberOfCreateableNotifications > 0 {
os_log("Could not create all notifications", type: .debug)
}
}
}
}
private func createNotification(for dateComponents: DateComponents) {
let center = UNUserNotificationCenter.current()
let content = UNMutableNotificationContent()
content.title = "Random Alarm"
content.subtitle = "It's time!"
content.body = self.note
content.sound = UNNotificationSound.default
let trigger = UNCalendarNotificationTrigger(dateMatching: dateComponents, repeats: false)
let uuidString = UUID().uuidString
let request = UNNotificationRequest(identifier: uuidString, content: content, trigger: trigger)
center.add(request) { (error) in
if let err = error {
print("error (err.localizedDescription)")
}
}
}
private func day(after dateComponents: DateComponents) -> DateComponents? {
guard let date = calendar.date(from: dateComponents),
let tomorrow = calendar.date(byAdding: .day, value: 1, to: date)
else {
os_log("Could not calculate tomorrow in Alarm.swift", log: OSLog.default, type: .debug)
return nil
}
let newDateComponents = calendar.dateComponents([.year, .month, .day, .timeZone, .hour, .minute], from: tomorrow)
return newDateComponents
}
One final note, it would probably be nicer to pass Date
instances rather than DateComponent
instances and convert to DateComponent
once when you need to actually schedule the notification.
Thanks! This is exactly what I needed to see. The only problems: 1. GettingValue of optional type 'DateComponents?' must be unwrapped to a value of type 'DateComponents'
error on linecreateNotification(for: day(after: dateComponents))
. How best to fix that? 2.current
isn't defined anywhere. Can I just initialize that anywhere above the while loop? 3.while numberOfCreatableNotifications > 0, current = currentDay
doesn't seem to be playing nicely with the compiler. Should it becurrent == currentDay
? 4. How do I unwrapcurrent
forcreateNotification(for: current)
– Tyler Cheek
Nov 27 '18 at 1:52
add a comment |
The scope of a variable created by a guard
statement is the block that contains the guard
statement, which is the body of your while
loop.
This means that the newDateComponents
you are creating with your guard
statement is not the same as the newDateComponents
you created outside the while
and the inner newDateComponents
will be discarded after each iteration of the while
loop.
You don't actually need the guard
statement; you can build the unwrap into your while
:
var newDateComponents: DateComponents? = dateComponents
while numberOfCreatableNotifications > 0, let currentDateComponents = newDateComponents {
newDateComponents = self.createNotificationForTomorrowAndReturnNewDateComponents(dateComponents: currentDateComponents)
numberOfCreatableNotifications -= 1
}
if numberOfCreateableNotifications > 0 {
os_log("Could not create all notifications
}
You can probably refactor this to be a bit more efficient and have one less function:
- Use a
Calendar
property so that you don't need to keep instantiating the calendar - Have a function to return "tomorrow"
- Have a function to schedule a notification
let calendar = Calendar.autoUpdatingCurrent
private func createNotifications(dateComponents: DateComponents) {
switch (recurrence) {
case .today:
createNotification(for: dateComponents)
case .tomorrow:
createNotification(for: day(after: dateComponents))
case .daily:
let center = UNUserNotificationCenter.current()
center.getPendingNotificationRequests { (notifications) in
var numberOfCreatableNotifications = 64 - notifications.count
var currentDay: DateComponents? = dateComponents
while numberOfCreatableNotifications > 0, current = currentDay {
createNotification(for: current)
currentDay = day(after: current)
numberOfCreateableNotification -= 1
}
if numberOfCreateableNotifications > 0 {
os_log("Could not create all notifications", type: .debug)
}
}
}
}
private func createNotification(for dateComponents: DateComponents) {
let center = UNUserNotificationCenter.current()
let content = UNMutableNotificationContent()
content.title = "Random Alarm"
content.subtitle = "It's time!"
content.body = self.note
content.sound = UNNotificationSound.default
let trigger = UNCalendarNotificationTrigger(dateMatching: dateComponents, repeats: false)
let uuidString = UUID().uuidString
let request = UNNotificationRequest(identifier: uuidString, content: content, trigger: trigger)
center.add(request) { (error) in
if let err = error {
print("error (err.localizedDescription)")
}
}
}
private func day(after dateComponents: DateComponents) -> DateComponents? {
guard let date = calendar.date(from: dateComponents),
let tomorrow = calendar.date(byAdding: .day, value: 1, to: date)
else {
os_log("Could not calculate tomorrow in Alarm.swift", log: OSLog.default, type: .debug)
return nil
}
let newDateComponents = calendar.dateComponents([.year, .month, .day, .timeZone, .hour, .minute], from: tomorrow)
return newDateComponents
}
One final note, it would probably be nicer to pass Date
instances rather than DateComponent
instances and convert to DateComponent
once when you need to actually schedule the notification.
Thanks! This is exactly what I needed to see. The only problems: 1. GettingValue of optional type 'DateComponents?' must be unwrapped to a value of type 'DateComponents'
error on linecreateNotification(for: day(after: dateComponents))
. How best to fix that? 2.current
isn't defined anywhere. Can I just initialize that anywhere above the while loop? 3.while numberOfCreatableNotifications > 0, current = currentDay
doesn't seem to be playing nicely with the compiler. Should it becurrent == currentDay
? 4. How do I unwrapcurrent
forcreateNotification(for: current)
– Tyler Cheek
Nov 27 '18 at 1:52
add a comment |
The scope of a variable created by a guard
statement is the block that contains the guard
statement, which is the body of your while
loop.
This means that the newDateComponents
you are creating with your guard
statement is not the same as the newDateComponents
you created outside the while
and the inner newDateComponents
will be discarded after each iteration of the while
loop.
You don't actually need the guard
statement; you can build the unwrap into your while
:
var newDateComponents: DateComponents? = dateComponents
while numberOfCreatableNotifications > 0, let currentDateComponents = newDateComponents {
newDateComponents = self.createNotificationForTomorrowAndReturnNewDateComponents(dateComponents: currentDateComponents)
numberOfCreatableNotifications -= 1
}
if numberOfCreateableNotifications > 0 {
os_log("Could not create all notifications
}
You can probably refactor this to be a bit more efficient and have one less function:
- Use a
Calendar
property so that you don't need to keep instantiating the calendar - Have a function to return "tomorrow"
- Have a function to schedule a notification
let calendar = Calendar.autoUpdatingCurrent
private func createNotifications(dateComponents: DateComponents) {
switch (recurrence) {
case .today:
createNotification(for: dateComponents)
case .tomorrow:
createNotification(for: day(after: dateComponents))
case .daily:
let center = UNUserNotificationCenter.current()
center.getPendingNotificationRequests { (notifications) in
var numberOfCreatableNotifications = 64 - notifications.count
var currentDay: DateComponents? = dateComponents
while numberOfCreatableNotifications > 0, current = currentDay {
createNotification(for: current)
currentDay = day(after: current)
numberOfCreateableNotification -= 1
}
if numberOfCreateableNotifications > 0 {
os_log("Could not create all notifications", type: .debug)
}
}
}
}
private func createNotification(for dateComponents: DateComponents) {
let center = UNUserNotificationCenter.current()
let content = UNMutableNotificationContent()
content.title = "Random Alarm"
content.subtitle = "It's time!"
content.body = self.note
content.sound = UNNotificationSound.default
let trigger = UNCalendarNotificationTrigger(dateMatching: dateComponents, repeats: false)
let uuidString = UUID().uuidString
let request = UNNotificationRequest(identifier: uuidString, content: content, trigger: trigger)
center.add(request) { (error) in
if let err = error {
print("error (err.localizedDescription)")
}
}
}
private func day(after dateComponents: DateComponents) -> DateComponents? {
guard let date = calendar.date(from: dateComponents),
let tomorrow = calendar.date(byAdding: .day, value: 1, to: date)
else {
os_log("Could not calculate tomorrow in Alarm.swift", log: OSLog.default, type: .debug)
return nil
}
let newDateComponents = calendar.dateComponents([.year, .month, .day, .timeZone, .hour, .minute], from: tomorrow)
return newDateComponents
}
One final note, it would probably be nicer to pass Date
instances rather than DateComponent
instances and convert to DateComponent
once when you need to actually schedule the notification.
The scope of a variable created by a guard
statement is the block that contains the guard
statement, which is the body of your while
loop.
This means that the newDateComponents
you are creating with your guard
statement is not the same as the newDateComponents
you created outside the while
and the inner newDateComponents
will be discarded after each iteration of the while
loop.
You don't actually need the guard
statement; you can build the unwrap into your while
:
var newDateComponents: DateComponents? = dateComponents
while numberOfCreatableNotifications > 0, let currentDateComponents = newDateComponents {
newDateComponents = self.createNotificationForTomorrowAndReturnNewDateComponents(dateComponents: currentDateComponents)
numberOfCreatableNotifications -= 1
}
if numberOfCreateableNotifications > 0 {
os_log("Could not create all notifications
}
You can probably refactor this to be a bit more efficient and have one less function:
- Use a
Calendar
property so that you don't need to keep instantiating the calendar - Have a function to return "tomorrow"
- Have a function to schedule a notification
let calendar = Calendar.autoUpdatingCurrent
private func createNotifications(dateComponents: DateComponents) {
switch (recurrence) {
case .today:
createNotification(for: dateComponents)
case .tomorrow:
createNotification(for: day(after: dateComponents))
case .daily:
let center = UNUserNotificationCenter.current()
center.getPendingNotificationRequests { (notifications) in
var numberOfCreatableNotifications = 64 - notifications.count
var currentDay: DateComponents? = dateComponents
while numberOfCreatableNotifications > 0, current = currentDay {
createNotification(for: current)
currentDay = day(after: current)
numberOfCreateableNotification -= 1
}
if numberOfCreateableNotifications > 0 {
os_log("Could not create all notifications", type: .debug)
}
}
}
}
private func createNotification(for dateComponents: DateComponents) {
let center = UNUserNotificationCenter.current()
let content = UNMutableNotificationContent()
content.title = "Random Alarm"
content.subtitle = "It's time!"
content.body = self.note
content.sound = UNNotificationSound.default
let trigger = UNCalendarNotificationTrigger(dateMatching: dateComponents, repeats: false)
let uuidString = UUID().uuidString
let request = UNNotificationRequest(identifier: uuidString, content: content, trigger: trigger)
center.add(request) { (error) in
if let err = error {
print("error (err.localizedDescription)")
}
}
}
private func day(after dateComponents: DateComponents) -> DateComponents? {
guard let date = calendar.date(from: dateComponents),
let tomorrow = calendar.date(byAdding: .day, value: 1, to: date)
else {
os_log("Could not calculate tomorrow in Alarm.swift", log: OSLog.default, type: .debug)
return nil
}
let newDateComponents = calendar.dateComponents([.year, .month, .day, .timeZone, .hour, .minute], from: tomorrow)
return newDateComponents
}
One final note, it would probably be nicer to pass Date
instances rather than DateComponent
instances and convert to DateComponent
once when you need to actually schedule the notification.
edited Nov 26 '18 at 6:56
answered Nov 26 '18 at 6:38
Paulw11Paulw11
70.2k1088104
70.2k1088104
Thanks! This is exactly what I needed to see. The only problems: 1. GettingValue of optional type 'DateComponents?' must be unwrapped to a value of type 'DateComponents'
error on linecreateNotification(for: day(after: dateComponents))
. How best to fix that? 2.current
isn't defined anywhere. Can I just initialize that anywhere above the while loop? 3.while numberOfCreatableNotifications > 0, current = currentDay
doesn't seem to be playing nicely with the compiler. Should it becurrent == currentDay
? 4. How do I unwrapcurrent
forcreateNotification(for: current)
– Tyler Cheek
Nov 27 '18 at 1:52
add a comment |
Thanks! This is exactly what I needed to see. The only problems: 1. GettingValue of optional type 'DateComponents?' must be unwrapped to a value of type 'DateComponents'
error on linecreateNotification(for: day(after: dateComponents))
. How best to fix that? 2.current
isn't defined anywhere. Can I just initialize that anywhere above the while loop? 3.while numberOfCreatableNotifications > 0, current = currentDay
doesn't seem to be playing nicely with the compiler. Should it becurrent == currentDay
? 4. How do I unwrapcurrent
forcreateNotification(for: current)
– Tyler Cheek
Nov 27 '18 at 1:52
Thanks! This is exactly what I needed to see. The only problems: 1. Getting
Value of optional type 'DateComponents?' must be unwrapped to a value of type 'DateComponents'
error on line createNotification(for: day(after: dateComponents))
. How best to fix that? 2. current
isn't defined anywhere. Can I just initialize that anywhere above the while loop? 3. while numberOfCreatableNotifications > 0, current = currentDay
doesn't seem to be playing nicely with the compiler. Should it be current == currentDay
? 4. How do I unwrap current
for createNotification(for: current)
– Tyler Cheek
Nov 27 '18 at 1:52
Thanks! This is exactly what I needed to see. The only problems: 1. Getting
Value of optional type 'DateComponents?' must be unwrapped to a value of type 'DateComponents'
error on line createNotification(for: day(after: dateComponents))
. How best to fix that? 2. current
isn't defined anywhere. Can I just initialize that anywhere above the while loop? 3. while numberOfCreatableNotifications > 0, current = currentDay
doesn't seem to be playing nicely with the compiler. Should it be current == currentDay
? 4. How do I unwrap current
for createNotification(for: current)
– Tyler Cheek
Nov 27 '18 at 1:52
add a comment |
You cannot directly bind to the variable newDateComponents
from the
outer scope in the guard-statement. You can bind to a new variable and
then assign that to newDateComponents
:
var newDateComponents = dateComponents
while numberOfCreatableNotifications > 0 {
guard let nextDateComponents =
self.createNotificationForTomorrowAndReturnNewDateComponents(dateComponents: newDateComponents) else {
os_log("Could not unwrap newDateComponents in createNotifications() in Alarm.swift", log: OSLog.default, type: .debug)
return
}
newDateComponents = nextDateComponents
numberOfCreatableNotifications = numberOfCreatableNotifications - 1
}
add a comment |
You cannot directly bind to the variable newDateComponents
from the
outer scope in the guard-statement. You can bind to a new variable and
then assign that to newDateComponents
:
var newDateComponents = dateComponents
while numberOfCreatableNotifications > 0 {
guard let nextDateComponents =
self.createNotificationForTomorrowAndReturnNewDateComponents(dateComponents: newDateComponents) else {
os_log("Could not unwrap newDateComponents in createNotifications() in Alarm.swift", log: OSLog.default, type: .debug)
return
}
newDateComponents = nextDateComponents
numberOfCreatableNotifications = numberOfCreatableNotifications - 1
}
add a comment |
You cannot directly bind to the variable newDateComponents
from the
outer scope in the guard-statement. You can bind to a new variable and
then assign that to newDateComponents
:
var newDateComponents = dateComponents
while numberOfCreatableNotifications > 0 {
guard let nextDateComponents =
self.createNotificationForTomorrowAndReturnNewDateComponents(dateComponents: newDateComponents) else {
os_log("Could not unwrap newDateComponents in createNotifications() in Alarm.swift", log: OSLog.default, type: .debug)
return
}
newDateComponents = nextDateComponents
numberOfCreatableNotifications = numberOfCreatableNotifications - 1
}
You cannot directly bind to the variable newDateComponents
from the
outer scope in the guard-statement. You can bind to a new variable and
then assign that to newDateComponents
:
var newDateComponents = dateComponents
while numberOfCreatableNotifications > 0 {
guard let nextDateComponents =
self.createNotificationForTomorrowAndReturnNewDateComponents(dateComponents: newDateComponents) else {
os_log("Could not unwrap newDateComponents in createNotifications() in Alarm.swift", log: OSLog.default, type: .debug)
return
}
newDateComponents = nextDateComponents
numberOfCreatableNotifications = numberOfCreatableNotifications - 1
}
answered Nov 26 '18 at 6:32
Martin RMartin R
403k56894994
403k56894994
add a comment |
add a comment |
Thanks for contributing an answer to Stack Overflow!
- 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.
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%2fstackoverflow.com%2fquestions%2f53475632%2fhow-to-unwrap-an-optional-into-a-variable-and-then-use-that-variable-in-the-next%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