I need to remove an event with certain/specific title, I hope that I can delete/remove the event based on the eventID/Identifier. but I don't know how to do that in code. I don't know how to give identifier to the event and remove it based on their identifier/title.
here is the code I use to save the event:
let eventStore = EKEventStore()
let newEvent = EKEvent(eventStore: eventStore)
newEvent.calendar = eventStore.defaultCalendarForNewEvents
newEvent.title = self.eventNameTextField.text ?? "Some Event Name"
newEvent.startDate = timeDatePicker.date
newEvent.endDate = endTimeDatePicker.date
newEvent.notes = "Ini adalah catatan"
newEvent.location = "Jalan Sunda kelapa no.60"
let eventAlarm = EKAlarm(relativeOffset: -60 * 10) // 10 minutes before the start date
newEvent.alarms = [eventAlarm]
do {
try eventStore.save(newEvent, span: .thisEvent)
print("Event has been saved")
} catch {
let alert = UIAlertController(title: "Event could not be saved", message: (error as NSError).localizedDescription, preferredStyle: .alert)
let OKAction = UIAlertAction(title: "OK", style: .default, handler: nil)
alert.addAction(OKAction)
self.present(alert, animated: true, completion: nil)
}
I know that I can use evenStore.remove() , but that method needs EKEvent instance. I don't understand how to remove a specific event if using that method, it will be easier if I can remove the event based on their identifier
Actually an EKEvent instance has a get-only attribute called eventIdentifier. You can't modify this identifier, but you can get it after you save the event. So:
do {
try eventStore.save(newEvent, span: .thisEvent)
let id = newEvent.eventIdentifier ?? "NO ID"
//Save your ID in your database or anywhere else so you can retrieve the event later
print("Event has been saved with id \(id)")
} catch {
let alert = UIAlertController(title: "Event could not be saved", message: (error as NSError).localizedDescription, preferredStyle: .alert)
let OKAction = UIAlertAction(title: "OK", style: .default, handler: nil)
alert.addAction(OKAction)
self.present(alert, animated: true, completion: nil)
}
Then you can get the event using its identifier
let event = eventStore.event(withIdentifier: id)
and then pass this EKEvent to eventStore.remove()
Related
I using a native UIAlertController action in my app to allow a user to report an individual post, and I'm using Firebase to create a data structure for these reports. However, for whatever reason, the cloud function is not being executed, and I'm wondering whether this is due to some race condition that's related to using the UIAlertController. I'm able to execute a print statement inside the handler, so there's nothing wrong with the alert action per se.
Below is my code.
let alertController = UIAlertController(title: nil, message: nil, preferredStyle: .actionSheet)
// Report Post
alertController.addAction(UIAlertAction(title: "Report", style: .default, handler: { (_) in
print("you've pressed report")
guard let postId = self.post?.postId else { return }
guard let uid = Auth.auth().currentUser?.uid else { return }
let creationDate = Int(NSDate().timeIntervalSince1970)
let values = ["creationDate": creationDate,
"uid": uid] as [String : Any]
REPORT_REF.child(postId).childByAutoId().updateChildValues(values)
}))
alertController.addAction(UIAlertAction(title: "Cancel", style: .cancel, handler: nil))
present(alertController, animated: true, completion: nil)
I am trying to check if event already exists in calendar and show alert that it exists. This is my code below
Edited: It keeps adding Duplicate Events.
let event = EKEvent(eventStore: eventStore)
var savedEventId : String = ""
event.title = title
event.startDate = (self.dataEvent?.dates?.begin)!
event.endDate = (self.dataEvent?.dates?.end)!
event.calendar = eventStore.defaultCalendarForNewEvents
let predicate = eventStore.predicateForEventsWithStartDate(startDate, endDate: endDate, calendars: nil)
let existingEvents = eventStore.eventsMatchingPredicate(predicate)
for singleEvent in existingEvents {
if singleEvent.title == self.dataEvent?.titleString && singleEvent.startDate == startDate && singleEvent.endDate == endDate {
let alert = UIAlertController(title: "Event Already Exists", message: "Event Already Exists in Calendar", preferredStyle: UIAlertControllerStyle.Alert)
alert.addAction(UIAlertAction(title: "Close", style: UIAlertActionStyle.Default, handler: nil))
self.presentViewController(alert, animated: true, completion: nil)
}
}
do {
try eventStore.saveEvent(event, span: .ThisEvent)
savedEventId = event.eventIdentifier
print("Event Added")
let alert = UIAlertController(title: "Event Successfully Added", message: "Event Added to Calendar", preferredStyle: UIAlertControllerStyle.Alert)
alert.addAction(UIAlertAction(title: "Close", style: UIAlertActionStyle.Default, handler: nil))
self.presentViewController(alert, animated: true, completion: nil)
} catch {
print("Error occurred")
}
The problem is that your do-catch block in which you add the event gets called all the time even if the event exists. You need to create a boolean to track whether the same event was found or not and only execute the do-catch block if it wasn't found.
Instead of using a for loop, you can use Array.contains(where:), which allows for an early exit if such an event was found.
var eventAlreadyExists = false
let event = EKEvent(eventStore: eventStore)
var savedEventId : String = ""
event.title = title
event.startDate = (self.dataEvent?.dates?.begin)!
event.endDate = (self.dataEvent?.dates?.end)!
event.calendar = eventStore.defaultCalendarForNewEvents
let predicate = eventStore.predicateForEventsWithStartDate(startDate, endDate: endDate, calendars: nil)
let existingEvents = eventStore.eventsMatchingPredicate(predicate)
let eventAlreadyExists = existingEvents.contains(where: {event in self.dataEvent?.titleString == event.title && event.startDate == startDate && event.endDate = endDate})
// Matching event found, don't add it again, just display alert
if eventAlreadyExists {
let alert = UIAlertController(title: "Event Already Exists", message: "Event Already Exists in Calendar", preferredStyle: UIAlertControllerStyle.Alert)
alert.addAction(UIAlertAction(title: "Close", style: UIAlertActionStyle.Default, handler: nil))
self.presentViewController(alert, animated: true, completion: nil)
} else {
// Event doesn't exist yet, add it to calendar
do {
try eventStore.saveEvent(event, span: .ThisEvent)
savedEventId = event.eventIdentifier
print("Event Added")
let alert = UIAlertController(title: "Event Successfully Added", message: "Event Added to Calendar", preferredStyle: UIAlertControllerStyle.Alert)
alert.addAction(UIAlertAction(title: "Close", style: UIAlertActionStyle.Default, handler: nil))
self.presentViewController(alert, animated: true, completion: nil)
} catch {
print("Error occurred")
}
}
Note: If your endDate and startDate are equal - then use in predicate range of time, eg endDate + 1, startDate +1 in eventStore.predicateForEventsWithStartDate. Overwise your existingEvents will always empty
I added a line of code so that name text-field is mandatory when registering an account with firebase but when I did that the UIAlert broke. It stopped showing up when I added that line of code. The code I added is highlighted with a >. What is the best way to fix the problem? Either recode the mandatory name text-field or recode the UIAlert. Which is the simplest way?
#IBAction func registerTapped(_ sender: Any) {
let namec = nameTextField.text
if let email = emailTextField.text, let pass = passwordTextField.text, let name = (namec?.capitalized.isEmpty)! ? nil:namec?.capitalized {
FIRAuth.auth()?.createUser(withEmail: email, password: pass, completion: { (user, error) in
if user != nil {
//user found
let interval = NSDate().timeIntervalSince1970
let date = Date(timeIntervalSince1970: interval)
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "dd/MM/yyyy/HH/mm/SS"
// you can change the date format to whatever you wants
let dateString = dateFormatter.string(from: date)
print(dateString)
self.refD?.child("Users").child((user?.uid)!).setValue(["Email": email, "Name": name, "User Created": dateString])
print("User Created And Added To Database", email, name, dateString)
self.performSegue(withIdentifier: "registertologin", sender: self)
}
else {
print(error!)
let alert = UIAlertController(title: "Error Creating Account ", message: "\(error!.localizedDescription)", preferredStyle: UIAlertControllerStyle.alert)
alert.addAction(UIAlertAction(title: "Dismiss", style: UIAlertActionStyle.default, handler: nil))
self.present(alert, animated: true, completion: nil)
}
})
}
}
}
i think you have to add alert code in the main queue block because your code is inside a completion handler block
DispatchQueue.main.async {
print(error!)
let alert = UIAlertController(title: "Error Creating Account ", message: "\(error!.localizedDescription)", preferredStyle: UIAlertControllerStyle.alert)
alert.addAction(UIAlertAction(title: "Dismiss", style: UIAlertActionStyle.default, handler: nil))
self.present(alert, animated: true, completion: nil)
}
Try this!
I wonder if its possible to show error messages in a UIAlertController.
My server sends error messages back as JSON.
I can get each error message using:
if let errorVal = errorVal {
if let items = errorVal["errors"].array {
for item in items {
print(item)
}
}
}
Now I wonder how I can show the errors in a AlertController.
The AlertController's message parameter expect a string but my errors come as JSON then cast to .array
let alertController = UIAlertController(title: "Hey! :)", message: "My Errors", preferredStyle: .Alert)
let defaultAction = UIAlertAction(title: "OK", style: .Default, handler: nil)
alertController.addAction(defaultAction)
self.presentViewController(alertController, animated: true, completion: nil)
Well, you could build up a string with description of each error ( or just message ) and show that ( may be too much to show ). It would go like this:
var errorMessages = ""
if let errorVal = errorVal {
if let items = errorVal["errors"].array {
for item in items {
print(item)
errorMessages = errorMessages + item + "\n" // if this is NSError you can use description, message or code
}
}
}
and later on you can do something like:
let alertController = UIAlertController(title: "Hey! :)", message: errorMessages , preferredStyle: .Alert)
let defaultAction = UIAlertAction(title: "OK", style: .Default, handler: nil)
alertController.addAction(defaultAction)
self.presentViewController(alertController, animated: true, completion: nil)
I have no idea how to change screens programatically. I have an alert view and I want to be able to change screen when the user presses the "Ok" button. How do I do this?
Here is my new code:
func showAlertController(){
let tilte = "My Medication"
let message = NSLocalizedString("Go through Medication guide?", comment: "")
let cancelButtonTitle = NSLocalizedString("Dismiss", comment: "")
let otherButtonTitle = NSLocalizedString("Ok", comment: "")
let alertController = UIAlertController(title: title, message: message, preferredStyle: .Alert)
let cancelAction = UIAlertAction(title: cancelButtonTitle, style: .Cancel){ action in
NSLog("User said no")}
let otherAction = UIAlertAction(title: otherButtonTitle, style: .Default){action in
// I know I need to put something in here.
let appointment = Appointment()
self.presentViewController(appointment, animated:true, completion:nil)
}
alertController.addAction(cancelAction)
alertController.addAction(otherAction)
self.presentViewController(alertController, animated: true, completion: nil)
}
However now I get a bug saying:
Thread 1: EXC_BAD_INSTRUCTION(code=EXC_l1386_INVOP,subcode=0x0)
Add presentViewController inside UIAlertAction closure for "Ok" button, it means that the button is pressed and so you do your stuffs for the button being pressed inside the block.
class MainViewController: UIViewController {
...
...
func showAlertController(){
let tilte = "My Medication"
let message = NSLocalizedString("Go through Medication guide?", comment: "")
let cancelButtonTitle = NSLocalizedString("Dismiss", comment: "")
let otherButtonTitle = NSLocalizedString("Ok", comment: "")
let alertController = UIAlertController(title: title, message: message, preferredStyle: .Alert)
let cancelAction = UIAlertAction(title: cancelButtonTitle, style: .Cancel){ action in
NSLog("User said no")}
let otherAction = UIAlertAction(title: otherButtonTitle, style: .Default){action in
// I know I need to put something in here.
let appointmentViewController = AppointmentViewController()
self.presentViewController(appointmentViewController, animated:true, completion:nil)
}
alertController.addAction(cancelAction)
alertController.addAction(otherAction)
self.presentViewController(alertController, animated: true, completion: nil)
}
...
...
}
class AppointmentViewController: UIViewController {
}