title: NSAttributedString from HTML on main thread behaves as if multithreading
body: <p>I'm converting some HTML to an <code>NSAttributedString</code> on the main thread (the way Apple tells you to). It takes some time and then it continues executing the rest of the block.</p>
  
  <p>Now, if another block is queued to run in the <strong>main</strong> thread too (e.g. after getting a response from an HTTP request), I would expect it to run <strong>after</strong> everything else is finished, but that's not what happens: they run in parallel as if they were on different threads. I did put asserts everywhere making sure it's on the main thread.</p>
  
  <p>I made an experiment "Single View App" project to test this, with a file containig a very long html string like <code>&lt;p&gt;lorem&lt;/p&gt; ipsum &lt;b&gt;dolor&lt;/b&gt; &lt;i&gt;&lt;u&gt;sit&lt;/u&gt; amet&lt;/i&gt;</code> and a view controller with the following code:</p>
  
  <pre class="lang-swift prettyprint-override"><code>import UIKit
  
  class ViewController: UIViewController {
  
      override func viewDidLoad() {
          super.viewDidLoad()
  
          dispatchStuff()
          for _ in 0..&lt;10 {
              // slowOperation()
              parseHTML()
          }
      }
  
      func dispatchStuff() {
          for i in 0..&lt;10 {
              let wait = Double(i) * 0.2
              DispatchQueue.main.asyncAfter(deadline: .now() + wait) {
                  assert(Thread.isMainThread, "not main thread!")
                  print(" dispatched after \(wait) seconds")
              }
          }
      }
  
      // just loads a big lorem ipsum full of html tags
      let html: String = {
          let filepath = Bundle.main.path(forResource: "test", ofType: "txt")!
          return try! String(contentsOfFile: filepath)
      }()
  
      var n = 0
      func slowOperation() {
          n += 1
          assert(Thread.isMainThread, "not main thread!")
          print("slowOperation \(n) START")
          var x = [0]
          for i in 0..&lt;10000 {
              x.removeAll()
              for j in 0..&lt;i {
                  x.append(j)
              }
          }
          print("slowOperation \(n) END")
          print("")
      }
  
      var m = 0
      func parseHTML() {
          m += 1
          assert(Thread.isMainThread, "not main thread!")
          print("parseHTML \(m) START")
          let options = [NSAttributedString.DocumentReadingOptionKey.documentType: NSAttributedString.DocumentType.html]
          let attrString = try! NSAttributedString(data: Data(html.utf8), options: options, documentAttributes: nil)
          print("parseHTML \(m) END")
          print("")
      }
  }
  
  </code></pre>
  
  <p>if you run it, this is what the console looks like:</p>
  
  <p><a href="https://i.stack.imgur.com/4zQDM.png" rel="noreferrer"><img src="https://i.stack.imgur.com/4zQDM.png" alt="parseHTML() uncommented"></a></p>
  
  <p>...all mixed together, that's the surprising (to me) behavior.</p>
  
  <p>But if in <code>viewDidLoad()</code> you comment the call to <code>parseHTML()</code> and uncomment <code>slowOperation()</code>, you'll get something like this instead:</p>
  
  <p><a href="https://i.stack.imgur.com/YbzxQ.png" rel="noreferrer"><img src="https://i.stack.imgur.com/YbzxQ.png" alt="slowOperation() uncommented"></a></p>
  
  <p>...which is what I'd expect. So, what's happening here? Is my understanding of how threads work horribly wrong?</p>