Phương thức ủy nhiệm UITextView của iOS 13.1 nên được gọi khi cuộn trên tệp đính kèm


15

Tôi đang sử dụng UITextViewphương thức ủy nhiệm để thực hiện một số công việc tùy chỉnh như mở trình duyệt trong ứng dụng khi người dùng nhấn vào URL hoặc tệp đính kèm:

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

Trong iOS 13, phương thức ủy nhiệm này được gọi ngay cả khi người dùng chỉ cuộn qua URL, điều này không được mong đợi. Hành vi này cũng được áp dụng để đính kèm hình ảnh.

Phương thức deleate đó bây giờ được gọi thông qua sự tương tác.

* 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

Vì vậy, câu hỏi của tôi là, có cách nào để biết liệu người dùng đang nhấn vào URL hay chỉ cuộn trên URL?


1
Đây là sự cố "đã biết" trong iOS 13.1. Được biết, các nhà phát triển đã tweet về nó và một số người trong chúng tôi đã nộp báo cáo lỗi. Kể từ iOS 13.2 beta seed 1, nó vẫn chưa được sửa. Gửi một lỗi và chọn một cách giải quyết - tùy thuộc vào cách ứng dụng của bạn hoạt động - bạn không thể làm gì và chỉ chờ, hoặc thử một cách giải quyết (ví dụ: một mô tả trong chủ đề này - twitter.com/scelis/status/ 1176676097754198017 ). Những gì tôi đã làm cá nhân không có gì ở một số nơi và ở những nơi khác tôi đã xóa UITextViewDelegate và để hành vi mặc định tiếp quản (mở các liên kết trong Safari).
bpapa

Câu trả lời:


15

Có vẻ như textView:shouldInteractWithURL:inRange:interaction:cuối cùng được gọi 3 lần trong một lần nhấn liên kết thông thường (nếu bạn luôn quay lại YES).

Một vài lần để xem liệu hành động mặc định có thể được gọi hay không (giả sử đó canInvokeDefaultActionlà về cái gì ):

  * 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

Và cuối cùng khi cử chỉ thực sự được công nhận:

  * 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

Khi cuộn, chỉ có cuộc gọi đầu tiên xảy ra.

Đây có lẽ là một thay đổi iOS 13.1, trong đó nó sẽ kiểm tra sớm hơn để xem liệu liên kết có thể được tương tác với. Nếu bạn muốn textView:shouldInteractWithURL:inRange:interaction:có tác dụng phụ, bạn chỉ muốn thực hiện chúng khi cử chỉ thực sự được nhận ra.

Những gì dường như hoạt động để chúng ta kiểm tra textView.gestureRecognizersvà chỉ thực hiện các hành động tùy chỉnh nếu một cử chỉ nhấn được nhận ra.

    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;

1
Cảm ơn! Giải pháp của bạn hoạt động tuyệt vời trên các liên kết. Làm thế nào về các hình ảnh đính kèm? Cuộn hoặc chạm vào tệp đính kèm hình ảnh có cùng ngăn xếp cuộc gọi và kiểm tra trạng thái nhận dạng cử chỉ không hoạt động với tệp đính kèm.
kukushi

5

Tôi vừa gặp phải vấn đề bực bội tương tự trong iOS 13. Đây là cách khắc phục hiệu quả với tôi trong Swift lấy cảm hứng từ câu trả lời của Mihai ở trên.

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()
    }
}

Điều này không hoạt động trên iPad. Đã giải quyết bằng cách đính kèm một UITapGestureRecognizer khác.
ccoroom
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.