masalibの日記

システム開発、運用と猫の写真ブログです

【Objective-C】UI操作(特にSegueの実行)はメインスレッド(MainThread)しないといけない

私はobjective-cの初心者です。デバックしならがら引き継ぎしたソースを解析しています 以下のエラーがでました

パターン1

 [self performSegueWithIdentifier:@"XXXXXView" sender:nil];
-[UIViewController performSegueWithIdentifier:sender:] must be used from main thread only

このエラーは、UI操作(特にSegueの実行)はメインスレッド(MainThread)で行う必要があるということを示しています。iOSアプリケーションでは、UI操作は常にメインスレッドで行われる必要があります。

エラーメッセージ [self performSegueWithIdentifier:@"XXXXXView" sender:nil]; がメインスレッド以外から呼ばれている可能性があります。これを修正するには、次のようにしてください:

メインスレッドでUI操作を行う UI操作を行う部分をメインスレッドで実行するように修正します。Objective-Cでは、次のようにdispatch_asyncを使って行うことができます:

   dispatch_async(dispatch_get_main_queue(), ^{
       [self performSegueWithIdentifier:@"XXXXXView" sender:nil];
   });

このエラーはなるほど・・・と思った

パターン2

以下のエラーはまじで意味がわからない

Main Thread Checker: UI API called on a background thread: -[UIViewController performSegueWithIdentifier:sender:]
PID: 12095, TID: 4733842, Thread name: (none), Queue name: com.apple.root.default-qos, QoS: 0
Backtrace:
4   ApplicationName                      0x0000000104971b70 -[XXXXViewController didFinishChkPrice] + 72
5   ApplicationName                      0x000000010497b860 -[StoreKitManager finishChkPrice] + 116
6   ApplicationName                      0x000000010497a70c -[StoreKitManager productsRequest:didReceiveResponse:] + 376
7   StoreKit                            0x00000001baecf3b8 F2CA7CCD-9558-3093-AADB-3353C09DD93C + 115640
8   libdispatch.dylib                   0x0000000105958b98 _dispatch_call_block_and_release + 32
9   libdispatch.dylib                   0x000000010595a7bc _dispatch_client_callout + 20
10  libdispatch.dylib                   0x000000010595d30c _dispatch_queue_override_invoke + 1056
11  libdispatch.dylib                   0x000000010596eae4 _dispatch_root_queue_drain + 404
12  libdispatch.dylib                   0x000000010596f4d8 _dispatch_worker_thread2 + 188
13  libsystem_pthread.dylib             0x00000001eea138f8 _pthread_wqthread + 228
14  libsystem_pthread.dylib             0x00000001eea100cc start_wqthread + 8
Main Thread Checker: UI API called on a background thread: -[UIViewController performSegueWithIdentifier:sender:]
PID: 12095, TID: 4733842, Thread name: (none), Queue name: com.apple.root.default-qos, QoS: 0
Backtrace:
4   ApplicationName                      0x0000000104971b70 -[XXXXXXXXViewController didFinishChkPrice] + 72
5   ApplicationName                      0x000000010497b860 -[StoreKitManager finishChkPrice] + 116
6   ApplicationName                      0x000000010497a70c -[StoreKitManager productsRequest:didReceiveResponse:] + 376
7   StoreKit                            0x00000001baecf3b8 F2CA7CCD-9558-3093-AADB-3353C09DD93C + 115640
8   libdispatch.dylib                   0x0000000105958b98 _dispatch_call_block_and_release + 32
9   libdispatch.dylib                   0x000000010595a7bc _dispatch_client_callout + 20
10  libdispatch.dylib                   0x000000010595d30c _dispatch_queue_override_invoke + 1056
11  libdispatch.dylib                   0x000000010596eae4 _dispatch_root_queue_drain + 404
12  libdispatch.dylib                   0x000000010596f4d8 _dispatch_worker_thread2 + 188
13  libsystem_pthread.dylib             0x00000001eea138f8 _pthread_wqthread + 228
14  libsystem_pthread.dylib             0x00000001eea100cc start_wqthread + 8

+[UIView setAnimationsEnabled:] being called from a background thread. Performing any operation from a background thread on UIView or a subclass is not supported and may result in unexpected and insidious behavior. trace=(
    0   UIKitCore                           0x0000000195048740 1741FA37-4E53-371E-8DAE-D611AAB0043D + 19457856
    1   libdispatch.dylib                   0x000000010595a7bc _dispatch_client_callout + 20
    2   libdispatch.dylib                   0x000000010595c34c _dispatch_once_callout + 140
    3   UIKitCore                           0x0000000194dcf454 1741FA37-4E53-371E-8DAE-D611AAB0043D + 16864340
    4   UIKitCore                           0x0000000194dcf37c 1741FA37-4E53-371E-8DAE-D611AAB0043D + 16864124
    5   UIKitCore                           0x000000019469d40c 1741FA37-4E53-371E-8DAE-D611AAB0043D + 9319436
    6   Project                      0x0000000104971b70 -[XXXXViewController didFinishChkPrice] + 72
    7   ProjectName                      0x000000010497b860 -[StoreKitManager finishChkPrice] + 116
    8   Application                      0x000000010497a70c -[StoreKitManager productsRequest:didReceiveResponse:] + 376
    9   StoreKit                            0x00000001baecf3b8 F2CA7CCD-9558-3093-AADB-3353C09DD93C + 115640
    10  libdispatch.dylib                   0x0000000105958b98 _dispatch_call_block_and_release + 32
    11  libdispatch.dylib                   0x000000010595a7bc _dispatch_client_callout + 20
    12  libdispatch.dylib                   0x000000010595d30c _dispatch_queue_override_invoke + 1056
    13  libdispatch.dylib                   0x000000010596eae4 _dispatch_root_queue_drain + 404
    14  libdispatch.dylib                   0x000000010596f4d8 _dispatch_worker_thread2 + 188
    15  libsystem_pthread.dylib             0x00000001eea138f8 _pthread_wqthread + 228
    16  libsystem_pthread.dylib             0x00000001eea100cc start_wqthread + 8
)
Unsupported enumeration of UIWindowScene windows on non-main thread.
*** Assertion failure in -[UIApplication _performAfterCATransactionCommitsWithLegacyRunloopObserverBasedTiming:block:], UIApplication.m:3246
*** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Call must be made on main thread'
*** First throw call stack:
(0x191bbcf20 0x189a42018 0x1910c3868 0x1940b4d28 0x193ff19e8 0x193ff1518 0x194179830 0x1941786e0 0x1941ce440 0x1946a58f0 0x194dc97c0 0x194dcf45c 0x194dcf37c 0x19469d40c 0x104971b70 0x10497b860 0x10497a70c 0x1baecf3b8 0x105958b98 0x10595a7bc 0x10595d30c 0x10596eae4 0x10596f4d8 0x1eea138f8 0x1eea100cc)
libc++abi: terminating due to uncaught exception of type NSException

まじでわからん・・・ よくわらないエラーがでるのですが

このエラーの最初に「Main Thread Checker: UI API called on a background thread: -[UIViewController performSegueWithIdentifier:sender:]」 とあります。これは、UI APIがバックグラウンドスレッドで呼ばれていることを示しています。」

・・・?

これも同じ

XXXXViewControllerにある

       [self performSegueWithIdentifier:@"XXXXXView" sender:nil];

↓

   dispatch_async(dispatch_get_main_queue(), ^{
       [self performSegueWithIdentifier:@"XXXXXView" sender:nil];
   });

に修正したらなおった

エラーを調査した結果

performSegueWithIdentifier: メソッドなどのUI操作は、 常にメインスレッドで行うようにするのが推奨されています。iOSのUIはメインスレッドでのみ安全に操作できるため、 他のスレッドからUIを直接操作すると予期しない問題が発生することがあります。

したがって、以下の場合には dispatch_async(dispatch_get_main_queue() を使用してメインスレッドで実行するようにします:

  1. 非同期処理の完了後にUIを更新する場合: バックグラウンドでデータを取得し、その結果をUIに反映させる場合、非同期処理の完了後にメインスレッドでUI操作を行う必要があります。

  2. イベントハンドラ内でUIを更新する場合: ボタンのタップなどのイベントハンドラ内でUI操作を行う場合、その処理もメインスレッドで行う必要があります。

  3. セグエの実行など: performSegueWithIdentifier: やその他のUI遷移を行うメソッドも、メインスレッドで呼び出す必要があります。

通常の場合、UI関連の操作はすべてメインスレッドで 行うようにすることで、アプリの安定性とパフォーマンスを保つことができます。

古いソースはこの画面遷移の部分を修正するのが必須だね