Как передать замыкание в качестве параметра в execute (selector, withObject) - PullRequest
0 голосов
/ 25 марта 2019

Я пытаюсь передать pass в качестве параметра для быстрого перехода и выполнения его в методе селектора.

override func viewDidLoad() {
    super.viewDidLoad()

    let closure = {
        print(self.isCityChoosen)
    }
    perform(#selector(foo(param:)), with: closure)
}

@objc func foo(param: () -> () ) {
    param()
}

Но у меня есть

Thread 1: EXC_BAD_ACCESS (code=1, address=0x0) Ошибка во время выполнения при выполнении param () Почему возникает эта ошибка? Есть ли способ обойти это?

Ответы [ 3 ]

6 голосов
/ 25 марта 2019

Ваше закрытие не является блоком Objective-C, поэтому оно не может быть передано через среду выполнения ObjC. Вы должны пометить его как блок, используя @convention.

let closure: @convention(block) () -> Void = { ... }

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

let closure = { ... }
let block: @convention(block) () -> Void = closure
perform(#selector(foo(param:)), with: block)

Блоки Objective-C фактически являются объектами и участвуют в ARC. Сбой происходит из-за того, что perform пытается вызвать Block_copy для неблокированного блока.

Конечно, как правило, селекторы не являются подходящими инструментами в Swift, и вы должны преобразовать любой интерфейс на основе селектора, чтобы он просто взял аргумент функции. Если вы обнаружите, что используете perform, вы, вероятно, не в ту сторону в Swift. Но он все еще доступен, если вам это нужно.

1 голос
/ 25 марта 2019

Я думаю, это потому, что вы используете необъективный тип-c в объявлении метода:

@objc func foo(param: () -> ()) замыкание не относится к типу цель-с.

Вы можете сделать что-то вроде этого;

@objc func foo(_ closure: Any) {
    if let closure = closure as? () -> Void {
        closure()
    }
}

Это работает, потому что (я полагаю) вы указываете среде выполнения objc, что метод принимает Any, который правильно переведен в тип target-c id.

1 голос
/ 25 марта 2019

Есть ли причина использования perform(_:with:)?Если нет, вы можете упростить ваш код и просто вызвать метод с замыканием

override func viewDidLoad() {
    super.viewDidLoad()

    foo {
        print(self.isCityChoosen)
    }
}

func foo(param: () -> () ) {
    param()
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...