在iOS开发中,NotificationCenter
是经常会用到的,我一般发通知会自己封装一个方法,在主线程中进行发送。
func postNotification(name: NSNotification.Name, object: Any?, _ userInfo: [AnyHashable : Any]? = nil){
DispatchQueue.main.async {
NotificationCenter.default.post(name: name, object: object, userInfo: userInfo)
}
}
因为我的想法是在接收到通知后有可能会操作UI,如果某次发送通知是在子线程(例如网络请求,请求到特定数据后发出通知),接收到通知更新UI,会造成程序崩溃。为了验证这个想法,我做了一个简单的测试。
测试
首先在子线程中发送通知,在接收到通知后更新界面中label的显示
运行程序,结果是程序不会崩溃,但是界面并不会更新任何信息,控制台打印信息如下:
=================================================================
Main Thread Checker: UI API called on a background thread: -[UILabel setText:]
PID: 1248, TID: 222437, Thread name: (none), Queue name: com.apple.root.default-qos, QoS: 0
Backtrace:
4 testnoti 0x000000010420bc68 _T08testnoti14ViewControllerC8updateUIyyF + 200
5 testnoti 0x000000010420be44 _T08testnoti14ViewControllerC8updateUIyyFTo + 40
6 CoreFoundation 0x00000001c3a8b068 <redacted> + 20
7 CoreFoundation 0x00000001c3a8b034 <redacted> + 64
8 CoreFoundation 0x00000001c3a8a720 <redacted> + 392
9 CoreFoundation 0x00000001c3a8a3cc <redacted> + 96
10 CoreFoundation 0x00000001c3afe060 <redacted> + 1404
11 CoreFoundation 0x00000001c39da164 _CFXNotificationPost + 384
12 Foundation 0x00000001c44583b4 <redacted> + 68
13 testnoti 0x000000010420b9d8 _T08testnoti14ViewControllerC11viewDidLoadyyFyycfU_ + 512
14 testnoti 0x000000010420ba2c _T0Ix_IyB_TR + 48
15 libdispatch.dylib 0x0000000105021338 _dispatch_client_callout + 16
16 libdispatch.dylib 0x000000010502c5e4 _dispatch_continuation_pop + 528
17 libdispatch.dylib 0x000000010502314c _dispatch_source_invoke + 1880
18 libdispatch.dylib 0x000000010502bef4 _dispatch_queue_override_invoke + 448
19 libdispatch.dylib 0x00000001050393ac _dispatch_root_queue_drain + 376
20 libdispatch.dylib 0x0000000105039db0 _dispatch_worker_thread2 + 156
21 libsystem_pthread.dylib 0x00000001c37155c0 _pthread_wqthread + 480
22 libsystem_pthread.dylib 0x00000001c371536c start_wqthread + 4
2018-07-03 14:14:48.830508+0800 testnoti[1248:222437] [reports] Main Thread Checker: UI API called on a background thread: -[UILabel setText:]
PID: 1248, TID: 222437, Thread name: (none), Queue name: com.apple.root.default-qos, QoS: 0
Backtrace:
4 testnoti 0x000000010420bc68 _T08testnoti14ViewControllerC8updateUIyyF + 200
5 testnoti 0x000000010420be44 _T08testnoti14ViewControllerC8updateUIyyFTo + 40
6 CoreFoundation 0x00000001c3a8b068 <redacted> + 20
7 CoreFoundation 0x00000001c3a8b034 <redacted> + 64
8 CoreFoundation 0x00000001c3a8a720 <redacted> + 392
9 CoreFoundation 0x00000001c3a8a3cc <redacted> + 96
10 CoreFoundation 0x00000001c3afe060 <redacted> + 1404
11 CoreFoundation 0x00000001c39da164 _CFXNotificationPost + 384
12 Foundation 0x00000001c44583b4 <redacted> + 68
13 testnoti 0x000000010420b9d8 _T08testnoti14ViewControllerC11viewDidLoadyyFyycfU_ + 512
14 testnoti 0x000000010420ba2c _T0Ix_IyB_TR + 48
15 libdispatch.dylib 0x0000000105021338 _dispatch_client_callout + 16
16 libdispatch.dylib 0x000000010502c5e4 _dispatch_continuation_pop + 528
17 libdispatch.dylib 0x000000010502314c _dispatch_source_invoke + 1880
18 libdispatch.dylib 0x000000010502bef4 _dispatch_queue_override_invoke + 448
19 libdispatch.dylib 0x00000001050393ac _dispatch_root_queue_drain + 376
20 libdispatch.dylib 0x0000000105039db0 _dispatch_worker_thread2 + 156
21 libsystem_pthread.dylib 0x00000001c37155c0 _pthread_wqthread + 480
22 libsystem_pthread.dylib 0x00000001c371536c start_wqthread + 4
2018-07-03 14:14:56.519094+0800 testnoti[1248:222437] [Animation] +[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 0x00000001efeaebbc <redacted> + 136
1 libdispatch.dylib 0x0000000105021338 _dispatch_client_callout + 16
2 libdispatch.dylib 0x0000000105022150 dispatch_once_f + 120
3 UIKitCore 0x00000001efeaeb30 <redacted> + 100
4 UIKitCore 0x00000001efeaecb8 <redacted> + 92
5 UIKitCore 0x00000001f01278f0 <redacted> + 372
6 UIKitCore 0x00000001f01279e4 <redacted> + 32
7 QuartzCore 0x00000001c8272c60 <redacted> + 332
8 QuartzCore 0x00000001c81d34fc <redacted> + 328
9 QuartzCore 0x00000001c8200d74 <redacted> + 596
10 QuartzCore 0x00000001c8201514 <redacted> + 252
11 libsystem_pthread.dylib 0x00000001c3715a58 <redacted> + 584
12 libsystem_pthread.dylib 0x00000001c37157e8 <redacted> + 80
13 libsystem_pthread.dylib 0x00000001c3721058 <redacted> + 80
14 libsystem_pthread.dylib 0x00000001c3715550 _pthread_wqthread + 368
15 libsystem_pthread.dylib 0x00000001c371536c start_wqthread + 4
)
很明显是在告诉我们,操作UI线程错误,必须在主线程操作,在代码中Xcode也给出了提示:
现在改动一下代码,使通知在主线程发送
运行程序,5秒后界面得到及时更新,所以在使用通知的时候,需要确定接收通知是否会进行UI操作,如果需要操作UI,则在主线程发送通知(封装后比较方便)或者接收通知后在主线程更新UI。