我有选项(NSError?)被Xcode / Swift标记为非转义 . 这些函数在一个函数内(在其闭包上有@escaping)被第二个函数调用(在它的闭包上也有@escaping) . 问题似乎是在任一函数的闭包中都没有捕获错误,所以Xcode / Swift看到它们可能是逃逸的 .

之前的堆栈溢出帖子已经注意到'withoutActuallyEscaping'作为解决方法 . 似乎不再支持(Xcode版本8.2.1) .

重构试图保持函数本地的所有东西都没有用 . 我也试过移动所有的NSError?错误(通过本地枚举),但也没有奏效 .

核心问题是如何启用从一个函数返回(通过成功/失败)到调用语句的错误,以便在本地捕获并保留或标记为转义,以便Swift / XCode可以编译 .

同样,这是在Swift 2.3中工作的,所以我正在寻找关于如何重构或者使用NSError或Error正确处理这些调用的内容的建议 .

这是大型代码堆栈的一部分(约25K行) . 我发布了下面的部分堆栈(鉴于Hamish的评论),试图让问题更加清晰 . 目前,代码堆栈中存在大约17种不同的此错误变体 .

public func fetchMostRecentSamples(ofTypes types: [HKSampleType], completion: @escaping HMTypedSampleBlock)
{
    let group = DispatchGroup()
    var samples = [HKSampleType: [MCSample]]()

    let updateSamples :  ((MCSampleArray, CacheExpiry) -> Void, (MCError) -> Void, HKSampleType, [MCSample], MCError) -> Void = {
        (success, failure, type, statistics, error) in
        guard error == nil else {
            failure(error)
            return
        }
        guard statistics.isEmpty == false else {
            failure(error)
            return
        }

        samples[type] = statistics
        success(MCSampleArray(samples: statistics), .never)
    }

    let onStatistic : ((MCSampleArray, CacheExpiry) -> Void, (MCError) -> Void, HKSampleType) -> Void = { (success, failure, type) in
        self.fetchMostRecentSample(type) { (samples, error) in
            guard error == nil else {
                failure(error)
                return
            }

然后fetchMostRecentSample有这个头:public func fetchMostRecentSample(_ sampleType:HKSampleType,completion:@escaping HMSampleBlock)

并且关于失败的错误消息是“关闭使用非转义参数'失败'可能允许它转义”:“参数'失败'隐式地不转义”

请注意,let updateSamples很好(不调用另一个函数),但带有失败的onStatistic(有错误代码)是转义/非转义问题的来源 . MCError是带有错误代码的枚举(在Swift 2.3版本中从NSError?重构) .

Hamish的主要功劳是帮助我了解这一点 . 如果它帮助其他人在他们的Swift 3转换中遇到这个问题,我偶然发现的另一个地方是假设我们所有的第三方pod都已完成,如果他们已经准备好使用Swift 3.在这种情况下我必须更新AwesomeCache用于正确处理错误的代码:

open func setObject(forKey key: String, cacheBlock: @escaping (@escaping(CacheBlockClosure), @escaping(ErrorClosure)) -> Void, completion: @escaping (T?, Bool, NSError?) -> Void) {
    if let object = object(forKey: key) {
        completion(object, true, nil)
    } else {
        let successBlock: CacheBlockClosure = { (obj, expires) in
            self.setObject(obj, forKey: key, expires: expires)
            completion(obj, false, nil)
        }

        let failureBlock: ErrorClosure = { (error) in
            completion(nil, false, error)
        }

        cacheBlock(successBlock, failureBlock)
    }
}

这只是添加了两个@escaping,超出了github master中的内容 . 否则,正如Hamish所指出的,它归结为需要注意函数调用中需要添加@escaping的位置 . AwesomeCache的更新来自这样的代码:

aggregateCache.setObjectForKey(key, cacheBlock: { success, failure in
        let doCache : ([MCAggregateSample], NSError?) -> Void = { (aggregates, error) in
            guard error == nil else {
                failure(error)
                return
            }
            success(MCAggregateArray(aggregates: aggregates), .Date(self.getCacheExpiry(period)))
        }

如果成功,失败将被标记为可能在没有AwesomeCache上的代码更改的情况下转义 .