Xcode UIView.init(frame:) must be used from main thread only

45,150

Solution 1

Xcode 9 has a new runtime Main Thread Checker that detects call to UIKit from a background thread and generate warnings.

I know its meant to generate warnings and not crash the app, but you can try disabling Main Thread Checker for your test target.

enter image description here

I tried this code in a sample project, the debugger paused at the issue (as it is supposed to), but the app didn't crash.

override func viewDidLoad() {
    super.viewDidLoad()

    DispatchQueue.global().async {
        let v = UIView(frame: .zero)
    }
}

Solution 2

Main Thread Entry

You can enter the main thread as follows

DispatchQueue.main.async { 
    // UIView usage
}

Solution 3

You can use this function

func downloadImage(urlstr: String, imageView: UIImageView) {
    let url = URL(string: urlstr)!
    let task = URLSession.shared.dataTask(with: url) { data, _, _ in
        guard let data = data else { return }
        DispatchQueue.main.async { // Make sure you're on the main thread here
            imageview.image = UIImage(data: data)
        }
    }
    task.resume()
}

How to use this function?

downloadImage(urlstr: "imageUrl", imageView: self.myImageView)
Share:
45,150
Lukas Würzburger
Author by

Lukas Würzburger

2022 - iOS, Server side Swift with Vapor 2021 - iOS, macOS (started SwiftUI) 2020 - iOS, macOS 2019 - iOS, macOS 2018 - iOS 2017 - iOS (started with Swift) 2016 - iOS 2015 - iOS 2014 - iOS 2013 - iOS 2012 - iOS, JSP 2011 - iOS, Web, JSP 2010 - iOS, Web 2009 - iPhoneOS, Web 2008 - Flex, iPhoneOS, Web, OSX (Objective-C) 2007 - Flash, Flex, Web, OSX (Objective-C) 2006 - Flash, Web 2005 - Flash, Web 2004 - Flash, Web

Updated on October 25, 2021

Comments

  • Lukas Würzburger
    Lukas Würzburger over 2 years

    I'm trying to render some views in background thread to not affect the main thread. That was never a problem before Xcode 9.

    DispatchQueue.global(qos: .background).async {
        let customView = UIView(frame: .zero)
        DispatchQueue.main.async {
            self.view.addSubview(customView)
        }
    }
    

    UIView.init(frame:) must be used from main thread only

    This error occurs in the second line.

    Update

    The Apple UIView Documentation actually says in the Threading Considerations section:

    Manipulations to your application’s user interface must occur on the main thread. Thus, you should always call the methods of the UIView class from code running in the main thread of your application. The only time this may not be strictly necessary is when creating the view object itself, but all other manipulations should occur on the main thread.