Ключевым моментом, на который следует обратить внимание, является то, что кадры с 0 по 5 этой обратной трассировки являются просто образцом, связанным с нераспознанным селектором. То есть кадр 6 вызвал метод для объекта, объект не распознал этот селектор, поэтому он вошел в инфраструктуру пересылки времени выполнения Objective C (кадры с 5 по 4). Это появилось в UIResponder (кадр 3), потому что UIResponder поддерживает какую-то общую пересылку сообщений. Переадресация сообщения завершилась неудачно, поэтому UIResponder вызвал super (кадр 2), который затем вызвал исключение.
Таким образом, реальный вопрос заключается в том, что происходит в кадре 6. Чтобы узнать больше об этом, вы можете разобрать код(-:
(lldb) disas -n '-[UIUndoGestureInteraction didMoveToView:]'
UIKitCore`-[UIUndoGestureInteraction didMoveToView:]:
0x1bbe92fd4 <+0>: stp x22, x21, [sp, #-0x30]!
0x1bbe92fd8 <+4>: stp x20, x19, [sp, #0x10]
0x1bbe92fdc <+8>: stp x29, x30, [sp, #0x20]
0x1bbe92fe0 <+12>: add x29, sp, #0x20 ; =0x20
0x1bbe92fe4 <+16>: mov x21, x2
0x1bbe92fe8 <+20>: mov x19, x0
0x1bbe92fec <+24>: add x20, x0, #0x10 ; =0x10
0x1bbe92ff0 <+28>: mov x0, x20
0x1bbe92ff4 <+32>: mov x1, x2
0x1bbe92ff8 <+36>: bl 0x1b7cd71d8 ; objc_storeWeak
0x1bbe92ffc <+40>: cbz x21, 0x1bbe930a8 ; <+212>
0x1bbe93000 <+44>: adrp x8, 208464
0x1bbe93004 <+48>: add x1, x8, #0x7b1 ; =0x7b1
0x1bbe93008 <+52>: mov x0, x19
0x1bbe9300c <+56>: bl 0x1b7cb9180 ; objc_msgSend
0x1bbe93010 <+60>: mov x0, x20
0x1bbe93014 <+64>: bl 0x1b7cd7a80 ; objc_loadWeakRetained
0x1bbe93018 <+68>: mov x20, x0
0x1bbe9301c <+72>: adrp x8, 208304
0x1bbe93020 <+76>: add x1, x8, #0xc04 ; =0xc04
0x1bbe93024 <+80>: bl 0x1b7cb9180 ; objc_msgSend
0x1bbe93028 <+84>: mov x29, x29
0x1bbe9302c <+88>: bl 0x1b7cd8864 ; objc_retainAutoreleasedReturnValue
0x1bbe93030 <+92>: mov x21, x0
0x1bbe93034 <+96>: adrp x8, 208502
0x1bbe93038 <+100>: add x1, x8, #0xbb7 ; =0xbb7
0x1bbe9303c <+104>: bl 0x1b7cb9180 ; objc_msgSend
0x1bbe93040 <+108>: stp d0, d1, [x19, #0x100]
Здесь вы можете узнать несколько вещей. Во-первых, кадр 6 в обратном следе имеет смещение +108, поэтому фактический сбой при вызове составляет +104. Objc_msgSend,имеет два стандартных параметра, целевой объект и селектор. На 64-битном Arm они отображаются на x0 и x1 соответственно.
Давайте сначала посмотрим на селектор. Это построено двумя инструкциями на +96 и+100.Эти две инструкции образуют относительный адрес ПК. Инструкция adrp ('добавить относительно страницы') берет текущий ПК (0x1bbe93034), очищает младшие 12 бит (0x1bbe93000, помните, что исторический размер страницы равен 4096 [1]), а затем берет литерал, сдвигает его влево на 12 бит (208502 << 12), а затем добавляет его. Инструкция добавления намного проще. результат предыдущего вычисления и добавляет 0xbb7 (обратите внимание на переключение с десятичного на шестнадцатеричное!). </p>
Если вы выполните это вычисление в отладчике, вы увидите следующее:
(lldb) p (char*)( 0x1bbe93000+(208502<<12)+0xbb7)
(char *) $1 = 0x00000001eed09bb7 "actualSceneBounds"
Так чтоСелектор является актуальнымКруто.
Теперь давайте посмотрим на объект. Во время вызова (+104) ожидается, что он будет в х0. В +92 мы видим, что это копирует x0 к x21, но это только отвлечение. На самом деле x0 - это результат функции из objc_retainAutoreleasedReturnValue со значением +88. Эта функция принимает и возвращает объект, поэтому x0 - это значение, возвращаемое сообщением, отправленным в +80. Делая тот же трюк с относительной страницей, который мы делали ранее, мы видим, что селектором для этого вызова является -window. Но какой объект вызывается?
Работать с этим… ну… довольно сложно из-за танца objc_storeWeak / objc_loadWeakRetained. Я считаю, что это сводится к значению, переданному в этот метод через x2, то есть третий параметр. Основываясь на имени метода, это явно представление (помните, что для методов Objective C первые два параметра, x0 и x1, содержат цель и селектор, поэтому x2 содержит первый фактический параметр).
Итак, в итоге:
Кажется, что у этого метода есть параметр представления.
Запрошено window.window.screenBounds.
Последний доступ к свойству не удался, потому что объект, который должен быть окном, не реализует метод -screenBounds.
Я не знаюя не знаю достаточно о UIKit, чтобы объяснить это. У меня есть несколько предложений здесь:
Запустите стандартные средства отладки памяти, и в частности зомби, чтобы увидеть, если они найдут что-нибудь полезное. Обязательно используйте жест отмены, основанный на имени класса метода, который мы разделили.
Если это не удастся, отскок к App Frameworkworks> Cocoa Touch, чтобы увидетьесли у кого-то есть какие-либо предложения.
Делитесь и наслаждайтесь
-
[1] На 64-битном ARM фактический размер страницы обычно составляет 64КиБ, но инструкция adrp использует исторический размер страницы 4096, поскольку она соответствует максимальному литеральному размеру в инструкции добавления.