How can I connect through HTTP in Kotlin/Native iOS development? - ios

I tried to get a web page in Kotlin/Native with iOS platform, but it didn't work.
Please tell me where is the problem.
I created the project with Gradle and build.gradle contains:
plugins {
id 'kotlin-multiplatform' version '1.3.21'
}
Here are the codes.
package sample
fun main(args: Array<String>) {
println(WebGateway.get("https://www.google.com/"))
}
package sample
import platform.Foundation.*
import platform.darwin.*
actual object WebGateway {
actual fun get(urlString: String): String {
val semaphore = dispatch_semaphore_create(0)
var components = NSURLComponents(urlString)
val url = components.URL
var result: String = ""
val config = NSURLSessionConfiguration.defaultSessionConfiguration()
config.waitsForConnectivity = true
config.timeoutIntervalForResource = 300.0
val session = NSURLSession.sessionWithConfiguration(
config, null, NSOperationQueue.mainQueue()
)
val task = session
.dataTaskWithURL(url!!) { nsData: NSData?, nsurlResponse: NSURLResponse?, nsError: NSError? ->
nsData?.run { result = toString() }
println(nsData)
dispatch_semaphore_signal(semaphore);
}
task.resume()
session.finishTasksAndInvalidate()
NSOperationQueue.mainQueue().waitUntilAllOperationsAreFinished()
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER)
return result
}
}
After building the application, main.kexe was created.
I expected the Google web page HTML is printed in standard output by executing the application.
But the actual is:
% ./main.kexe
It doesn't show anything.
The program stops at dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER).
After executing the application, task.state became NSURLSessionTaskStateCompleted, but the program doesn't show anything or finish.
When I changed the session to NSURLSession.sessionWithConfiguration(config), I got the following output.
% ./main.kexe
Uncaught Kotlin exception: kotlin.native.IncorrectDereferenceException: illegal attempt to access non-shared sample.WebGateway.$<anonymous>$FUNCTION_REFERENCE$0#f6f058e8 from other thread
at 0 main.kexe 0x000000010039c3c3 ThrowIllegalObjectSharingException + 595
at 1 main.kexe 0x00000001003b9d6d -[KotlinObjectHolder ref] + 141
at 2 main.kexe 0x00000001003c9524 platform_Foundation_kniBridge11046 + 148
at 3 main.kexe 0x00000001003ca18c __platform_Foundation_kniBridge11045_block_invoke + 108
at 4 CFNetwork 0x00007fff4cd80763 __75-[__NSURLSessionLocal taskForClass:request:uploadFile:bodyData:completion:]_block_invoke + 19
at 5 CFNetwork 0x00007fff4cd8016c __49-[__NSCFLocalSessionTask _task_onqueue_didFinish]_block_invoke + 172
at 6 Foundation 0x00007fff50243a47 __NSBLOCKOPERATION_IS_CALLING_OUT_TO_A_BLOCK__ + 7
at 7 Foundation 0x00007fff5024394e -[NSBlockOperation main] + 68
at 8 Foundation 0x00007fff50218f7a -[__NSOperationInternal _start:] + 686
at 9 Foundation 0x00007fff5024367f __NSOQSchedule_f + 227
at 10 libdispatch.dylib 0x00007fff7aef3d4f _dispatch_call_block_and_release + 12
at 11 libdispatch.dylib 0x00007fff7aef4dcb _dispatch_client_callout + 8
at 12 libdispatch.dylib 0x00007fff7aef75d8 _dispatch_continuation_pop + 427
at 13 libdispatch.dylib 0x00007fff7aef6c7a _dispatch_async_redirect_invoke + 718
at 14 libdispatch.dylib 0x00007fff7af02d1a _dispatch_root_queue_drain + 325
at 15 libdispatch.dylib 0x00007fff7af034b1 _dispatch_worker_thread2 + 90
at 16 libsystem_pthread.dylib 0x00007fff7b1346ee _pthread_wqthread + 619
at 17 libsystem_pthread.dylib 0x00007fff7b134415 start_wqthread + 13
zsh: abort ./main.kexe
When I changed session to NSURLSession.sharedSession(), the same error appeared.

Kotlin native expects the callback to be called on the main thread.
This is how the native HTTP request is implemented in Kotlin conf spinner app.
https://github.com/Kotlin/kotlinconf-spinner/blob/master/clients/ios/src/iosMain/kotlin/platformUtils.kt

Related

Can't obtain output buffer from iOS camera in Kotlin Multiplatform

I've got a Kotlin Multiplatform multi-module project and one module deals with the camera. I've separated Android and iOS sourcesets for this specific module. Using Kotlin native for iOS, I can succesfully add a video input, a video output and show the preview in a layer, but I can't manage to get the sample buffer in the AVCaptureVideoDataOutputSampleBufferDelegateProtocol delegate.
I'm having this error:
Uncaught Kotlin exception: kotlin.native.IncorrectDereferenceException: illegal attempt to access non-shared <object>#8121d008 from other thread
at 0 MyFramework 0x000000010118fd3c kfun:kotlin.Throwable#<init>(kotlin.String?){} + 92
at 1 MyFramework 0x0000000101188cf0 kfun:kotlin.Exception#<init>(kotlin.String?){} + 88
at 2 MyFramework 0x000000010118883c kfun:kotlin.RuntimeException#<init>(kotlin.String?){} + 88
at 3 MyFramework 0x00000001011b7074 kfun:kotlin.native.IncorrectDereferenceException#<init>(kotlin.String){} + 88
at 4 MyFramework 0x00000001011ba8cc ThrowIllegalObjectSharingException + 428
at 5 MyFramework 0x00000001015fe100 TryAddHeapRef + 0
at 6 MyFramework 0x00000001015fddc4 _ZN27BackRefFromAssociatedObject9tryAddRefEv + 108
at 7 MyFramework 0x00000001015ed7f4 _ZN12_GLOBAL__N_113_tryRetainImpEP11objc_objectP13objc_selector + 64
at 8 libobjc.A.dylib 0x00000002202f1f94 objc_loadWeakRetained + 348
at 9 libobjc.A.dylib 0x00000002202f2060 objc_loadWeak + 20
at 10 AVFoundation 0x00000002271f73b8 <redacted> + 32
at 11 libdispatch.dylib 0x00000001049e8de4 _dispatch_client_callout + 16
at 12 libdispatch.dylib 0x00000001049f7fe4 _dispatch_sync_invoke_and_complete + 124
at 13 AVFoundation 0x00000002271f72c8 <redacted> + 164
at 14 AVFoundation 0x00000002271f715c <redacted> + 36
at 15 AVFoundation 0x00000002271d7fa4 <redacted> + 124
at 16 AVFoundation 0x00000002271d7ce8 <redacted> + 100
at 17 CoreMedia 0x00000002246ffdfc <redacted> + 280
at 18 CoreMedia 0x000000022471d4cc <redacted> + 224
at 19 libdispatch.dylib 0x00000001049e8de4 _dispatch_client_callout + 16
at 20 libdispatch.dylib 0x00000001049ec1e0 _dispatch_continuation_pop + 528
at 21 libdispatch.dylib 0x00000001049fecac _dispatch_source_invoke + 1864
at 22 libdispatch.dylib 0x00000001049f0cd8 _dispatch_lane_serial_drain + 288
at 23 libdispatch.dylib 0x00000001049f1bb4 _dispatch_lane_invoke + 516
at 24 libdispatch.dylib 0x00000001049f0cd8 _dispatch_lane_serial_drain + 288
at 25 libdispatch.dylib 0x00000001049f1b7c _dispatch_lane_invoke + 460
at 26 libdispatch.dylib 0x00000001049fbc18 _dispatch_workloop_worker_thread + 1220
at 27 libsystem_pthread.dylib 0x0000000220d260f0 _pthread_wqthread + 312
at 28 libsystem_pthread.dylib 0x0000000220d28d00 start_wqthread + 4
I guess is related to threading problems, maybe when the images are sendded to the delegate, but I'm not sure. I tried to use #ThreadLocal with no success.
This is the code:
class MyClass(val listener: MyListener) {
...
private val sampleDelegate: AVCaptureVideoDataOutputSampleBufferDelegateProtocol = object : NSObject(), AVCaptureVideoDataOutputSampleBufferDelegateProtocol {
override fun captureOutput(output: AVCaptureOutput, didOutputSampleBuffer: CMSampleBufferRef?, fromConnection: AVCaptureConnection) {
//Not called due to previous error
}
}
...
fun addVideoOutput(captureDevicePosition: AVCaptureDevicePosition) {
val videoOutput = AVCaptureVideoDataOutput()
val myqueue = dispatch_queue_create("cameraQueue", null)
videoOutput.setSampleBufferDelegate(sampleDelegate, myqueue)
val format = kCVPixelFormatType_32BGRA
videoOutput.videoSettings = NSDictionary.dictionaryWithObject(
NSNumber.numberWithUnsignedInt(format),
kCVPixelBufferPixelFormatTypeKey as NSCopyingProtocol
)
if (captureSession.canAddOutput(videoOutput)) {
captureSession.addOutput(videoOutput)
}
val conn = videoOutput.connectionWithMediaType(AVMediaTypeVideo)
if (conn!!.isVideoOrientationSupported()) {
conn.videoOrientation = captureDevicePosition
}
videoOutput.alwaysDiscardsLateVideoFrames = true
captureSession.sessionPreset = AVCaptureSessionPresetHigh
}
Using
val myqueue = dispatch_get_main_queue()
solved the problem

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.
To achieve this, I have a WKApplicationRefreshBackgroundTask that runs periodically. It uses sendMessage(_:replyHandler:errorHandler:) from WatchConnectivity to request the information from the iPhone app, process the reply, and update the complication.
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. 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.
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.
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. To be safe I implemented the delegate method on iPhone as an empty method that does nothing.
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. Maybe that's core to the issue here?
Here's my background refresh code from 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:
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.
You can therefore not rely on sendMessage to wake up the iOS app and to call replyHandler in time.
I suggest that you initialize the transfer of complication data on 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. This userInfo is received even if your watch app is not running, and the complication data can be updated as required.
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. If so, you could simply use sendMessage with replyHandler and errorHandler set to nil.
sendMessage is guaranteed to wake up the iOS app in the future, even when the watchOS app is already inactive. The iOS app could then send complication data, and these would be displayed immediately.
Additionally, the iOS app could send the userInfo that updates your ViewModel as application context. It would then be available when the watchOS app becomes active again, and you can update the ViewModel.
If this fits to your use case, you could simply remove the timer and complete the background task immediately after sendMessage.

Creating a Kotlin Native Background Dispatcher for Coroutine

I'm currently trying to write a dispatcher for iOS, to run Http requests in the background. My current attempt is the following object:
val runCoroutineDispatcher: CoroutineContext = NsQueueDispatcher
object NsQueueDispatcher: CoroutineDispatcher(){
override fun dispatch(
context: CoroutineContext,
block: Runnable
){
dispatch_async(
dispatch_get_global_queue(
NSNumber(double = DISPATCH_QUEUE_PRIORITY_DEFAULT.toDouble()).integerValue,
0)
) {
block.run()
}
}
}
If I try to use this dispatcher for a coroutine I always get the issue
Uncaught Kotlin exception: kotlin.native.IncorrectDereferenceException: illegal attempt to access non-shared de.ubimax.common.dispatcher.NsGlobalQueueDispatcher.$dispatch$lambda-0$FUNCTION_REFERENCE$1#8147aca8 from other thread
at 0 FrontlineClientCommon 0x00000001012d0fec kfun:kotlin.Throwable.<init>(kotlin.String?)kotlin.Throwable + 92
at 1 FrontlineClientCommon 0x00000001012c9ebc kfun:kotlin.Exception.<init>(kotlin.String?)kotlin.Exception + 88
at 2 FrontlineClientCommon 0x00000001012c9980 kfun:kotlin.RuntimeException.<init>(kotlin.String?)kotlin.RuntimeException + 88
at 3 FrontlineClientCommon 0x00000001012f92dc kfun:kotlin.native.IncorrectDereferenceException.<init>(kotlin.String)kotlin.native.IncorrectDereferenceException + 88
at 4 FrontlineClientCommon 0x00000001012fae84 ThrowIllegalObjectSharingException + 512
at 5 FrontlineClientCommon 0x000000010185cc9c _ZNK16KRefSharedHolder3refEv + 100
at 6 FrontlineClientCommon 0x0000000101879144 Kotlin_Interop_unwrapKotlinObjectHolder + 48
at 7 FrontlineClientCommon 0x00000001017aa184 _knbridge33 + 120
at 8 libdispatch.dylib 0x0000000108bed7fc _dispatch_call_block_and_release + 24
at 9 libdispatch.dylib 0x0000000108beebd8 _dispatch_client_callout + 16
at 10 libdispatch.dylib 0x0000000108bf12d4 _dispatch_queue_override_invoke + 872
at 11 libdispatch.dylib 0x0000000108c00160 _dispatch_root_queue_drain + 376
at 12 libdispatch.dylib 0x0000000108c00a88 _dispatch_worker_thread2 + 156
at 13 libsystem_pthread.dylib 0x00000001a6160f48 _pthread_wqthread + 212
at 14 libsystem_pthread.dylib 0x00000001a6163ad4 start_wqthread + 8
Sample code:
CoroutineScope(runCoroutineDispatcher).launch {
println("Hello World")
}
So far I only could find examples with the usage of dispatch_get_main_queue() instead of dispatch_get_global_queue().

SetIcon on cordova-plugin-googlemaps throws an error on iOS and freeze the screen only the first time

I'm trying to change the icon (image and size) using setIcon, On Android, it works nice but on iOS it changes but the first time I execute the code the map freeze, after that the map is not frozen anymore. When I look at Xcode console it throws this error:
PID: 2617, TID: 951642, Thread name: (none), Queue name: NSOperationQueue 0x2818e5240 (QOS: UNSPECIFIED), QoS: 0
Backtrace:
4 XXXXXXXXXXXXX 0x000000010254cf9c -[PluginMarker setIcon_:iconProperty:callbackBlock:] + 5316
5 XXXXXXXXXXXXX 0x000000010254a04c __24-[PluginMarker setIcon:]_block_invoke + 1872
6 Foundation 0x00000001b2695ef8 <redacted> + 16
7 Foundation 0x00000001b25a23e0 <redacted> + 72
8 Foundation 0x00000001b25a18c8 <redacted> + 740
9 Foundation 0x00000001b2697c7c <redacted> + 272
10 libdispatch.dylib 0x0000000107d5b6f0 _dispatch_call_block_and_release + 24
11 libdispatch.dylib 0x0000000107d5cc74 _dispatch_client_callout + 16
12 libdispatch.dylib 0x0000000107d5fffc _dispatch_continuation_pop + 524
13 libdispatch.dylib 0x0000000107d5f458 _dispatch_async_redirect_invoke + 628
14 libdispatch.dylib 0x0000000107d6ddc8 _dispatch_root_queue_drain + 372
15 libdispatch.dylib 0x0000000107d6e7ac _dispatch_worker_thread2 + 156
16 libsystem_pthread.dylib 0x00000001b18511b4 _pthread_wqthread + 464
17 libsystem_pthread.dylib 0x00000001b1853cd4 start_wqthread + 4
2019-08-09 12:44:29.304099+0200 condis-family[2617:951642] [reports] Main Thread Checker: UI API called on a background thread: -[UIWebView request]
The Typescript code is very simple:
private async _showClickedShop(marker: Marker) {
const index = this._sortedFilteredShopsList.findIndex((shop) => shop.id === this.selectedShop.id);
const currentMarker = this._markersArray[index];
const isFavouriteToggle = this.isShopFavouriteShop(this.selectedShop.id);
const iconCurrent: MarkerIcon = this.iconConfig(this.selectedShop.category, 32, 45, isFavouriteToggle);
currentMarker.setIcon(iconCurrent);
this.selectedShop = this._sortedFilteredShopsList[marker.get('index')]
this.isFavouriteToggle = this.isShopFavouriteShop(this.selectedShop.id);
const iconSelected: MarkerIcon = this.iconConfig(this.selectedShop.category, 42, 55, isFavouriteToggle);
marker.setIcon(iconSelected);
}
private iconConfig(category: string, width: number, height: number, isFavorite: boolean): MarkerIcon {
const url = isFavorite ? this._getIconMarkerFAV(category) : this._getIconMarker(category);
return {
url,
size: {
width: width,
height: height
}
};
}
I am not very familiar on iOS errors so I don't know how to resolve it, anyone has an idea to fix this?
If I remove the setIcon, the map is not frozen anymore so the problem is there.

How make correctely main thread on using sempanhores to sync Alamofire requests Swift4?

I'am using semaphores to sync my requests on AlamofireXMLRPC. So my function is:
let semaphore = DispatchSemaphore(value: 0)
for i in idsCloud {
if !idsLocal.contains(i) {
count += 1
print("\n---->O ID: \(i) NÃO CONSTA NO BANCO LOCAL! <----\n")
// se o id nao consta no banco local, deve inseri-lo
OdooService.getProductByIdFromOdoo(id: i,successBlock: { (p) in
CoreDataHandler.saveProduct(p: p)
semaphore.signal()
}, failureBlock: { (erro) in
print(erro)
})
semaphore.wait()
}
}
static func getProductByIdFromOdoo( id : Int, successBlock: #escaping (_ params : [String:Any]) -> Void, failureBlock: #escaping (_ params : String) -> Void) {
if !checkOdooConn() {
failureBlock("Falha na conexão com o Odoo")
return
}
let options = ["fields": fieldsProducts] as [String:Any]
let params = [OdooAuth.db,OdooAuth.uid,OdooAuth.password,"product.template","search_read",[[["id","=",id]]],options] as [Any]
print("start request...")
AlamofireXMLRPC.request(OdooAuth.host2, methodName: "execute_kw", parameters: params).responseXMLRPC(queue: DispatchQueue.global(qos: .background)) {
(response: DataResponse<XMLRPCNode>) -> Void in
switch response.result {
case .success( _):
let str = String(data: response.data!, encoding: String.Encoding.utf8) as String!
let options = AEXMLOptions()
let pdict = strToDict(str: str!,options: options)
successBlock(pdict.first!)
break
case .failure(let error):
failureBlock(error.localizedDescription)
break
} // fim switch
} // fim request
}
On first iteraction of my "for i in idsCloud" I receive a strange message on console.
=================================================================
Main Thread Checker: UI API called on a background thread: -[UIApplication delegate]
PID: 30310, TID: 1868520, Thread name: (none), Queue name: com.apple.root.background-qos, QoS: 9
Backtrace:
4 OdooVendas 0x00000001082d184e _T010OdooVendas15CoreDataHandlerC10getContext33_C78C41DC1F74DDA11E962327A9344CC5LLSo015NSManagedObjectG0CyFZ + 94
5 OdooVendas 0x00000001082d1951 _T010OdooVendas15CoreDataHandlerC11saveProductys10DictionaryVySSypG1p_tFZ + 33
6 OdooVendas 0x00000001082d588c _T010OdooVendas15CoreDataHandlerC12syncProductsyyFZys10DictionaryVySSypGcfU1_ + 60
7 OdooVendas 0x00000001082d5aaa _T010OdooVendas15CoreDataHandlerC12syncProductsyyFZys10DictionaryVySSypGcfU1_TA + 58
8 OdooVendas 0x00000001082f6cb1 _T010OdooVendas0A7ServiceC018getProductByIdFromA0ySi2id_ys10DictionaryVySSypGc12successBlockySSc07failureL0tFZy9Alamofire12DataResponseVy0N6XMLRPC10XMLRPCNodeVGcfU_ + 1697
9 OdooVendas 0x00000001082f6f62 _T010OdooVendas0A7ServiceC018getProductByIdFromA0ySi2id_ys10DictionaryVySSypGc12successBlockySSc07failureL0tFZy9Alamofire12DataResponseVy0N6XMLRPC10XMLRPCNodeVGcfU_TA + 114
10 AlamofireXMLRPC 0x00000001087e052d _T09Alamofire12DataResponseVy0A6XMLRPC10XMLRPCNodeVGIxx_AGIxi_TR + 173
11 AlamofireXMLRPC 0x00000001087e1092 _T09Alamofire12DataResponseVy0A6XMLRPC10XMLRPCNodeVGIxx_AGIxi_TRTA + 66
12 Alamofire 0x0000000108686819 _T09Alamofire11DataRequestC8responseACXDSo13DispatchQueueCSg5queue_x0D10SerializeryAA0B8ResponseVy16SerializedObjectQzGc17completionHandlertAA0biH8ProtocolRzlFyycfU_yycfU_ + 905
13 Alamofire 0x000000010868f08e _T09Alamofire11DataRequestC8responseACXDSo13DispatchQueueCSg5queue_x0D10SerializeryAA0B8ResponseVy16SerializedObjectQzGc17completionHandlertAA0biH8ProtocolRzlFyycfU_yycfU_TA + 110
14 Alamofire 0x000000010863f269 _T0Ix_IyB_TR + 41
15 libdispatch.dylib 0x000000010e1bc2f7 _dispatch_call_block_and_release + 12
16 libdispatch.dylib 0x000000010e1bd33d _dispatch_client_callout + 8
17 libdispatch.dylib 0x000000010e1c93a2 _dispatch_root_queue_drain + 1444
18 libdispatch.dylib 0x000000010e1c8da0 _dispatch_worker_thread3 + 132
19 libsystem_pthread.dylib 0x000000010e6881ca _pthread_wqthread + 1387
20 libsystem_pthread.dylib 0x000000010e687c4d start_wqthread + 13
2018-03-23 15:06:48.237961-0300 OdooVendas[30310:1868520] [reports] Main Thread Checker: UI API called on a background thread: -[UIApplication delegate]
PID: 30310, TID: 1868520, Thread name: (none), Queue name: com.apple.root.background-qos, QoS: 9
Backtrace:
4 OdooVendas 0x00000001082d184e _T010OdooVendas15CoreDataHandlerC10getContext33_C78C41DC1F74DDA11E962327A9344CC5LLSo015NSManagedObjectG0CyFZ + 94
5 OdooVendas 0x00000001082d1951 _T010OdooVendas15CoreDataHandlerC11saveProductys10DictionaryVySSypG1p_tFZ + 33
6 OdooVendas 0x00000001082d588c _T010OdooVendas15CoreDataHandlerC12syncProductsyyFZys10DictionaryVySSypGcfU1_ + 60
7 OdooVendas 0x00000001082d5aaa _T010OdooVendas15CoreDataHandlerC12syncProductsyyFZys10DictionaryVySSypGcfU1_TA + 58
8 OdooVendas 0x00000001082f6cb1 _T010OdooVendas0A7ServiceC018getProductByIdFromA0ySi2id_ys10DictionaryVySSypGc12successBlockySSc07failureL0tFZy9Alamofire12DataResponseVy0N6XMLRPC10XMLRPCNodeVGcfU_ + 1697
9 OdooVendas 0x00000001082f6f62 _T010OdooVendas0A7ServiceC018getProductByIdFromA0ySi2id_ys10DictionaryVySSypGc12successBlockySSc07failureL0tFZy9Alamofire12DataResponseVy0N6XMLRPC10XMLRPCNodeVGcfU_TA + 114
10 AlamofireXMLRPC 0x00000001087e052d _T09Alamofire12DataResponseVy0A6XMLRPC10XMLRPCNodeVGIxx_AGIxi_TR + 173
11 AlamofireXMLRPC 0x00000001087e1092 _T09Alamofire12DataResponseVy0A6XMLRPC10XMLRPCNodeVGIxx_AGIxi_TRTA + 66
12 Alamofire 0x0000000108686819 _T09Alamofire11DataRequestC8responseACXDSo13DispatchQueueCSg5queue_x0D10SerializeryAA0B8ResponseVy16SerializedObjectQzGc17completionHandlertAA0biH8ProtocolRzlFyycfU_yycfU_ + 905
13 Alamofire 0x000000010868f08e _T09Alamofire11DataRequestC8responseACXDSo13DispatchQueueCSg5queue_x0D10SerializeryAA0B8ResponseVy16SerializedObjectQzGc17completionHandlertAA0biH8ProtocolRzlFyycfU_yycfU_TA + 110
14 Alamofire 0x000000010863f269 _T0Ix_IyB_TR + 41
15 libdispatch.dylib 0x000000010e1bc2f7 _dispatch_call_block_and_release + 12
16 libdispatch.dylib 0x000000010e1bd33d _dispatch_client_callout + 8
17 libdispatch.dylib 0x000000010e1c93a2 _dispatch_root_queue_drain + 1444
18 libdispatch.dylib 0x000000010e1c8da0 _dispatch_worker_thread3 + 132
19 libsystem_pthread.dylib 0x000000010e6881ca _pthread_wqthread + 1387
20 libsystem_pthread.dylib 0x000000010e687c4d start_wqthread + 13
The curious is that all works fine but I'm fear with this message, I don't know if I making some thing wrong. I don't know working with queues in swift, but this code appears solve my problem.
I using CoreData to manage my database.
You cannot call UIKit method on background threads, so you cannot access UIApplication.delegate (that's a UIKit method). This is one of many reasons that you should never store global variables in the app delegate. Create a separate singleton, or pass the viewContext around where it's needed. But don't store anything in the app delegate.
That said, you also shouldn't be using a semaphore here. Semaphores are almost never the right tool. Even if you need to synchronize, you almost always should be using a DispatchGroup, not a Semaphore.
If you need to serialize the calls, then have each completion handler call the next one.
If you can do the calls in parallel, then use a DispatchGroup and use the .notify method on it to schedule something to do when all of them are completed. (For each network call, add a group.enter() and when it's completed, call group.leave().)

Resources