title: iOS 12 specific problem: Core Data External Storage Binary Data corruption
body: <p>I've spent the better part of a workday trying to solve this.</p>
  
  <p><strong>Background</strong></p>
  
  <p>I have a simple core data model, with books and reading sessions. The books have covers (images) that are stored as binary data with "Allows External Storage".</p>
  
  <p>On iOS 11.4 and below, everything works fine all the time. When I save a new session everything gets updated properly. </p>
  
  <p><strong>Problem</strong></p>
  
  <p>Since iOS 12, when I create a new reading session and link it to the book, about every <em>second</em> time, core data generates a SQL statement that also updates the book cover field, sometimes resulting in a bad reference (to file on disk) which often results in the cover being <em>nil</em> when restarting the app, and almost always creates duplicate copy of the cover on disk (as can be seen in Simulator's <code>_EXTERNAL_DATA</code> folder). </p>
  
  <p>In-memory context and objects remain correct though (and everything in the UI is therefore OK), until the app is restarted, then the cover is often <em>nil</em>.</p>
  
  <p><strong>iOS 12 specific</strong></p>
  
  <p>On iOS 12, I can deterministically reproduce the error in the simulator, on physical devices, and users have reported the error as well. I cannot reproduce the error on iOS 11.4, and no users reported the error previous to iOS 12.</p>
  
  <p><strong>Steps taken</strong></p>
  
  <ul>
  <li><p>I've enabled "<code>-com.apple.CoreData.ConcurrencyDebug 1</code>", so it shouldn't be that I'm accessing anything from the wrong queue. I've also enabled "<code>-com.apple.CoreData.SQLDebug 3</code>" so that I can see exactly what gets written.</p></li>
  <li><p>I've made sure the Book instance (and therefore the cover) is not modified by my code before the association with the new Session by checking <code>hasChanges</code>, just before I do <code>newSession.book = book</code> and <code>context.save()</code>.</p></li>
  <li><p>To be 100% sure I'm not touching the cover property on any thread I've short-circuited my getters and setters for that property. No improvement.</p></li>
  <li><p>I've tried using <code>objectID</code> to request an instance of the book just before the association and save. No improvement.</p></li>
  <li><p>I've even tried the option where the context keeps strong references to all objects, just to make sure it was not some kind of memory management issue. No improvement.</p></li>
  </ul>
  
  <p><strong>Question</strong></p>
  
  <p>Any ideas for next steps?</p>
  
  <p><strong>Status update</strong></p>
  
  <p>This is a defect in iOS 12. See accepted answer below for a detailed description of a resonable workaround.</p>