如何解决requestAccess(无限循环:完成:)上EKEventStore?

问题描述 投票:6回答:2

我接通EKAuthorizationStatus但即使requestAuthorisation(to:commit:)被调用,并返回真实,没有错误switch语句中的.notDetermined情况下仍然符合并在它的递归产生无限循环后。它驱使我疯了!

我试图找出requestAuthorisation(to:commit:)如何实际工作,因为我感觉这个问题是所有关于并发或东西,但我无法找到任何东西,所以我无法真正原因有关情况。

而且,由于在我的代码递归绝对是这个无限循环的一部分,我想没有递归的方法。但由于EKAuthorizationStatus可能我的应用程序的调用之间改变的事件商店,我要检查它提前反应到所有它的相应规定。所以我会打电话给我的方法用于切换的授权状态,一个用于请求,并处理所有在我的类,我不想为了可读性,安全而且合理的任何错误。

private func confirmAuthorization(for entityType: EKEntityType) throws {
    switch EKEventStore.authorizationStatus(for: entityType) {
    case EKAuthorizationStatus.notDetermined:
        // Request authorisation for the entity type.
        requestAuthorisation(for: entityType)

        // Switch again.
        try confirmAuthorization(for: entityType)

    case EKAuthorizationStatus.denied:
        print("Access to the event store was denied.")
        throw EventHelperError.authorisationDenied

    case EKAuthorizationStatus.restricted:
        print("Access to the event store was restricted.")
        throw EventHelperError.authorisationRestricted

    case EKAuthorizationStatus.authorized:
        print("Acces to the event store granted.")
    }
}

private func requestAuthorisation(for entityType: EKEntityType) {
    store.requestAccess(to: entityType) { (granted, error)  in
        if (granted) && (error == nil) {
            DispatchQueue.main.async {
                print("User has granted access to \(String(describing: entityType))") // It's being printed over and over
            }
        } else {
            DispatchQueue.main.async {
                print("User has denied access to \(String(describing: entityType))")
            }
        }
    }
}

我期待的开关将匹配在首次推出的.notDetermined情况下,它会要求授权。所以,当我通过开关的状态再次应现配不同的情况下,像.authorized.denied。但实际上它的.notDetermined情况下再次匹配,并访问被授予了个遍。 \>:[

console:

>2019-01-08 12:50:51.314628+0100 EventManager[4452:190572] libMobileGestalt MobileGestalt.c:890: MGIsDeviceOneOfType is not supported on this platform.
>2019-01-08 12:50:54.608391+0100 EventManager[4452:190572] Adding a new event.
>2019-01-08 12:50:54.784684+0100 EventManager[4452:190572] [MC] System group container for systemgroup.com.apple.configurationprofiles path is /Users/***/Library/Developer/CoreSimulator/Devices/********-****-****-****-************/data/Containers/Shared/SystemGroup/systemgroup.com.apple.configurationprofiles
>2019-01-08 12:50:54.785638+0100 EventManager[4452:190572] [MC] Reading from private effective user settings.
>Acces to the event store granted.
>Saved event with identifier: Optional("F8EAC467-9EC2-476C-BF30-45588240A8D0:903EF489-BB52-4A86-917B-DF72494DEA3D")
>2019-01-08 12:51:03.019751+0100 EventManager[4452:190572] Events succsessfully saved.
>User has granted access to EKEntityType
>User has granted access to EKEntityType
>User has granted access to EKEntityType
>[…]
>User has granted access to EKEntityType
>User has granted access to EKEntityType
>User has granted access to EKEntityType
>2019-01-08 12:51:03.291606+0100 EventManager[4452:190572] [Common] _BSMachError: port 26b03; (os/kern) invalid capability (0x14) "Unable to insert COPY_SEND"
>2019-01-08 12:51:03.317800+0100 EventManager[4452:190572] [Common] _BSMachError: port 26b03; (os/kern) invalid capability (0x14) "Unable to insert COPY_SEND"
>User has granted access to EKEntityType
>User has granted access to EKEntityType
>User has granted access to EKEntityType
>[…]
>User has granted access to EKEntityType
>User has granted access to EKEntityType
>User has granted access to EKEntityType
>Acces to the event store granted.
>Preset <EventManager.EventCreationPreset: 0x6000020ca340> needs update.
>Acces to the event store granted.
>Preset <EventManager.EventCreationPreset: 0x6000020ca340> was updated.
>2019-01-08 12:51:03.567071+0100 EventManager[4452:190572] Events succsessfully saved.
>User has granted access to EKEntityType
>User has granted access to EKEntityType
>User has granted access to EKEntityType
>[…]
swift recursion infinite-loop eventkit ekeventstore
2个回答
5
投票

requestAuthorisation异步运行,所以在授权对话框甚至被呈现给用户confirmAuthorization越来越再次调用。

一般来说,在这种模式(在异步模式的递归调用东西的欲望)的,该解决方案将是递归调用移动到异步方法的完成处理。但是,在这种情况下,用户获取授权对话框后,他们会接受或拒绝,而且也没有点担心:“如果它仍然没有确定是什么”的状态。因此,底线,需要或在这种情况下期望没有递归。

话虽如此,很显然你希望得到的状态返回给调用者。但错误引发模式是行不通的,因为你需要处理异步情况(这里没有确定的权限,我们需要提出一个确认对话框)。

所以,我建议,而是你用整个完成处理模式:

private func confirmAuthorization(for entityType: EKEntityType, completion: @escaping (EKAuthorizationStatus) -> Void) {
    let status = EKEventStore.authorizationStatus(for: entityType)

    switch status {
    case .notDetermined:
        requestAuthorisation(for: entityType, completion: completion)

    default:
        completion(status)
    }
}

private func requestAuthorisation(for entityType: EKEntityType, completion: @escaping (EKAuthorizationStatus) -> Void) {
    store.requestAccess(to: entityType) { _, _ in
        DispatchQueue.main.async {
            completion(EKEventStore.authorizationStatus(for: entityType))
        }
    }
}

或者,你可以减少到一个单一的方法:

private func confirmAuthorization(for entityType: EKEntityType, completion: @escaping (EKAuthorizationStatus) -> Void) {
    let status = EKEventStore.authorizationStatus(for: entityType)

    switch status {
    case .notDetermined:
        store.requestAccess(to: entityType) { _, _ in
            DispatchQueue.main.async {
                completion(EKEventStore.authorizationStatus(for: entityType))
            }
        }

    default:
        completion(status)
    }
}

那么你也能:

confirmAuthorization(for: .event) { status in
    switch status {
    case .authorized:
        // proceed

    default:
        // handle non-authorized process here
    }
}

// But, remember, the above runs asynchronously, so do *not*
// put any code contingent upon the auth status here. You 
// must put code contingent upon authorization inside the above
// completion handler closure.
//

2
投票
// Request authorisation for the entity type.
requestAuthorisation(for: entityType)

被产卵的闭合,这是在后台线程中执行。这意味着该计划的继续,这个方法调用的结果将在未来的某一时刻被传递。问题是:

// Switch again.
try confirmAuthorization(for: entityType)

在随即〜执行主线程〜,并产生另一个后台线程。你不等待这些后台线程来完成,调用另一个后台线程等之前。你需要返工逻辑等待requestAuthorisation再次调用confirmAuthorization之前返回的东西...

© www.soinside.com 2019 - 2024. All rights reserved.