Simultaneous accesses to 0x1c0a7f0f8, but modification requires exclusive access error on Xcode 9 beta 4

余生颓废 提交于 2019-11-27 08:37:25

I think this 'bug' may be a Swift 4 'feature', specifically something they call 'Exclusive access to Memory'.

Check out this WWDC video. Around the 50 minute mark, the long-haired speaker explains it.

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

You could try turning the thread sanitizer off in your scheme settings if you're happy to ignore it. However, the debugger is trying to tell you about a subtle threading issue so it's probably a better use of your time to try to figure out why you've got something writing to your array at the same time it's being read from.

Under the target's Build Settings. Select No Enforcement for Exclusive Access to Memory from Swift Compiler - Code Generation

Ralf Hundewadt

Only in Swift 4 and when using .initial option for your KVO Settings

If you check your context in observeValue method, just make your context variable static. This blog post describes this bug in detail.

In Swift 5.0, this will be the default behavior when running your application in Release mode. Before 5.0 (Swift 4.2.1 as of today and lower) this behavior is only running when in Debug mode.

Your application may fail in release mode if you ignored this error.

Consider this example:

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

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

What is the value of count, when the print(count) line is printed? Well I don't know either and the compiler gives unpredicatable results when you run this code. This isn't allowed in Swift 4.0 in debug mode and in Swift 5.0 it crashes even in runtime.

Source: https://swift.org/blog/swift-5-exclusivity/

In my case, Swift 4 actually uncovered a kind of bug that I wouldn't have noticed until I started calling a function from more than one place. My function was passed an inout global array and it was referencing both that parameter and the global name. When I changed the function to reference only the parameter, the "simultaneous access" error went away.

JonJ

Returning zero in the numberOfSections override function will cause this crash:

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

Simple solution - return 1 in the function above and then return 0 in the collectionView(_:numberOfItemsInSection:) function.

override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int
Tai Le

What I would do is change FetchOperation to a class instead of struct.

OhadM

The answers by @Mark Bridges and @geek1706 are good answers but I would like to add my 2 cents about this matter and give a general example.

As stated above this is a feature in Swift 4 SE-176.

The implementation should still be permitted to detect concurrent conflicting accesses, of course. Some programmers may wish to use an opt-in thread-safe enforcement mechanism instead, at least in some build configurations.

The exclusive access is an enforces that every write mutation of vars must be exclusive when accessing that variable. In a multithread environment, multiple threads accessing a shared var and one or more can modify it.

There's nothing like a good example: If we try to mutate a shared value in a multi-threaded environment using an abstraction (mutation occurs on a protocol type) between 2 objects and the Exclusive Access to Memory is on, our app will crash.

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()

Since we didn't state that the Abstraction protocol is class bound, during runtime, inside myMutatingFunc, the capture of self will be treated as struct even though we injected an actual class (MyClass).

Escaping variables generally require dynamic enforcement instead of static enforcement. This is because Swift cannot reason about when an escaping closure will be called and thus when the variable will be accessed.

The solution is to bound the Abstraction protocol to class:

protocol Abstraction: class
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!