-[Uiapplication Delegate] Must Be Called from Main Thread Only

-[UIApplication delegate] must be called from main thread only

Just call it from the main thread like this.

Objective-C

dispatch_async(dispatch_get_main_queue(), ^{
[[UIApplication delegate] fooBar];
});

Swift

DispatchQueue.main.async {
YourUIControlMethod()
}

Reaching out to your app delegate like this, is a hint that your architecture could use a little cleanup.

You can call delegates from any thread you want. You only need to make sure you're on the main thread for UIKit calls.
Or that you're on the correct thread your CoreData objects expect. It all depends on the API contract your objects have.

WARNING-[UIApplication delegate] must be used from main thread only


+ (NSString *)accessTokenHashForDate:(NSDate *)date withParameters:(NSArray *)params{
__block NSString *accessToken = NULL;
if ([NSThread isMainThread]) {
accessToken = ((AppDelegate *)[[UIApplication sharedApplication] delegate]).loginProfile.accessToken;


} else {
dispatch_semaphore_t semaphore = dispatch_semaphore_create(1);
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
dispatch_async(dispatch_get_main_queue(), ^{
accessToken = ((AppDelegate *)[[UIApplication sharedApplication] delegate]).loginProfile.accessToken;
dispatch_semaphore_signal(semaphore);
});
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
dispatch_semaphore_signal(semaphore);
}
NSString *paramsStr = [params componentsJoinedByString:@""];
NSString *hashStr = [NSString stringWithFormat:@"%@%@%@%@", [CommonUtil IMEI], [date agileHashFormattedString], (!paramsStr) ? @"" : paramsStr, accessToken];
return hashStr;

}

UIApplication.delegate must be used from main thread only

With ref to this (-[UIApplication delegate] must be called from main thread only) in Swift (for your query resolution)

    DispatchQueue.main.async(execute: {

// Handle further UI related operations here....
//let ad = UIApplication.shared.delegate as! AppDelegate
//let context = ad.persistentContainer.viewContext

})

With edit: (Where is the correct place to declare ad and context? Should I declare these in my viewControllers in the main dispatch)

Place of variables (ad and context) declaration defines scope for it. You need to decide what would be scope of these variable. You can declare them Project or application level (Globally), class level or particular this function level.
If you want to use these variable in other ViewControllers then declare it globally or class level with public/open/internal access control.

   var ad: AppDelegate!    //or var ad: AppDelegate?
var context: NSManagedObjectContext! //or var context: NSManagedObjectContext?


DispatchQueue.main.async(execute: {

// Handle further UI related operations here....
ad = UIApplication.shared.delegate as! AppDelegate
context = ad.persistentContainer.viewContext

//or

//self.ad = UIApplication.shared.delegate as! AppDelegate
//self.context = ad.persistentContainer.viewContext

})

UIApplication applicationState must be used from main thread only


(Question changed from being about the main thread to how to define and call closures. This answer has changed to reflect that.)

[UIApplication applicationState] is most likely being called from
within the GeneralHelper.

The service helper is most likely making the network request on a
background thread.

So, to make sure GeneralHelper is called on the main thread, execute
it via a DispatchQueue.

(Also! You're not calling your completion handler, so we'll add that in too.)

func registerApi(path: String, player_id: Int, contest_id: Int, country_id: Int,  completion: ((Bool) -> Void)? = nil)
{
let helper = ServiceHelper.sharedInstance
let params = [
"api_token": Constants.USER_INFO["api_token"].rawValue,
"player_id": player_id,
"country_id": country_id,
"contest_id": contest_id
]
helper.sendRequest(path: "register-country", params: params, showSpinner: true) { (response, error) in
var success = true

if let error = error
{
// Do stuff on failure.
success = false
}
else
{
// Do stuff on success
}

// Call completion handler from 'registerApi'
completion?(success)
})
}

In your test, you can now add a parameter to test for success.

func testApiWorking()
{
let controller = WorldCupChooseCountryVC()

let expected = XCTestExpectation(description: "Some Countries to return")

controller.registerApi(path: "register-country", player_id: 163, contest_id: 1, country_id: 1) { success in
if success {
// Test success
} else {
// Test fail
}

expected.fulfill()
}

waitForExpectations(timeout: 30) { (_) -> Void in
}
}

Swift 4 ,must be used from main thread only warning

You're making this call on a background queue. To fix, try something like…

public var context: NSManagedObjectContext

DispatchQueue.main.async {

var appDelegate = UIApplication.shared.delegate as! AppDelegate
context = appDelegate.persistentContainer.viewContext
}

Although this is a pretty bad way to do this… you're using your App Delegate as a global variable (which we all know is bad!)

You should look at passing the managed object context from view controller to view controller…

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: 

(window?.rootViewController as? MyViewController)?.moc = persistentContainer.viewContext
}

and so on

Xcode Error for iOS app: [UI Application Delegate] must be called from main thread only

Use the main thread:

Swift:

DispatchQueue.main.async {

let appController = GetAppController()

}

Objective-C:

dispatch_async(dispatch_get_main_queue(), ^{
UnityAppController* appController = GetAppController();
});


Related Topics



Leave a reply



Submit