2017-07-31 9 views
7

mój projekt wykorzystuje zarówno kod Objective-C, jak i Swift. Gdy użytkownik się loguje, wywołuje zestaw apis dla preferencji użytkownika, mam klasę DataCoordinator.swift, która planuje działanie interfejsu API i wykonuję te wywołania z klasy UserDetailViewController.m w celu załadowania preferencji użytkownika. To użycie działa dobrze przed przeniesieniem mojego kodu do Swift 4 przy użyciu Xcode 9 beta 4. Teraz, gdy się loguję, zawiesza się, podając ten błąd w mojej klasie DataCoordinator. Poniżej znajduje się przykład mojej klasy DataCoordinator i Viewcontroller.Jednoczesne dostęp do 0x1c0a7f0f8, ale modyfikacja wymaga wyjątkowego błędu dostępu w 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 
} 

// To jest jak ja to nazywam w moich viewcontrollers metoda 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 

    } 

} 

Nie jestem pewien, jak postępować w tej sprawie, widziałem raport o błędzie w https://bugs.swift.org/browse/SR-5119 ale wydaje się być naprawiono w Xcode 9 beta 3. Każda pomoc jest doceniana.

+0

widzę to również na Xcode 9 beta 5. Nie kwestia pre-beta 4 czy Xcode 8. Wciąż kopanie. – pho0

+0

Ciągle mi się przydarza w Xcode 9 Beta 6 :(dzieje się, gdy dodasz obserwatora do klawisza MPVolumeViews alfa keypath i ulega awarii podczas uzyskiwania dostępu do kontekstu w attentionValue (forKeyPath: of: change: object :) – fruitcoder

+0

Czy wiesz, w którym wierszu to jest sprawdzanie czasu wykonywania? Co to jest obiekt pod adresem '0x1c0a7f0f8'? – Sparga

Odpowiedz

10

Myślę, że ten "błąd" może być cechą Swift 4 ', a konkretnie czymś, co nazywają "Wyłącznym dostępem do pamięci".

Zobacz wideo z WWDC. Około 50-minutowej minuty wyjaśnia to długowłosy mówca.

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

można spróbować toczenia gwintu dezynfekcji wyłączyć w ustawieniach schematu, jeśli jesteś szczęśliwy, aby go zignorować. Jednak debugger próbuje ci opowiedzieć o subtelnym wątku, więc prawdopodobnie lepiej wykorzystasz swój czas, aby dowiedzieć się, dlaczego coś piszesz do swojej tablicy w tym samym czasie, kiedy jest czytane.

0

W moim przypadku, Swift 4 faktycznie odkrył rodzaj błędu, którego bym nie zauważył, dopóki nie zacznę wywoływać funkcji z więcej niż jednego miejsca. Moja funkcja została przekazana inout globalnej tablicy i odwoływała się zarówno do tego parametru, jak i do nazwy globalnej. Kiedy zmieniłem funkcję, by odnieść się tylko do parametru, błąd "równoczesny dostęp" zniknął.

0

Swift 4: Jeśli sprawdzisz swój kontekst w metodzie observeValue, po prostu ustaw zmienną kontekstową na statyczną. Ten blog post opisuje ten problem szczegółowo.

1

Pod ustawieniami konstrukcyjnymi celu. Wybierz No Enforcement dla Exclusive Access to Memory z Swift Compiler - Code Generation

Powiązane problemy