2017-07-31 4 views
7

mon projet utilise à la fois Objective-C et le code Swift. Quand un utilisateur se connecte, il appelle un ensemble d'API pour les préférences de l'utilisateur, j'ai une classe DataCoordinator.swift qui planifie l'opération d'API et je fais ces appels de la classe UserDetailViewController.m pour charger les préférences de l'utilisateur. Cette utilisation fonctionne bien avant de migrer mon code vers Swift 4 en utilisant Xcode 9 beta 4. Maintenant, lorsque je me connecte, il se bloque en me donnant cette erreur dans ma classe DataCoordinator. Voici un exemple de ma classe DataCoordinator et Viewcontroller.simultanée accède à 0x1c0a7f0f8, mais la modification nécessite erreur d'accès exclusif sur Xcode 9 beta 4

DataCoordinator.swift 

import UIKit 

@objcMembers 

class 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 Struct 
private typealias FetchOperationBlock = (_ operation:FetchOperation)->Void 

private 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 
} 

// Voici comment je l'appelle dans mes viewcontrollers méthode viewDidLoad

__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 

    } 

} 

Je ne sais pas comment procéder à ce sujet, j'ai vu un rapport de bogue à https://bugs.swift.org/browse/SR-5119, mais il semble être fixe dans Xcode 9 beta 3. Toute aide est appréciée

+0

Je vois cela aussi bien sur Xcode 9 beta 5. Pas un problème pré-bêta 4 ou 8. est Xcode creuser encore. – pho0

+0

passe encore à moi dans Xcode 9 Beta 6 :(il se produit lorsqu'un ajouter un observateur à un bouton MPVolumeViews alpha keypath et se bloque à chaque accès au contexte dans observeValue (forKeyPath: de: changement: objet :) – fruitcoder

+0

Savez-vous à quelle ligne ce contrôle d'exécution est déclenché? Quel est l'objet à l'adresse '0x1c0a7f0f8'? – Sparga

Répondre

10

Je pense que ce « bug » peut être une « caractéristique » Swift 4, plus précisément ce qu'ils appellent « l'accès exclusif à la mémoire ».

Découvrez cette vidéo WWDC. Autour de la marque de 50 minutes, le haut-parleur à poil long l'explique.

https://developer.apple.com/videos/play/wwdc2017/402/?time=233

Vous pouvez essayer tourner le fil désinfectant pour les mains hors dans les paramètres du régime si vous êtes heureux de l'ignorer. Cependant, le débogueur essaie de vous parler d'un problème de thread subtil, il est donc préférable que vous utilisiez votre temps pour essayer de comprendre pourquoi vous avez écrit quelque chose sur votre tableau en même temps qu'il est lu.

0

Dans mon cas, Swift 4 en fait découvert une sorte de bug que je ne l'aurais pas remarqué jusqu'à ce que je commencé à appeler une fonction de plus d'un endroit. Ma fonction a été passé un tableau global inout et il référençait à la fois ce paramètre et le nom global. Lorsque j'ai changé la fonction pour ne référencer que le paramètre, l'erreur "accès simultané" s'est dissipée.

0

Swift 4: Si vous vérifiez votre contexte dans la méthode observeValue, il suffit de faire votre contexte statique variable. Ce blog post décrit ce problème en détail.

1

Sous les paramètres de construction de la cible. Sélectionnez No Enforcement pour Exclusive Access to Memory de Swift Compiler - Code Generation