Swift 4 Как получить все события из календаря?
Я использую Swift 4.1. И я хочу написать функцию, которая будет собирать все события из всех календарей в приложении Календарь iOS. Благодаря этому ответу на stackru: Как получить все события из календаря (Swift) я смог написать свой собственный class
и назовите это Cale
, Пожалуйста, посмотрите на это:
import UIKit
import EventKit
class Cale {
private func createDate(year: Int) -> Date {
var components = DateComponents()
components.year = year
components.timeZone = TimeZone(secondsFromGMT: 0)
return Calendar.current.date(from: components)!
}
private let eventStore = EKEventStore()
private func get() {
let calendars = eventStore.calendars(for: .event)
for calendar in calendars {
// This checking will remove Birthdays and Hollidays callendars
guard calendar.allowsContentModifications else {
continue
}
let start = createDate(year: 2016)
let end = createDate(year: 2025)
print("start: \(start)")
print(" end: \(end)")
let predicate = eventStore.predicateForEvents(withStart: start, end: end, calendars: [calendar])
print("predicate: \(predicate)")
let events = eventStore.events(matching: predicate)
for event in events {
print(" title: \(event.title!)")
print("startDate: \(event.startDate!)")
print(" endDate: \(event.endDate!)")
}
}
}
func checkStatusAndGetAllEvents() {
let currentStatus = EKEventStore.authorizationStatus(for: EKEntityType.event)
switch currentStatus {
case .authorized:
//print("authorized")
self.get()
case .notDetermined:
//print("notDetermined")
eventStore.requestAccess(to: .event) { accessGranted, error in
if accessGranted {
self.get()
} else {
print("Change Settings to Allow Access")
}
}
case .restricted:
print("restricted")
case .denied:
print("denied")
}
}
}
Довольно простой класс, вы можете использовать его, он работает, но с одним исключением. Основная функция там есть get()
В этой функции я создаю предикат, основанный на двух датах: начало и конец. Как вы видите, дата начала:
2016-01-01 00:00:00 +0000
и дата окончания:
2025-01-01 00:00:00 +0000
Но если мы запустим программу, мы увидим, что предикат будет выглядеть так:
Начало CADEventPredicate: 01.01.2016, 03:00; конец: 01.01.2020, 03:00; cals:( 2)
Только с 2016 по 2020, 4 года! Я проверил это в разные даты, но я мог получить предикат с интервалом максимум 4 года. Значит, это не даст мне все события! Итак, вопрос: как получить все события из календаря? Если это возможно, без использования даты!
Спасибо за любую будущую помощь или совет!
0 ответов
В случае, если кому-то все еще интересно, Apple намеренно ограничила это четырьмя годами.
Из predicateForEvents(withStart:end:calendars:):
По соображениям производительности этот метод сопоставляет только те события в течение четырехлетнего промежутка времени. Если диапазон дат между startDate и endDate превышает четыре года, он сокращается до первых четырех лет.
Если вам нужен более длинный диапазон, я думаю, вам придется обернуть его в свою собственную функцию, чтобы разделить его на четыре года.
Потратив так много времени, я нашел решение своей проблемы. Моя проблема была как ниже,
event start date 2019-03-15 09:00:00 +0000
event end date 2019-03-15 14:00:00 +0000
предикат, как показано ниже,
CADEventPredicate start:15/03/19, 1:30 PM; end:15/03/19, 7:30 PM; cals:(null)
Поскольку я из Индии, предикат добавляет GMT+5:30 к фактическому времени начала и окончания события. Я получил метод от переполнения стека, чтобы преобразовать в локальный и глобальный часовой пояс, как показано ниже.
extension Date {
// Convert local time to UTC (or GMT)
func toGlobalTime() -> Date {
let timezone = TimeZone.current
let seconds = -TimeInterval(timezone.secondsFromGMT(for: self))
return Date(timeInterval: seconds, since: self)
}
// Convert UTC (or GMT) to local time
func toLocalTime() -> Date {
let timezone = TimeZone.current
let seconds = TimeInterval(timezone.secondsFromGMT(for: self))
return Date(timeInterval: seconds, since: self)
}
}
Проходя дату начала и окончания со временем, чтобы предсказать, я конвертирую в globalTimeZone, как показано ниже.
let predicate = eventStore.predicateForEvents(withStart: eventStartDateTime.toGlobalTime(), end: eventEndDateTime.toGlobalTime(), calendars: nil)
Если у вас нет времени, у вас есть только даты начала и окончания, а затем используйте предикат, как показано ниже,
event start date 2019-03-15 00:00:00 +0000
event end date 2019-03-15 00:00:00 +0000
let predicate = eventStore.predicateForEvents(withStart: eventStartDateTime, end: eventEndDateTime, calendars: nil)
Потому что, если у вас нет времени и конвертации в globalTimeZone, вы можете столкнуться с проблемами при удалении событий.
Надеюсь, это кому-нибудь поможет.