Сбой IBOutlet с EXC_BAD_ACCESS, хотя не ноль - PullRequest
0 голосов
/ 07 декабря 2018

В UIViewController (rolePageController) я настраиваю другой UIViewController (pocketController) и передаю ему 2 UIViews со страницы ролей, которая будет частью конфигурации кейдконтроллера.Как только ящик контроллера пытается получить доступ к представлениям IBOutlet из rolePageController, он завершается с EXC_BAD_ACCESS (code = EXC_I386_GPFLT).

В 1-ом VC (rolePageController) есть следующие IBOutlets:

@IBOutlet var rolePageDrawerView: UIView!
@IBOutlet var rolePageContentView: UIView!

В rolePageController.viewDidLoad () я выполняю вызов к ящику bottomController.configureDrawer (...):

override func viewDidLoad() {
    super.viewDidLoad()

    //other stuff happens here

    let drawerController = UIStoryboard(name: "StoryboardName", bundle: nil).instantiateViewController(withIdentifier: "drawerController") as! DrawerViewController
    drawerController.configureDrawer(drawerContainerView: self.rolePageDrawerView, overlaidView: self.rolePageContentView)

    //other stuff here
}

Протокол DrawerViewController определяется как:

protocol DrawerViewController where Self: UIViewController {
    func configureDrawer(drawerContainerView: UIView, overlaidView: UIView)
}

Вот код для функции configureDrawer (...):

private var drawerParentView: UIView!
private var overlaidByDrawerView: UIView!


func configureDrawer(drawerContainerView: UIView, overlaidView: UIView) {
    self.drawerParentView = drawerContainerView
    self.overlaidByDrawerView = overlaidView
}

Замечено вотладчик, что вызываемый экземпляр boxController не соответствует собственному экземпляру, который получает вызов.Вот адрес экземпляра, который будет вызываться:

enter image description here

Вот адрес экземпляра, когда я вступаю в вызов:

enter image description here

Когда я вхожу в вызов, адрес ящика контроллера перед вызовом не является адресом самого себя.Этого никогда не должно быть.

Я создал упрощенный проект, который воспроизводит сбой в https://github.com/ksoftllc/DynamicStackBufferOverflow.

Решение Решение оказалось для удаления предложения where изПротокол DrawerViewController.

protocol DrawerViewController where Self: UIViewController {
    func configureDrawer(drawerContainerView: UIView, overlaidView: UIView)
}

Ответы [ 5 ]

0 голосов
/ 16 декабря 2018

Чтобы исправить вашу проблему, запустите ее на снимке панели инструментов разработки.Вы можете скачать его здесь:

https://swift.org/download/

Перейти к снимкам -> Разработка магистрали (мастер) XCode (не Swift 5.0) и загрузить снимок с15 декабря (я получил его с 30 ноября, но я уверен, что 15 декабря также будет работать.)

После того, как вы установили цепочку инструментов, в XCode перейдите по адресу: File -> Preferences -> Components и выберите новейшую цепочку инструментов. Теперь он работает без сбоев .

Кроме того, где Self: UIViewController можно сократить до :UIViewcontroller ( Это работает только для новейших цепочек инструментов ):

protocol DrawerViewController: UIViewController {
    func configureDrawer(drawerContainerView: UIView, overlaidView: UIView)
}
0 голосов
/ 12 декабря 2018

Это действительно похоже на ошибку компилятора Swift.Я упростил ваш код для уточнения:

func foo(_ wow: TestProtocol) {
    wow.foo()
}

protocol TestProtocol where Self: NSObject {
    func foo()
}

class TestClass: NSObject, TestProtocol {

    func foo() {
        print("Much wow")
    }

}

foo(TestClass())

Вы можете сообщить об этом как об ошибке.Чтобы решить эту проблему, я предлагаю вам не использовать оператор where или pass с типом func foo(_ wow: TestClass {.

0 голосов
/ 10 декабря 2018

dynamic-stack-buffer-overflow не имеет никакого отношения к рекурсии.Это означает, что буфер alloca был переполнен.Проверьте исходный код asan времени выполнения .

Предположим, что стек спроектирован так, что у вас есть буфер alloca, за которым следует указатель объекта - возможно, даже один из указателей объекта, переданных какАргумент.

Предположим, что буфер alloca переполнен.В сборке asan это может вызвать ошибку dynamic-stack-buffer-overflow.Но в сборке, отличной от asan, он просто записывает байты этого указателя объекта.Предположим, что он записывает байты, образующие адрес, который не отображается в таблице страниц вашего процесса.

Если программа пытается прочитать указатель этого объекта и сохранить его в другом месте (скажем, в переменной экземпляра), она должна увеличить значениесчетчик ссылок на объект.Но это означает разыменование указателя - и указатель указывает на не отображенный адрес.Возможно, это приводит к общей ошибке защиты, которую Мах вызывает EXC_I386_GPFLT.

. Было бы полезно, если вы разместили в стеке трассировку ошибки asan dynamic-stack-buffer-overflow и разборку.кода, приводящего к ошибке.

0 голосов
/ 11 декабря 2018

Найден код ошибки, но я не знаю, почему это может привести к ошибкам, которые я видел.Кассетный ящик соответствует протоколу DrawerViewController, определенному как:

protocol DrawerViewController where Self: UIViewController {
    func configureDrawer(drawerContainerView: UIView, overlaidView: UIView)
}

Когда я удаляю условие «Где», он больше не падает.

protocol DrawerViewController {
    func configureDrawer(drawerContainerView: UIView, overlaidView: UIView)
}

Предложение where фактически не было необходимо для правильной работы программы, поэтому я продолжу без него.

ОБНОВЛЕНИЕ Я сообщил об ошибке на swift.org и получил ответ.Добавление предложения where к протоколу не поддерживается в Swift 4.2, но будет поддерживаться в Swift 5.0.Кроме того, @J Doe опубликовал ниже способ достижения этого с обновлением инструментария XCode.

0 голосов
/ 10 декабря 2018

Переместить этот вызов функции из viewDidLoad в viewWillAppear drawerController.configureDrawer(drawerContainerView: self.rolePageDrawerView, overlaidView: self.rolePageContentView)

...