Swift 3 在 NSOperation 中调用 init 时添加 @esaping 属性崩溃
Swift 3 adding @esaping attribute crashes when calling init in NSOperation
我有一个函数定义了这样的闭包:
func synchronizeData(completion externalCompletion: RequestsCompletionHandler?) {
let closure = {
(operationCompletion:@escaping ()->Void) in
assert(Thread.isMainThread, "must be the main thread")
/*
Internal (non-optional) completion handler
*/
let internalCompletion: RequestsCompletionHandler = {
(success, newData, decommissionRequired, errors) -> Void in
/*
Synchronization is finished. Firstly, call either the external completion handler or the delegate
*/
if let externalCompletion = externalCompletion {
externalCompletion(success, newData, decommissionRequired, errors)
}
else {
self.delegate?.synchroniationInteractor(self, didSynchronizeDataWithStatus: success, dataIsNew: newData, decommissionRequired: decommissionRequired, error: errors.last)
}
/*
Now call the closure operation's completion handler
*/
operationCompletion()
}
/*
The synchronization itself
*/
guard let _ = self.keychain.retrieveActivationIdentifiers() else {
internalCompletion(false, false, false, [NSError(domain: "", code: 0, userInfo: ["reason" : "unable to retrieve credentials"])])
return
}
var errors :[NSError] = []
var numberOfRequests = 0
var completedRequests = 0
var decommissionRequired: Bool?
/*
Synchronization results handler. Regardless of success for fail, increase completed requests counter and append any errors to array, if final request call main completion block
*/
let handleCompletedRequests = {
(error: NSError?) -> Void in
// assert(NSThread.isMainThread(), "must be the main thread")
if let error = error {
errors.append(error)
}
completedRequests += 1
if(completedRequests >= numberOfRequests) {
internalCompletion(errors.count == 0, true, decommissionRequired, errors)
/*
Decrement operations counter
*/
self.manageBusy(retain: false)
}
}
/*
Increment operations counter
*/
self.manageBusy(retain: true)
/*
Do the actual synchronization.
Fetch the Patient Data first
*/
self.fetchPatientDataInternal {
(success, newData, error) -> Void in
numberOfRequests = 6
//Fetch Patient Schedule
self.fetchPatientScheduleInternal {
(success, newData, error) -> Void in
handleCompletedRequests(error)
}
//Fetch Patient Thresholds
self.fetchPatientThresholdInternal {
(success, newData, error) -> Void in
handleCompletedRequests(error)
}
//Fetch Patient Device Settings
self.fetchPatientDeviceSettingsInternal {
(success, newData, decommissionReq, error) -> Void in
decommissionRequired = decommissionReq
handleCompletedRequests(error)
}
// Device Checkin
self.deviceCheckInInternal {
(success, newData, error) -> Void in
handleCompletedRequests(error)
}
// Upload Vitals
self.uploadPendingVitalsInternal {
(success, newData, error) -> Void in
handleCompletedRequests(error)
}
//Upload Health sessions
self.uploadPendingHealthSessionsInternal {
(success, newData, error) -> Void in
handleCompletedRequests(error)
}
}
}
let operation = CIAsyncronousOperation.init(closure: closure as! (()->Void)-> Void)
operation.name = "Data Synchronization"
isolationQueue.addOperation(operation)
}
当我们在上面的函数中调用这一行时,即
let operation = CIAsyncronousOperation.init(closure: closure as! (()->Void)-> Void)
应用程序崩溃并显示以下信息:
0x00000001003b083c CIAppliance`partial apply forwarder for CIAppliance.SynchronizationInteractor.(synchronizeData (completion : Swift.Optional<(Swift.Bool, Swift.Optional, Swift.Optional, Swift.Array<__ObjC.NSError>) -> ()>) -> ()).(closure #1) at SynchronizationInteractor.swift
CIAsyncronousOperation init定义如下:
init(closure aClosure: @escaping (()->Void)-> Void)
{
closure = aClosure
}
我无法找出崩溃的原因。是转换问题还是由于新的 Swift 3 语法更改?
如果您必须强制转换函数,那么很可能您的函数签名不正确。如果 CIAsyncronousOperation 定义如下,它将编译。函数和作为参数aClosure的函数都需要设置为@escaping
class CIAsyncronousOperation {
init(closure aClosure: @escaping (@escaping ()->Void)->Void)
{
closure = aClosure
}
var closure : (@escaping ()->Void)-> Void;
}
我有一个函数定义了这样的闭包:
func synchronizeData(completion externalCompletion: RequestsCompletionHandler?) {
let closure = {
(operationCompletion:@escaping ()->Void) in
assert(Thread.isMainThread, "must be the main thread")
/*
Internal (non-optional) completion handler
*/
let internalCompletion: RequestsCompletionHandler = {
(success, newData, decommissionRequired, errors) -> Void in
/*
Synchronization is finished. Firstly, call either the external completion handler or the delegate
*/
if let externalCompletion = externalCompletion {
externalCompletion(success, newData, decommissionRequired, errors)
}
else {
self.delegate?.synchroniationInteractor(self, didSynchronizeDataWithStatus: success, dataIsNew: newData, decommissionRequired: decommissionRequired, error: errors.last)
}
/*
Now call the closure operation's completion handler
*/
operationCompletion()
}
/*
The synchronization itself
*/
guard let _ = self.keychain.retrieveActivationIdentifiers() else {
internalCompletion(false, false, false, [NSError(domain: "", code: 0, userInfo: ["reason" : "unable to retrieve credentials"])])
return
}
var errors :[NSError] = []
var numberOfRequests = 0
var completedRequests = 0
var decommissionRequired: Bool?
/*
Synchronization results handler. Regardless of success for fail, increase completed requests counter and append any errors to array, if final request call main completion block
*/
let handleCompletedRequests = {
(error: NSError?) -> Void in
// assert(NSThread.isMainThread(), "must be the main thread")
if let error = error {
errors.append(error)
}
completedRequests += 1
if(completedRequests >= numberOfRequests) {
internalCompletion(errors.count == 0, true, decommissionRequired, errors)
/*
Decrement operations counter
*/
self.manageBusy(retain: false)
}
}
/*
Increment operations counter
*/
self.manageBusy(retain: true)
/*
Do the actual synchronization.
Fetch the Patient Data first
*/
self.fetchPatientDataInternal {
(success, newData, error) -> Void in
numberOfRequests = 6
//Fetch Patient Schedule
self.fetchPatientScheduleInternal {
(success, newData, error) -> Void in
handleCompletedRequests(error)
}
//Fetch Patient Thresholds
self.fetchPatientThresholdInternal {
(success, newData, error) -> Void in
handleCompletedRequests(error)
}
//Fetch Patient Device Settings
self.fetchPatientDeviceSettingsInternal {
(success, newData, decommissionReq, error) -> Void in
decommissionRequired = decommissionReq
handleCompletedRequests(error)
}
// Device Checkin
self.deviceCheckInInternal {
(success, newData, error) -> Void in
handleCompletedRequests(error)
}
// Upload Vitals
self.uploadPendingVitalsInternal {
(success, newData, error) -> Void in
handleCompletedRequests(error)
}
//Upload Health sessions
self.uploadPendingHealthSessionsInternal {
(success, newData, error) -> Void in
handleCompletedRequests(error)
}
}
}
let operation = CIAsyncronousOperation.init(closure: closure as! (()->Void)-> Void)
operation.name = "Data Synchronization"
isolationQueue.addOperation(operation)
}
当我们在上面的函数中调用这一行时,即
let operation = CIAsyncronousOperation.init(closure: closure as! (()->Void)-> Void)
应用程序崩溃并显示以下信息:
0x00000001003b083c CIAppliance`partial apply forwarder for CIAppliance.SynchronizationInteractor.(synchronizeData (completion : Swift.Optional<(Swift.Bool, Swift.Optional, Swift.Optional, Swift.Array<__ObjC.NSError>) -> ()>) -> ()).(closure #1) at SynchronizationInteractor.swift
CIAsyncronousOperation init定义如下:
init(closure aClosure: @escaping (()->Void)-> Void)
{
closure = aClosure
}
我无法找出崩溃的原因。是转换问题还是由于新的 Swift 3 语法更改?
如果您必须强制转换函数,那么很可能您的函数签名不正确。如果 CIAsyncronousOperation 定义如下,它将编译。函数和作为参数aClosure的函数都需要设置为@escaping
class CIAsyncronousOperation {
init(closure aClosure: @escaping (@escaping ()->Void)->Void)
{
closure = aClosure
}
var closure : (@escaping ()->Void)-> Void;
}