简体   繁体   English

如何诊断和解决 WCSession sendMessage(_:replyHandler:errorHandler:) 上的崩溃?

[英]How can I diagnose and resolve a crash on WCSession sendMessage(_:replyHandler:errorHandler:)?

I'm building a watchOS app that needs to periodically request information from a companion iPhone app to refresh a complication.我正在构建一个 watchOS 应用程序,它需要定期从配套的 iPhone 应用程序请求信息以刷新复杂功能。

To achieve this, I have a WKApplicationRefreshBackgroundTask that runs periodically.为了实现这一点,我有一个定期运行的WKApplicationRefreshBackgroundTask It uses sendMessage(_:replyHandler:errorHandler:) from WatchConnectivity to request the information from the iPhone app, process the reply, and update the complication.它采用sendMessage(_:replyHandler:errorHandler:)WatchConnectivity请求从iPhone应用程序的信息,处理回复,并更新并发症。

This works reliably for many users most of the time, however, I'm seeing Apple Watch crashes in Xcode related to sendMessage(_:replyHandler:errorHandler:) and I worry this is leading to missed complication updates for users.大多数情况下,这对许多用户来说都是可靠的,但是,我在 Xcode 中看到 Apple Watch 崩溃与sendMessage(_:replyHandler:errorHandler:) ,我担心这会导致用户错过复杂功能更新。 Some users have been complaining about the complication not updating, so I'm trying to identify if there are issues outside of the regular limitations on how often a complication can refresh in watchOS.一些用户一直在抱怨复杂功能没有更新,因此我试图确定是否存在复杂功能在 watchOS 中刷新频率的常规限制之外的问题。

Does anyone have any suggestions on how I can fix this issue?有没有人对我如何解决这个问题有任何建议? Or, do you have any suggestions for how I can better troubleshoot what's going wrong to cause the crash and figure out how to prevent it?或者,您对我如何更好地解决导致崩溃的问题并找出预防方法有什么建议吗?

I've included a full example of one of the crashes at the bottom, along with the code that handles the background task and the code that handles sending and receiving values from the paired iPhone.我在底部包含了一个崩溃的完整示例,以及处理后台任务的代码和处理从配对 iPhone 发送和接收值的代码。

I'm never sending a message without a replyHandler, so while others have seen problems because the delegate method for a message without a handler was not implemented on iPhone, I don't think that's the issue here.我从不发送没有 replyHandler 的消息,所以虽然其他人看到了问题,因为没有处理程序的消息的委托方法没有在 iPhone 上实现,但我不认为这是这里的问题。 To be safe I implemented the delegate method on iPhone as an empty method that does nothing.为了安全起见,我在 iPhone 上将委托方法实现为一个什么都不做的空方法。

UPDATE 30 January 2020: A friend suggested that maybe the issue is that the task is being marked complete by the 10 second timer while it's still in progress, causing a memory issue when something that's pending finishes, but wasn't sure what could be done about it. 2020 年 1 月 30 日更新:一位朋友建议,问题可能在于任务仍在进行中时被 10 秒计时器标记为已完成,从而在未完成的事情完成时导致内存问题,但不确定可以做什么关于它。 Maybe that's core to the issue here?也许这是这里问题的核心?

Here's my background refresh code from ExtensionDelegate :这是我来自ExtensionDelegate后台刷新代码:

func handle(_ backgroundTasks: Set<WKRefreshBackgroundTask>) {
    for task in backgroundTasks {
        switch task {
        case let backgroundTask as WKApplicationRefreshBackgroundTask:

            // set a timer in case it doesn't complete
            // the maximum allowed is 15 seconds, and then it crashes, so schedule the new task and mark complete after 10
            var timeoutTimer: Timer? = Timer.scheduledTimer(withTimeInterval: 10, repeats: false) { (timer) in

                self.scheduleBackgroundRefresh()

                backgroundTask.setTaskCompletedWithSnapshot(false)
            }

            // schedule the next refresh now in case the request crashes
            scheduleBackgroundRefresh()

            WatchConnectivityManager.shared.requestDataFromPhone()

            ComplicationManager.shared.reloadComplication()

            // as long as the expiration timer is valid, cancel the timer and set the task complete
            // otherwise, we'll assume the timer has fired and the task has been marked complete already
            // if it's marked complete again, that's a crash
            if let timerValid = timeoutTimer?.isValid, timerValid == true {
                timeoutTimer?.invalidate()
                timeoutTimer = nil
                backgroundTask.setTaskCompletedWithSnapshot(true)
            }

        default:
            // make sure to complete unhandled task types
            task.setTaskCompletedWithSnapshot(false)
        }
    }
}

private func scheduleBackgroundRefresh() {

    let fiveMinutesFromNow: Date = Date(timeIntervalSinceNow: 5 * 60)

    WKExtension.shared().scheduleBackgroundRefresh(withPreferredDate: fiveMinutesFromNow,
    userInfo: nil) { (error) in
        if let error = error {
            fatalError("\(error)")
        }
    }
}

And here is WatchConnectivityManager :这是WatchConnectivityManager

import Foundation
import WatchKit
import WatchConnectivity

class WatchConnectivityManager: NSObject {

    static let shared = WatchConnectivityManager()

    let session = WCSession.default

    private let receivedMessageQueue: OperationQueue = {
        let queue = OperationQueue()
        queue.maxConcurrentOperationCount = 1
        return queue
    }()

    private func process(messageOrUserInfo: [String : Any]) {

        receivedMessageQueue.addOperation {
            if let recievedValue = messageOrUserInfo["ValueFromPhone"] as? Int {
                DispatchQueue.main.async {
                    ViewModel.shared.valueFromPhone = recievedValue
                }
            }
        }
    }

    func requestDataFromPhone() {

        if session.activationState == .activated {

            let message: [String : Any] = ["Request" : true]

            let replyHandler: (([String : Any]) -> Void) = { reply in

                self.process(messageOrUserInfo: reply)
            }

            let errorHandler: ((Error) -> Void) = { error in
            }

            if session.isReachable {
                session.sendMessage(message,
                                    replyHandler: replyHandler,
                                    errorHandler: errorHandler)
            }

            // send a request to the iPhone as a UserInfo in case the message fails
            session.transferUserInfo(message)
        }
    }
}

extension WatchConnectivityManager: WCSessionDelegate {

    func session(_ session: WCSession,
                 activationDidCompleteWith activationState: WCSessionActivationState,
                 error: Error?) {

        if activationState == .activated {
            requestDataFromPhone()
        }
    }

    func session(_ session: WCSession,
                 didReceiveUserInfo userInfo: [String : Any])
    {
        process(messageOrUserInfo: userInfo)
    }
}

Example crash:示例崩溃:

Hardware Model:      Watch3,4
AppVariant:          1:Watch3,4:6
Code Type:           ARM (Native)
Role:                Non UI
Parent Process:      launchd [1]

OS Version:          Watch OS 6.1.1 (17S449)
Release Type:        User
Baseband Version:    n/a

Exception Type:  EXC_BAD_ACCESS (SIGSEGV)
Exception Subtype: KERN_INVALID_ADDRESS at 0x00000004
VM Region Info: 0x4 is not in any region.  Bytes before following region: 638972
      REGION TYPE              START - END     [ VSIZE] PRT/MAX SHRMOD  REGION DETAIL
      UNUSED SPACE AT START
--->  
      __TEXT                 0009c000-000ac000 [   64K] r-x/r-x SM=COW  ...x/App Name

Termination Signal: Segmentation fault: 11
Termination Reason: Namespace SIGNAL, Code 0xb
Terminating Process: exc handler [377]
Triggered by Thread:  9

Thread 0 name:
Thread 0:
0   libsystem_kernel.dylib          0x4381f864 semaphore_wait_trap + 8
1   libdispatch.dylib               0x436dac26 _dispatch_sema4_wait + 12 (lock.c:139)
2   libdispatch.dylib               0x436db09a _dispatch_semaphore_wait_slow + 104 (semaphore.c:132)
3   FrontBoardServices              0x46de503e -[FBSSceneSnapshotRequestHandle performRequestForScene:] + 408 (FBSSceneSnapshotRequestHandle.m:67)
4   FrontBoardServices              0x46de96ac -[FBSSceneSnapshotAction snapshotRequest:performWithContext:] + 218 (FBSSceneSnapshotAction.m:168)
5   FrontBoardServices              0x46da4320 -[FBSSceneSnapshotRequest performSnapshotWithContext:] + 292 (FBSSceneSnapshotRequest.m:65)
6   UIKitCore                       0x5ba6a000 __65-[UIApplication _performSnapshotsWithAction:forScene:completion:]_block_invoke_3 + 168 (UIApplication.m:7655)
7   FrontBoardServices              0x46de9568 -[FBSSceneSnapshotAction _executeNextRequest] + 244 (FBSSceneSnapshotAction.m:135)
8   FrontBoardServices              0x46de91e0 -[FBSSceneSnapshotAction executeRequestsWithHandler:completionHandler:expirationHandler:] + 244 (FBSSceneSnapshotAction.m:87)
9   UIKitCore                       0x5ba69f20 __65-[UIApplication _performSnapshotsWithAction:forScene:completion:]_block_invoke_2 + 238 (UIApplication.m:7650)
10  UIKitCore                       0x5ba69696 -[UIApplication _beginSnapshotSessionForScene:withSnapshotBlock:] + 772 (UIApplication.m:7582)
11  UIKitCore                       0x5ba69e16 __65-[UIApplication _performSnapshotsWithAction:forScene:completion:]_block_invoke + 112 (UIApplication.m:7648)
12  UIKitCore                       0x5b2c1110 -[UIScene _enableOverrideSettingsForActions:] + 40 (UIScene.m:1206)
13  UIKitCore                       0x5b2c1330 -[UIScene _performSystemSnapshotWithActions:] + 112 (UIScene.m:1230)
14  UIKitCore                       0x5ba69b90 -[UIApplication _performSnapshotsWithAction:forScene:completion:] + 382 (UIApplication.m:7647)
15  UIKitCore                       0x5be89586 __98-[_UISceneSnapshotBSActionsHandler _respondToActions:forFBSScene:inUIScene:fromTransitionCont... + 146 (_UISceneSnapshotBSActionsHandler.m:54)
16  UIKitCore                       0x5ba68fd4 _runAfterCACommitDeferredBlocks + 274 (UIApplication.m:3038)
17  UIKitCore                       0x5ba5b3da _cleanUpAfterCAFlushAndRunDeferredBlocks + 198 (UIApplication.m:3016)
18  UIKitCore                       0x5ba82702 _afterCACommitHandler + 56 (UIApplication.m:3068)
19  CoreFoundation                  0x43b63644 __CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__ + 18 (CFRunLoop.c:1758)
20  CoreFoundation                  0x43b5f43c __CFRunLoopDoObservers + 350 (CFRunLoop.c:1868)
21  CoreFoundation                  0x43b5f956 __CFRunLoopRun + 1150 (CFRunLoop.c:2910)
22  CoreFoundation                  0x43b5f23a CFRunLoopRunSpecific + 370 (CFRunLoop.c:3192)
23  GraphicsServices                0x46973cd0 GSEventRunModal + 96 (GSEvent.c:2246)
24  UIKitCore                       0x5ba61580 UIApplicationMain + 1730 (UIApplication.m:4773)
25  libxpc.dylib                    0x438fbcf0 _xpc_objc_main.cold.3 + 152
26  libxpc.dylib                    0x438eca34 _xpc_objc_main + 184 (main.m:126)
27  libxpc.dylib                    0x438ee934 xpc_main + 110 (init.c:1568)
28  Foundation                      0x443f3156 -[NSXPCListener resume] + 172 (NSXPCListener.m:276)
29  PlugInKit                       0x4b58b26c -[PKService run] + 384 (PKService.m:165)
30  WatchKit                        0x52e9dafe WKExtensionMain + 62 (main.m:19)
31  libdyld.dylib                   0x43715e82 start + 2

Thread 1 name:
Thread 1:
0   libsystem_kernel.dylib          0x4381f814 mach_msg_trap + 20
1   libsystem_kernel.dylib          0x4381eece mach_msg + 42 (mach_msg.c:103)
2   CoreFoundation                  0x43b63946 __CFRunLoopServiceMachPort + 152 (CFRunLoop.c:2575)
3   CoreFoundation                  0x43b5f9de __CFRunLoopRun + 1286 (CFRunLoop.c:2931)
4   CoreFoundation                  0x43b5f23a CFRunLoopRunSpecific + 370 (CFRunLoop.c:3192)
5   Foundation                      0x443bf398 -[NSRunLoop(NSRunLoop) runMode:beforeDate:] + 180 (NSRunLoop.m:374)
6   Foundation                      0x443bf2b4 -[NSRunLoop(NSRunLoop) runUntilDate:] + 76 (NSRunLoop.m:421)
7   UIKitCore                       0x5badf012 -[UIEventFetcher threadMain] + 140 (UIEventFetcher.m:637)
8   Foundation                      0x444c1b60 __NSThread__start__ + 708 (NSThread.m:724)
9   libsystem_pthread.dylib         0x438ad1ac _pthread_start + 130 (pthread.c:896)
10  libsystem_pthread.dylib         0x438b3f28 thread_start + 20

Thread 2 name:
Thread 2:
0   libsystem_kernel.dylib          0x43836d04 __psynch_cvwait + 24
1   libsystem_pthread.dylib         0x438b02c2 _pthread_cond_wait + 496 (pthread_cond.c:591)
2   libsystem_pthread.dylib         0x438aca4a pthread_cond_wait + 38 (pthread_cancelable.c:558)
3   Foundation                      0x444381f0 -[NSOperation waitUntilFinished] + 446 (NSOperation.m:737)
4   Foundation                      0x444a5302 __NSOPERATIONQUEUE_IS_WAITING_ON_AN_OPERATION__ + 22 (NSOperation.m:2610)
5   Foundation                      0x444222ee -[NSOperationQueue addOperations:waitUntilFinished:] + 128 (NSOperation.m:2618)
6   WatchConnectivity               0x53f9871e __47-[WCSession handleUserInfoResultWithPairingID:]_block_invoke.491 + 540 (WCSession.m:1440)
7   WatchConnectivity               0x53fa5608 -[WCFileStorage enumerateUserInfoResultsWithBlock:] + 1564 (WCFileStorage.m:505)
8   WatchConnectivity               0x53f984ca __47-[WCSession handleUserInfoResultWithPairingID:]_block_invoke_2 + 284 (WCSession.m:1430)
9   Foundation                      0x444a4794 __NSBLOCKOPERATION_IS_CALLING_OUT_TO_A_BLOCK__ + 10 (NSOperation.m:1541)
10  Foundation                      0x443d2f7a -[NSBlockOperation main] + 74 (NSOperation.m:1560)
11  Foundation                      0x444a63e2 __NSOPERATION_IS_INVOKING_MAIN__ + 22 (NSOperation.m:2184)
12  Foundation                      0x443d2b96 -[NSOperation start] + 578 (NSOperation.m:2201)
13  Foundation                      0x444a6b7c __NSOPERATIONQUEUE_IS_STARTING_AN_OPERATION__ + 22 (NSOperation.m:2215)
14  Foundation                      0x444a6798 __NSOQSchedule_f + 134 (NSOperation.m:2226)
15  libdispatch.dylib               0x436d9846 _dispatch_call_block_and_release + 10 (init.c:1408)
16  libdispatch.dylib               0x436da8b8 _dispatch_client_callout + 6 (object.m:495)
17  libdispatch.dylib               0x436dc6f8 _dispatch_continuation_pop + 330 (inline_internal.h:2484)
18  libdispatch.dylib               0x436dc08c _dispatch_async_redirect_invoke + 520 (queue.c:803)
19  libdispatch.dylib               0x436e6eac _dispatch_root_queue_drain + 540 (inline_internal.h:2525)
20  libdispatch.dylib               0x436e73e0 _dispatch_worker_thread2 + 98 (queue.c:6628)
21  libsystem_pthread.dylib         0x438aecd2 _pthread_wqthread + 158 (pthread.c:2364)
22  libsystem_pthread.dylib         0x438b3f10 start_wqthread + 20

Thread 3:
0   libsystem_pthread.dylib         0x438b3efc start_wqthread + 0

Thread 4:
0   libsystem_pthread.dylib         0x438b3efc start_wqthread + 0

Thread 5:
0   libsystem_pthread.dylib         0x438b3efc start_wqthread + 0

Thread 6 name:
Thread 6:
0   libsystem_kernel.dylib          0x43838c6c kevent_qos + 24
1   libdispatch.dylib               0x436f2b74 _dispatch_kq_poll + 204 (event_kevent.c:736)
2   libdispatch.dylib               0x436f280a _dispatch_kq_drain + 96 (event_kevent.c:809)
3   libdispatch.dylib               0x436f2196 _dispatch_event_loop_poke + 162 (event_kevent.c:1918)
4   libdispatch.dylib               0x436e32b8 _dispatch_mgr_queue_push + 110 (queue.c:5857)
5   WatchConnectivity               0x53f9aa26 -[WCSession createAndStartTimerOnWorkQueueWithHandler:] + 150 (WCSession.m:1803)
6   WatchConnectivity               0x53f90790 -[WCSession onqueue_sendMessageData:replyHandler:errorHandler:dictionaryMessage:] + 382 (WCSession.m:674)
7   WatchConnectivity               0x53f901da __51-[WCSession sendMessage:replyHandler:errorHandler:]_block_invoke.256 + 190 (WCSession.m:630)
8   Foundation                      0x444a4794 __NSBLOCKOPERATION_IS_CALLING_OUT_TO_A_BLOCK__ + 10 (NSOperation.m:1541)
9   Foundation                      0x443d2f7a -[NSBlockOperation main] + 74 (NSOperation.m:1560)
10  Foundation                      0x444a63e2 __NSOPERATION_IS_INVOKING_MAIN__ + 22 (NSOperation.m:2184)
11  Foundation                      0x443d2b96 -[NSOperation start] + 578 (NSOperation.m:2201)
12  Foundation                      0x444a6b7c __NSOPERATIONQUEUE_IS_STARTING_AN_OPERATION__ + 22 (NSOperation.m:2215)
13  Foundation                      0x444a6798 __NSOQSchedule_f + 134 (NSOperation.m:2226)
14  libdispatch.dylib               0x436e4c02 _dispatch_block_async_invoke2 + 80 (queue.c:525)
15  libdispatch.dylib               0x436da8b8 _dispatch_client_callout + 6 (object.m:495)
16  libdispatch.dylib               0x436dc6f8 _dispatch_continuation_pop + 330 (inline_internal.h:2484)
17  libdispatch.dylib               0x436dc08c _dispatch_async_redirect_invoke + 520 (queue.c:803)
18  libdispatch.dylib               0x436e6eac _dispatch_root_queue_drain + 540 (inline_internal.h:2525)
19  libdispatch.dylib               0x436e73e0 _dispatch_worker_thread2 + 98 (queue.c:6628)
20  libsystem_pthread.dylib         0x438aecd2 _pthread_wqthread + 158 (pthread.c:2364)
21  libsystem_pthread.dylib         0x438b3f10 start_wqthread + 20

Thread 7:
0   libsystem_pthread.dylib         0x438b3efc start_wqthread + 0

Thread 8:
0   libsystem_pthread.dylib         0x438b3efc start_wqthread + 0

Thread 9 name:
Thread 9 Crashed:
0   libdispatch.dylib               0x436eacec dispatch_channel_cancel + 6 (source.c:1020)
1   WatchConnectivity               0x53f909c6 __81-[WCSession onqueue_sendMessageData:replyHandler:errorHandler:dictionaryMessage:]_block_invoke + 42 (WCSession.m:675)
2   libdispatch.dylib               0x436da8b8 _dispatch_client_callout + 6 (object.m:495)
3   libdispatch.dylib               0x436dc6f8 _dispatch_continuation_pop + 330 (inline_internal.h:2484)
4   libdispatch.dylib               0x436ea81e _dispatch_source_invoke + 1758 (source.c:568)
5   libdispatch.dylib               0x436e6eac _dispatch_root_queue_drain + 540 (inline_internal.h:2525)
6   libdispatch.dylib               0x436e73e0 _dispatch_worker_thread2 + 98 (queue.c:6628)
7   libsystem_pthread.dylib         0x438aecd2 _pthread_wqthread + 158 (pthread.c:2364)
8   libsystem_pthread.dylib         0x438b3f10 start_wqthread + 20

Thread 10:
0   libsystem_pthread.dylib         0x438b3efc start_wqthread + 0

Thread 11:
0   libsystem_pthread.dylib         0x438b3efc start_wqthread + 0

Thread 9 crashed with ARM Thread State (32-bit):
    r0: 0x00000000    r1: 0x80000000      r2: 0x00000001      r3: 0x7fffffff
    r4: 0x16548f40    r5: 0x00000000      r6: 0x00000110      r7: 0x3f057e58
    r8: 0x00000000    r9: 0x00000000     r10: 0x00000000     r11: 0x00401600
    ip: 0x66e39628    sp: 0x3f057e30      lr: 0x53f909c7      pc: 0x436eacec
  cpsr: 0x80000030

I assume your friend is right:我认为你的朋友是对的:
When you set your background task as complete, the system will suspend your app, see here .当您将后台任务设置为完成时,系统将暂停您的应用程序,请参阅此处
And the system can purge suspended apps without warning, see here .并且系统可以在没有警告的情况下清除暂停的应用程序,请参见此处
So if this happens, replyHandler or errorHandler cannot be called, and the app crashes.因此,如果发生这种情况,则无法调用replyHandlererrorHandler ,并且应用程序崩溃。
You can therefore not rely on sendMessage to wake up the iOS app and to call replyHandler in time.因此,您不能依赖sendMessage来唤醒 iOS 应用程序并及时调用replyHandler
I suggest that you initialize the transfer of complication data on iOS.我建议你在iOS上初始化复杂数据的传输。 To do so regularly, you could use silent push notifications that wake up your iOS app, and send new complication data using transferCurrentComplicationUserInfo(_:) see here .要定期执行此操作,您可以使用静默推送通知唤醒您的 iOS 应用,并使用transferCurrentComplicationUserInfo(_:)发送新的复杂数据,请参见此处 This userInfo is received even if your watch app is not running, and the complication data can be updated as required.即使您的手表应用程序未运行,也会收到此userInfo ,并且可以根据需要更新并发症数据。

EDIT:编辑:

While my solution above might work, there might be a much simpler solution:虽然我上面的解决方案可能有效,但可能有一个更简单的解决方案:

Maybe it is not required to update your ViewModel in respond to sendMessage , only the complications.也许不需要更新您的ViewModel以响应sendMessage ,只有复杂性。 If so, you could simply use sendMessage with replyHandler and errorHandler set to nil .如果是这样,您可以简单地使用sendMessage并将replyHandlererrorHandler设置为nil
sendMessage is guaranteed to wake up the iOS app in the future, even when the watchOS app is already inactive. sendMessage保证在未来唤醒 iOS 应用程序,即使 watchOS 应用程序已经处于非活动状态。 The iOS app could then send complication data, and these would be displayed immediately.然后 iOS 应用程序可以发送复杂数据,这些数据将立即显示。
Additionally, the iOS app could send the userInfo that updates your ViewModel as application context.此外,iOS 应用程序可以将更新您的ViewModeluserInfo作为应用程序上下文发送。 It would then be available when the watchOS app becomes active again, and you can update the ViewModel .当 watchOS 应用程序再次激活时,它将可用,您可以更新ViewModel
If this fits to your use case, you could simply remove the timer and complete the background task immediately after sendMessage .如果这适合您的用例,您可以简单地删除计时器并在sendMessage之后立即完成后台任务。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 WCSession sendMessage:replyHandler错误代码7014(WCErrorCodeDeliveryFailed) - WCSession sendMessage:replyHandler error code 7014 (WCErrorCodeDeliveryFailed) WCSession sendMessage errorHandler多次调用 - WCSession sendMessage errorHandler called multiple times WatchOS2 WCSession WCSession可以在WatchKitExtension中拥有多少个代理? - WatchOS2 WCSession How many delegates can the WCSession have in WatchKitExtension? WatchConnectivity WCSession.sendMessage的性能 - Performance of WatchConnectivity WCSession.sendMessage 如何使用AppDelegate的“ [WCSession defaultSession] sendMessage”同时在watchOS 2的特定接口控制器中接收消息 - How to receive message in a particular interface controller of watchOS 2 while using “[WCSession defaultSession] sendMessage” from AppDelegate WCSession.sendMessage工作50/50 - WCSession.sendMessage works 50/50 WCSession:使用transferUserInfo或sendMessage的最佳方法? - WCSession: Best way of using transferUserInfo or sendMessage? WatchConnectivity sendMessage:replyHandler: 当链接器有标志 -ObjC 时不起作用 - WatchConnectivity sendMessage:replyHandler: don't work when linker have flag -ObjC WatchOS2 WCSession sendMessage不会在后台唤醒iPhone - WatchOS2 WCSession sendMessage doesn't wake iPhone on background 从2.1升级到2.2后,WCSession sendmessage的速度慢了两倍 - WCSession sendmessage is twice as slow after updating from 2.1 to 2.2
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM