it-swarm.com.de

Gleichzeitiger Zugriff auf 0x1c0a7f0f8, jedoch für die Änderung ist ein exklusiver Zugriffsfehler in Xcode 9 Beta 4 erforderlich

mein Projekt verwendet sowohl Objective-C- als auch Swift-Code. Wenn sich ein Benutzer anmeldet, ruft er eine Gruppe von apis für Benutzereinstellungen auf. Ich habe eine DataCoordinator.Swift-Klasse, die die API-Operation plant, und ich mache diese Aufrufe von der UserDetailViewController.m-Klasse, um Benutzervorgaben zu laden. Damit funktioniert es einwandfrei, bevor ich meinen Code mit Xcode 9 Beta 4 nach Swift 4 migriert habe. Wenn ich mich jetzt anmelde, stürzt er ab, indem ich mir diesen Fehler in meiner DataCoordinator-Klasse ansehe. Nachfolgend finden Sie ein Beispiel meiner DataCoordinator- und Viewcontroller-Klasse. 

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
}

// So nenne ich es in meiner viewDidLoad-Methode von viewcontrollers

__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

     }

}

Ich bin mir nicht sicher, wie ich weiter vorgehen soll. Ich habe einen Fehlerbericht unter https://bugs.Swift.org/browse/SR-5119 gesehen, aber es scheint in Xcode 9 Beta 3 behoben zu sein wird geschätzt

16
Gamerlegend

Ich denke, dieser "Fehler" kann eine "Swift 4" - Funktion sein, die als "exklusiver Zugriff auf Speicher" bezeichnet wird.

Schauen Sie sich dieses WWDC-Video an. Um die 50-Minuten-Marke erklärt es der langhaarige Sprecher.

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

Sie können versuchen, das Thread-Desinfektionsmittel in den Schemaeinstellungen auszuschalten, wenn Sie es ignorieren möchten. Der Debugger versucht jedoch, Sie über ein subtiles Threading-Problem zu informieren, sodass Sie Ihre Zeit wahrscheinlich besser nutzen können, um herauszufinden, warum Sie etwas gleichzeitig in Ihr Array schreiben, aus dem es gelesen wird. 

19
Mark Bridges

Unter den Build-Einstellungen des Ziels. Wählen Sie No Enforcement für Exclusive Access to Memory aus Swift Compiler - Code Generation

7
geek1706

Nur in Swift 4 und bei Verwendung der Option .initial für Ihre KVO-Einstellungen

Wenn Sie Ihren Kontext in der observValue-Methode überprüfen, machen Sie einfach Ihre Kontextvariable static. Dieser Blogbeitrag beschreibt diesen Fehler im Detail.

6
Ralf Hundewadt

In meinem Fall entdeckte Swift 4 tatsächlich eine Art Fehler, den ich erst bemerkt hatte, als ich angefangen hatte, eine Funktion von mehreren Stellen aufzurufen. Meine Funktion wurde in einem globalen Array übergeben, und es wurde sowohl auf diesen Parameter als auch auf den globalen Namen verwiesen. Wenn ich die Funktion so geändert habe, dass nur der Parameter referenziert wird, ist der Fehler "Gleichzeitiger Zugriff" nicht mehr vorhanden. 

2
KenM

In Swift 5.0 ist dies das Standardverhalten, wenn Sie Ihre Anwendung im Release-Modus ausführen. Vor 5.0 (Swift 4.2.1 ab heute und niedriger) wird dieses Verhalten nur im Debug-Modus ausgeführt.

Ihre Anwendung schlägt möglicherweise im Freigabemodus fehl, wenn Sie diesen Fehler ignoriert haben.

Betrachten Sie dieses Beispiel:

func modifyTwice(_ value: inout Int, by modifier: (inout Int) -> ()) {
  modifier(&value)
  modifier(&value)
}

func testCount() {
  var count = 1
  modifyTwice(&count) { $0 += count }
  print(count)
}

Was ist der Wert von count, wenn die Druckzeile (count) gedruckt wird? Ich weiß es auch nicht und der Compiler liefert unvorhersehbare Ergebnisse, wenn Sie diesen Code ausführen. Dies ist in Swift 4.0 im Debug-Modus nicht zulässig und in Swift 5.0 stürzt es sogar zur Laufzeit ab.

Quelle: https://Swift.org/blog/Swift-5-exclusivity/

1
J. Doe

Die Antworten von @ Mark Bridges und @ Geek1706 sind gute Antworten, aber ich möchte meine 2 Cent über diese Angelegenheit hinzufügen und ein allgemeines Beispiel geben.

Wie oben erwähnt, ist dies eine Funktion in Swift 4 SE-176 .

Natürlich sollte die Implementierung weiterhin die Möglichkeit haben, konkurrierende Zugriffe zu erkennen. Einige Programmierer möchten möglicherweise stattdessen einen Thread-sicheren Durchsetzungsmechanismus für die Aktivierung verwenden, zumindest in einigen Build-Konfigurationen.

Der exklusive Zugriff erzwingt, dass jede Schreibmutation von Variablen exklusiv sein muss, wenn auf diese Variable zugegriffen wird. In einer Multithread-Umgebung können mehrere Threads, die auf eine gemeinsam genutzte Variable und eine oder mehrere zugreifen, diese ändern.

Es gibt kein gutes Beispiel: Wenn wir versuchen, einen gemeinsam genutzten Wert in einer Umgebung mit mehreren Threads mithilfe einer Abstraktion (Mutation tritt bei einem Protokolltyp auf) zwischen zwei Objekten zu mutieren und Exclusive Access to Memory Aktiviert ist, stürzt unsere App ab .

protocol Abstraction {
  var sharedProperty: String {get set}
}

class MyClass: Abstraction {
  var sharedProperty: String

  init(sharedProperty: String) {
     self.sharedProperty = sharedProperty
  }

  func myMutatingFunc() {
     // Invoking this method from a background thread
     sharedProperty = "I've been changed"
  }
}


class MainClass {
   let myClass: Abstraction

   init(myClass: Abstraction) {
     self.myClass = myClass
   }

   func foobar() {
      DispatchQueue.global(qos: .background).async {
         self.myClass.myMutatingFunc()
      }
   }
}

let myClass = MyClass(sharedProperty: "Hello")
let mainClass = MainClass(myClass: myClass)
// This will crash
mainClass.foobar()

Da wir nicht angegeben haben, dass das Abstraction -Protokoll class gebunden ist, wird die Erfassung von myMutatingFunc zur Laufzeit in self als struct, obwohl wir ein tatsächliches class (MyClass) injiziert haben.

Escape-Variablen erfordern im Allgemeinen eine dynamische Erzwingung anstelle einer statischen Erzwingung. Dies liegt daran, dass Swift nicht begründen kann, wann ein Escape-Closure aufgerufen wird und somit auf die Variable zugegriffen wird.

Die Lösung besteht darin, das Protokoll Abstraction an class zu binden:

protocol Abstraction: class
1
OhadM

Was ich mache, ist FetchOperation in class statt struct zu ändern.

0
Tai Le

In meinem Fall habe ich die Tabellenhöhe während des Erstellens des Projekts geändert. Zu dieser Zeit war mein Gerät mit dem Netzwerk verbunden. Ich habe die abgeleiteten Daten gelöscht und das Problem für mich behoben.

0
Raj Mohan

Die Rückgabe von Null in der numberOfSections-Überschreibungsfunktion führt zu diesem Absturz:

override func numberOfSections(in collectionView: UICollectionView) -> Int {
    // This causes a crash!    
    return 0
}

Einfache Lösung - return 1 in der Funktion oben und dann return 0 in der Funktion collectionView(_:numberOfItemsInSection:).

override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int
0
JonJ