Die iOS 13.1 UITextView-Delegatenmethode sollte beim Scrollen im Anhang aufgerufen werden

15

Ich verwende die UITextViewDelegate-Methode, um benutzerdefinierte Arbeiten wie das Öffnen eines In-App-Browsers auszuführen, wenn Benutzer auf URL oder Anhang tippen:

func textView(_ textView: UITextView,
                  shouldInteractWith URL: URL,
                  in characterRange: NSRange,
                  interaction: UITextItemInteraction) -> Bool

In iOS 13 wird diese Delegatenmethode auch dann aufgerufen, wenn der Benutzer nur über die URL blättert, was nicht erwartet wird. Dieses Verhalten gilt auch für Bildanhänge.

Diese Deleate-Methode wird jetzt über die Interaktion aufgerufen.

* thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 6.1 7.1
  * frame #0: 0x0000000104a54c5c ProjectS1`PostListViewController.textView(textView=0x00000001090a4600, URL=Foundation.URL @ 0x000000016b5d1200, characterRange=location=161, length=9, interaction=invokeDefaultAction, self=0x0000000109b03990) at PostListViewController.swift:610:9
    frame #1: 0x0000000104a54d70 ProjectS1`@objc PostListViewController.textView(_:shouldInteractWith:in:interaction:) at <compiler-generated>:0
    frame #2: 0x00000001b3293eec UIKitCore`-[UITextView _allowInteraction:forTextInteractableItem:] + 212
    frame #3: 0x00000001b2602160 UIKitCore`-[_UITextInteractableItem _allowInteraction:] + 140
    frame #4: 0x00000001b2601f68 UIKitCore`-[_UITextInteractableItem canInvokeDefaultAction] + 100
    frame #5: 0x00000001b31dd528 UIKitCore`-[_UITextSimpleLinkInteraction _canBeginInteractionSessionForLinkAtPoint:asTap:] + 136
    frame #6: 0x00000001b31dd3d0 UIKitCore`-[_UITextSimpleLinkInteraction interaction_gestureRecognizer:shouldReceiveTouch:] + 228
    frame #7: 0x00000001b31dc234 UIKitCore`-[UITextInteraction gestureRecognizer:shouldReceiveTouch:] + 144
    frame #8: 0x00000001b2b5f460 UIKitCore`-[UIGestureRecognizer _delegateShouldReceiveTouch:] + 452
    frame #9: 0x00000001b2b5edf4 UIKitCore`-[UIGestureRecognizer _shouldReceiveTouch:forEvent:recognizerView:] + 488
    frame #10: 0x00000001b2ffa630 UIKitCore`__56-[UITouchesEvent _addGestureRecognizersForView:toTouch:]_block_invoke + 332
    frame #11: 0x00000001b2ffa0e4 UIKitCore`__62-[UITouchesEvent _collectGestureRecognizersForView:withBlock:]_block_invoke + 408
    frame #12: 0x00000001b2ff9b58 UIKitCore`-[UITouchesEvent _collectGestureRecognizersForView:withBlock:] + 308
    frame #13: 0x00000001b2ffa4b0 UIKitCore`-[UITouchesEvent _addGestureRecognizersForView:toTouch:] + 164
    frame #14: 0x00000001b2ffa9a8 UIKitCore`-[UITouchesEvent _addTouch:forDelayedDelivery:] + 812
    frame #15: 0x00000001b300bfac UIKitCore`_AddTouchToEventAndDetermineIfNeedsCancel + 196
    frame #16: 0x00000001b300c074 UIKitCore`____updateTouchesWithDigitizerEventAndDetermineIfShouldSend_block_invoke.96 + 136
    frame #17: 0x00000001aef35b20 CoreFoundation`__NSDICTIONARY_IS_CALLING_OUT_TO_A_BLOCK__ + 24
    frame #18: 0x00000001aef360e4 CoreFoundation`____NSDictionaryEnumerate_block_invoke.11 + 56
    frame #19: 0x00000001aef07a10 CoreFoundation`CFBasicHashApply + 144
    frame #20: 0x00000001aef35c80 CoreFoundation`__NSDictionaryEnumerate + 220
    frame #21: 0x00000001b300d560 UIKitCore`__dispatchPreprocessedEventFromEventQueue + 2444
    frame #22: 0x00000001b30107dc UIKitCore`__handleEventQueueInternal + 4928
    frame #23: 0x00000001b3009960 UIKitCore`__handleHIDEventFetcherDrain + 112
    frame #24: 0x00000001aee61260 CoreFoundation`__CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 28
    frame #25: 0x00000001aee611b4 CoreFoundation`__CFRunLoopDoSource0 + 84
    frame #26: 0x00000001aee60920 CoreFoundation`__CFRunLoopDoSources0 + 184
    frame #27: 0x00000001aee5b7ec CoreFoundation`__CFRunLoopRun + 1068
    frame #28: 0x00000001aee5b098 CoreFoundation`CFRunLoopRunSpecific + 480
    frame #29: 0x00000001b8fc5534 GraphicsServices`GSEventRunModal + 108
    frame #30: 0x00000001b2f7b7ac UIKitCore`UIApplicationMain + 1940
    frame #31: 0x0000000104b090d0 ProjectS1`main at AppDelegate.swift:25:7
    frame #32: 0x00000001aecdaf30 libdyld.dylib`start + 4

Meine Frage ist also, gibt es eine Möglichkeit zu wissen, ob der Benutzer auf die URL tippt oder nur auf der URL blättert?

Kukushi
quelle
1
Dies ist ein "bekanntes" Problem in iOS 13.1. Es ist bekannt, dass Entwickler darüber getwittert haben und einige von uns Fehlerberichte eingereicht haben. Ab iOS 13.2 Beta Seed 1 ist es immer noch nicht behoben. Melden Sie einen Fehler an und wählen Sie eine Problemumgehung aus - ganz nach Ihren Wünschen und abhängig von der Funktionsweise Ihrer App. Sie können entweder nichts tun und einfach warten oder eine Problemumgehung versuchen (z. B. eine in diesem Thread beschriebene - twitter.com/scelis/status/). 1176676097754198017 ). Was ich persönlich getan habe, war an einigen Stellen nichts, und an anderen Stellen habe ich das UITextViewDelegate entfernt und das Standardverhalten übernehmen lassen (Links in Safari öffnen).
bpapa

Antworten:

15

Es sieht so textView:shouldInteractWithURL:inRange:interaction:aus, als würde es während eines normalen Link-Pressings dreimal aufgerufen (wenn Sie immer zurückkehren YES).

Ein paar Mal, um zu sehen, ob die Standardaktion aufgerufen werden kann (vorausgesetzt, canInvokeDefaultActiondarum geht es):

  * frame #0: 0x0000000101610038 Engage`::-[BubbleMessageCell textView:shouldInteractWithURL:inRange:interaction:](self=0x00007ff19e999600, _cmd="textView:shouldInteractWithURL:inRange:interaction:", textView=0x00007ff19eaf2000, url="https://9to5mac.com/2019/09/07/imessage-for-business/", characterRange=location=235, length=33, interaction=UITextItemInteractionInvokeDefaultAction) at BubbleMessageCell.mm:623:5
    frame #1: 0x00007fff478b2902 UIKitCore`-[UITextView _allowInteraction:forTextInteractableItem:] + 532
    frame #2: 0x00007fff46b8ba1c UIKitCore`-[_UITextInteractableItem _allowInteraction:] + 135
    frame #3: 0x00007fff46b8b84d UIKitCore`-[_UITextInteractableItem canInvokeDefaultAction] + 97
    frame #4: 0x00007fff477f76f7 UIKitCore`-[_UITextSimpleLinkInteraction _canBeginInteractionSessionForLinkAtPoint:asTap:] + 127
    frame #5: 0x00007fff477f75c7 UIKitCore`-[_UITextSimpleLinkInteraction interaction_gestureRecognizer:shouldReceiveTouch:] + 217
    frame #6: 0x00007fff477f6506 UIKitCore`-[UITextInteraction gestureRecognizer:shouldReceiveTouch:] + 127
    frame #7: 0x00007fff47133669 UIKitCore`-[UIGestureRecognizer _delegateShouldReceiveTouch:] + 493
  * frame #0: 0x0000000101610038 Engage`::-[BubbleMessageCell textView:shouldInteractWithURL:inRange:interaction:](self=0x00007ff19e999600, _cmd="textView:shouldInteractWithURL:inRange:interaction:", textView=0x00007ff19eaf2000, url="https://9to5mac.com/2019/09/07/imessage-for-business/", characterRange=location=235, length=33, interaction=UITextItemInteractionInvokeDefaultAction) at BubbleMessageCell.mm:623:5
    frame #1: 0x00007fff478b2902 UIKitCore`-[UITextView _allowInteraction:forTextInteractableItem:] + 532
    frame #2: 0x00007fff46b8ba1c UIKitCore`-[_UITextInteractableItem _allowInteraction:] + 135
    frame #3: 0x00007fff46b8b84d UIKitCore`-[_UITextInteractableItem canInvokeDefaultAction] + 97
    frame #4: 0x00007fff477f77fb UIKitCore`-[_UITextSimpleLinkInteraction _beginInteractionSessionForLinkAtPoint:asTap:] + 167
    frame #5: 0x00007fff477f74d0 UIKitCore`-[_UITextSimpleLinkInteraction interaction_gestureRecognizerShouldBegin:] + 196
    frame #6: 0x00007fff477f62a1 UIKitCore`-[UITextInteraction gestureRecognizerShouldBegin:] + 307
    frame #7: 0x00007fff471339b6 UIKitCore`-[UIGestureRecognizer _shouldBegin] + 413

Und schließlich, wenn die Geste tatsächlich erkannt wird:

  * frame #0: 0x0000000101610038 Engage`::-[BubbleMessageCell textView:shouldInteractWithURL:inRange:interaction:](self=0x00007ff19e999600, _cmd="textView:shouldInteractWithURL:inRange:interaction:", textView=0x00007ff19eaf2000, url="https://9to5mac.com/2019/09/07/imessage-for-business/", characterRange=location=235, length=33, interaction=UITextItemInteractionInvokeDefaultAction) at BubbleMessageCell.mm:623:5
    frame #1: 0x00007fff478b2902 UIKitCore`-[UITextView _allowInteraction:forTextInteractableItem:] + 532
    frame #2: 0x00007fff46b8ba1c UIKitCore`-[_UITextInteractableItem _allowInteraction:] + 135
    frame #3: 0x00007fff46b8b8cc UIKitCore`-[_UITextInteractableItem invokeDefaultAction] + 94
    frame #4: 0x00007fff477f6f32 UIKitCore`-[_UITextSimpleLinkInteraction linkTapped:] + 188
    frame #5: 0x00007fff4712bbfb UIKitCore`-[UIGestureRecognizerTarget _sendActionWithGestureRecognizer:] + 44

Beim Scrollen erfolgt nur der erste Aufruf.

Dies ist vermutlich eine Änderung von iOS 13.1, bei der früher überprüft wird, ob mit dem Link interagiert werden kann. Wenn Sie textView:shouldInteractWithURL:inRange:interaction:Nebenwirkungen haben möchten, möchten Sie diese nur dann ausführen, wenn die Geste tatsächlich erkannt wird.

Was für uns zu funktionieren scheint, um textView.gestureRecognizersdie benutzerdefinierten Aktionen zu überprüfen und nur auszuführen, wenn eine Tippgeste erkannt wurde.

    BOOL recognizedTapGesture = NO;
    for (UIGestureRecognizer *recognizer in textView.gestureRecognizers) {
        if ([recognizer isKindOfClass:UITapGestureRecognizer.class] && recognizer.state == UIGestureRecognizerStateEnded) {
            recognizedTapGesture = YES;
            break;
        }
    }
    if (!recognizedTapGesture) {
        // Tap gesture is not being recognized, this must be an early 
        // check when touches begin. Leave the link handling alone.
        return YES;
    }

    // Do custom action here

    return NO;
Mihai Parparita
quelle
1
Vielen Dank! Ihre Lösung funktioniert hervorragend auf dem Link. Wie wäre es mit dem Bildanhang? Das Scrollen oder Tippen auf einen Bildanhang hat denselben Aufrufstapel und der Status der Gestenerkennung funktioniert nicht mit dem Anhang.
Kukushi
5

Ich habe gerade das gleiche frustrierende Problem in iOS 13 festgestellt. Hier ist ein Fix, der für mich in Swift funktioniert hat, inspiriert von Mihais Antwort oben.

func textView(_ textView: UITextView, shouldInteractWith URL: URL, in characterRange: NSRange, interaction: UITextItemInteraction) -> Bool {

    switch interaction {
    case .invokeDefaultAction:
        if textView.gestureRecognizers?.contains(where: {$0.isKind(of: UITapGestureRecognizer.self) && $0.state == .ended}) == true {

            // Handle your custom logic here.

            return false
        }
        return true
    case .presentActions:

        // Default action.

        return true
    case .preview:

        // Default action.

        return true
    @unknown default:
        fatalError()
    }
}
de3z1e
quelle
Dies funktioniert nicht auf dem iPad. Problem beim Anhängen eines anderen UITapGestureRecognizer behoben.
ccoroom