I am encountering a problem with DeviceActivityCenter the place my app generally will get hung up on the next traces:
middle.stopMonitoring()
middle.startMonitoring(.locked, throughout: defaultSchedule, occasions: occasions)
middle.startMonitoring(.unlocked, throughout: schedule, occasions: occasions)
This conduct happens inconsistently, roughly 50% of the time, and causes a delay earlier than the monitoring begins. Finally, the code does execute, however it could possibly cling for a number of seconds. This problem is new to iOS 18—it by no means occurred in iOS 17.
It hangs intermittently on the calls to stopMonitoring() and startMonitoring(). I added print() statements to substantiate that that is the place the delay happens.
Has anybody else skilled this with iOS 18? Any insights or ideas can be appreciated!
Extra Data:
Concern began after upgrading to iOS 18.
Occurs about 50% of the time, with no clear sample.
No modifications had been made to this a part of the code between iOS 17 and iOS 18.
This delay can final for as much as a minute earlier than it proceeds.
Right here is my code:
import DeviceActivity
import SwiftUI
extension DeviceActivityName {
static let locked = Self("locked")
static let unlocked = Self("unlocked")
}
extension DeviceActivityEvent.Identify {
static let locked = Self("locked")
static let unlocked = Self("unlocked")
}
class MySchedule {
static let shared = MySchedule()
let middle = DeviceActivityCenter()
@AppStorage("unlockedStartDate", retailer: UserDefaults(suiteName: "group.com.Haplo.Barrier")) non-public var unlockedStartDateData: Knowledge?
var unlockedStartDate: Date? {
get {
if let information = unlockedStartDateData {
let decoder = JSONDecoder()
if let decodedDate = strive? decoder.decode(Date.self, from: information) {
return decodedDate
}
}
return nil
}
set {
if let newDate = newValue {
let encoder = JSONEncoder()
if let encodedData = strive? encoder.encode(newDate) {
unlockedStartDateData = encodedData
} else {
unlockedStartDateData = nil
}
} else {
unlockedStartDateData = nil
}
}
}
@AppStorage("unlockedEndDate", retailer: UserDefaults(suiteName: "group.com.Haplo.Barrier")) non-public var unlockedEndDateData: Knowledge?
var unlockedEndDate: Date? {
get {
if let information = unlockedEndDateData {
let decoder = JSONDecoder()
if let decodedDate = strive? decoder.decode(Date.self, from: information) {
return decodedDate
}
}
return nil
}
set {
if let newDate = newValue {
let encoder = JSONEncoder()
if let encodedData = strive? encoder.encode(newDate) {
unlockedEndDateData = encodedData
} else {
unlockedEndDateData = nil
}
} else {
unlockedEndDateData = nil
}
}
}
// Save schedule begin and finish occasions
public func setSchedule(timeLimitMinutes: Int = 0) {
print("middle.stopMonitoring().begin")
middle.stopMonitoring([.locked, .unlocked])
print("middle.stopMonitoring().full")
if timeLimitMinutes == 0 {
// Schedule to dam apps (locked state)
let startTime = DateComponents(hour: 0, minute: 0)
let endTime = DateComponents(hour: 23, minute: 59)
let defaultSchedule = DeviceActivitySchedule(
intervalStart: startTime,
intervalEnd: endTime,
repeats: true
)
unlockedStartDate = nil
unlockedEndDate = nil
let occasions: [DeviceActivityEvent.Name: DeviceActivityEvent] = [
.locked: DeviceActivityEvent(
applications: MyModel.shared.selectionToDiscourage.applicationTokens,
categories: MyModel.shared.selectionToDiscourage.categoryTokens,
webDomains: MyModel.shared.selectionToDiscourage.webDomainTokens,
threshold: DateComponents(minute: timeLimitMinutes)
)
]
do {
print("middle.startMonitoring(.locked).begin")
strive middle.startMonitoring(.locked, throughout: defaultSchedule, occasions: occasions)
print("middle.startMonitoring(.locked).full")
} catch {
print("Error beginning locked schedule: (error.localizedDescription)")
}
} else {
// Schedule to unlock apps (unlocked state)
let schedule = getUnlockedSchedule(forMinutes: timeLimitMinutes)
let occasions: [DeviceActivityEvent.Name: DeviceActivityEvent] = [
.unlocked: DeviceActivityEvent(threshold: DateComponents(minute: timeLimitMinutes))
]
do {
print("middle.startMonitoring(.unlocked).begin")
strive middle.startMonitoring(.unlocked, throughout: schedule, occasions: occasions)
print("middle.startMonitoring(.unlocked).full")
} catch {
print("Error beginning unlocked schedule: (error.localizedDescription)")
}
}
}
// Create a schedule primarily based on the present time and specified minutes
func getUnlockedSchedule(forMinutes minutes: Int) -> DeviceActivitySchedule {
let calendar = Calendar.present
let currentDate = Date()
// Begin is now
let startComponents = calendar.dateComponents([.hour, .minute, .second], from: currentDate)
// Finish is 'minutes' from now
let intervalEnd = calendar.date(byAdding: .minute, worth: minutes, to: currentDate)!
let endComponents = calendar.dateComponents([.hour, .minute, .second], from: intervalEnd)
unlockedStartDate = currentDate
unlockedEndDate = intervalEnd
return DeviceActivitySchedule(
intervalStart: startComponents,
intervalEnd: endComponents,
repeats: false
)
}
// Examine if the present time is inside the schedule
func isScheduleUnlocked() -> Bool {
let now = Date()
guard let intervalStartDate = unlockedStartDate, let intervalEndDate = unlockedEndDate else { return false }
return now >= intervalStartDate && now <= intervalEndDate
}
}