my project uses both Objective-C and Swift code. When a user logs in, it calls a set of apis for user preference, I have a DataCoordinator.swift class which schedules the API operation and I make this calls from UserDetailViewController.m class to load user preferences. This use to work fine before I migrated my code to Swift 4 using Xcode 9 beta 4. Now when I login it crashes by giving me this error in my DataCoordinator class. Below is a sample of my DataCoordinator and Viewcontroller class.
DataCoordinator.swiftimport UIKit@objcMembersclass DataCoordinator: NSObject { //MARK:- Private fileprivate var user = myDataStore.sharedInstance().user fileprivate var preferenceFetchOperations = [FetchOperation]() fileprivate func scheduleFetchOperation(_ operation:FetchOperation, inFetchOperations operations:inout [FetchOperation]) { guard operations.index(of: operation) == nil else { return } operations.append(operation) } fileprivate func completeFetchOperation(_ fetchOperation:FetchOperation, withError error:Error?, andCompletionHandler handler:@escaping FetchCompletionHandler) { func removeOperation(_ operation:FetchOperation, fromOperations operations:inout [FetchOperation]) { if operations.count > 0 { operations.remove(at: operations.index(of: fetchOperation)!) handler(error) } } if preferenceFetchOperations.contains(fetchOperation) { removeOperation(fetchOperation, fromOperations: &preferenceFetchOperations) } } fileprivate func schedulePreferencesFetchOperation(_ serviceName:String, fetch:@escaping FetchOperationBlock){ let operation = FetchOperation(name: serviceName, fetch: fetch); scheduleFetchOperation(operation, inFetchOperations: &preferenceFetchOperations) } fileprivate func runOperationsIn(_ fetchOperations:inout [FetchOperation]) { for var operation in fetchOperations { guard operation.isActivated == false else { continue } operation.isActivated = true operation.execute() } } //MARK:- Non-Private typealias FetchCompletionHandler = (_ error:Error?)->Void var numberOfPreferencesFetchCalls:Int { get { return preferenceFetchOperations.count } } // MARK: - func fetchPreferences(_ completionHandler:@escaping FetchCompletionHandler) -> Void { defer { runOperationsIn(&preferenceFetchOperations) } schedulePreferencesFetchOperation("com.fetchPreferences.type1") {[unowned self] (operation:FetchOperation) in WebServiceManager.getType1Detail(for: user) {[unowned self] (error) in self.completeFetchOperation(operation, withError: error, andCompletionHandler: completionHandler) } } schedulePreferencesFetchOperation("com.fetchPreferences.type2") {[unowned self] (operation:FetchOperation) in WebServiceManager.getType2Detail(for: user) {[unowned self] (error) in self.completeFetchOperation(operation, withError: error, andCompletionHandler: completionHandler) } } schedulePreferencesFetchOperation("com.fetchPreferences.type3") {[unowned self] (operation:FetchOperation) in WebServiceManager.getType3Detail(for: user) {[unowned self] (error) in self.completeFetchOperation(operation, withError: error, andCompletionHandler: completionHandler) } } schedulePreferencesFetchOperation("com.fetchPreferences.type4") {[unowned self] (operation:FetchOperation) in WebServiceManager.getType4Detail(for: user) {[unowned self] (error) in self.completeFetchOperation(operation, withError: error, andCompletionHandler: completionHandler) } } }}// MARK:- Fetch Operation Structprivate typealias FetchOperationBlock = (_ operation:FetchOperation)->Voidprivate struct FetchOperation:Hashable { fileprivate var runToken = 0 fileprivate let fetchBlock:FetchOperationBlock let name:String! var isActivated:Bool { get { return runToken == 0 ? false : true } mutating set { if runToken == 0 && newValue == true { runToken = 1 } } } fileprivate var hashValue: Int { get { return name.hashValue } } func execute() -> Void { fetchBlock(self) } init (name:String, fetch:@escaping FetchOperationBlock) { self.name = name self.fetchBlock = fetch }}private func ==(lhs: FetchOperation, rhs: FetchOperation) -> Bool { return lhs.hashValue == rhs.hashValue}
//This is how I call it in my viewcontrollers viewDidLoad method
__weak UserDetailViewController *weakSelf = self;[self.dataCoordinator fetchPreferences:^(NSError * _Nullable error) { if (error == nil) { [weakSelf didFetchPrefrences]; } else { // handle error } }];//completion response- (void)didFetchPrefrences { //when api calls complete load data if (self.dataCoordinator.numberOfPreferencesFetchCalls == 0) { //Load details }}
I'm not sure how to proceed on this, I saw a bug report at https://bugs.swift.org/browse/SR-5119 but it seems to be fixed in Xcode 9 beta 3. Any help is appreciated