Swift performSelector: withObject: afterDelay: недоступен

У меня есть приложение на Objective C, которое я перехожу на Swift. В Objective C у меня есть такой метод:

[self.view performSelector:@selector(someSelector) withObject:self afterDelay:0.1f];

Я работаю со Swift и не могу понять, как это сделать. Я пробовал:

self.view.performSelector(Selector("someSelector"), withObject: self, afterDelay: 0.1)

Вот ошибка, которую я получаю: 'performSelector' is unavailable: 'performSelector' methods are unavailable

Какой вызов бы я использовал для вызова метода afterDelay?

ОБНОВЛЕНИЕ

Вот что у меня получилось:

extension NSObject {

    func callSelectorAsync(selector: Selector, object: AnyObject?, delay: NSTimeInterval) -> NSTimer {

        let timer = NSTimer.scheduledTimerWithTimeInterval(delay, target: self, selector: selector, userInfo: object, repeats: false)
        return timer
    }

    func callSelector(selector: Selector, object: AnyObject?, delay: NSTimeInterval) {

        let delay = delay * Double(NSEC_PER_SEC)
        let time = dispatch_time(DISPATCH_TIME_NOW, Int64(delay))
        dispatch_after(time, dispatch_get_main_queue(), {
            NSThread.detachNewThreadSelector(selector, toTarget:self, withObject: object)
        })
    }
}

person Cody Winton    schedule 11.06.2014    source источник
comment
Я бы не согласился. Я не спрашиваю, как выполнить Селектор. Я спрашиваю, как выполнить селектор afterDelay   -  person Cody Winton    schedule 12.06.2014
comment
Там дан ответ на тот же вопрос. Используйте GCD и dispatch_after или dispatch_async.   -  person David Berry    schedule 12.06.2014
comment
@ Дэвид: Там нет ответа. dispatch_after использует очереди отправки; тогда как performSelector:afterDelay: использует текущий цикл выполнения. Они разные.   -  person user102008    schedule 27.08.2014
comment
привет, я использовал ваш код в своем проекте, подумал, что вам может быть интересно: github.com/goktugyil/CozyLoadingActivity   -  person Esqarrouth    schedule 04.06.2015
comment
@Esq - Милый, чувак! Это потрясающе.   -  person Cody Winton    schedule 05.06.2015
comment
self.perform (#selector (self.someSelector), с: self, afterDelay: 0.1)   -  person Rajeev Udayan    schedule 19.02.2019


Ответы (3)


Swift 4

DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
    // your function here
}

Swift 3

DispatchQueue.main.asyncAfter(deadline: .now() + .seconds(0.1)) {
    // your function here
}

Swift 2

let dispatchTime: dispatch_time_t = dispatch_time(DISPATCH_TIME_NOW, Int64(0.1 * Double(NSEC_PER_SEC))) 
dispatch_after(dispatchTime, dispatch_get_main_queue(), { 
    // your function here 
})
person brandonscript    schedule 11.06.2014
comment
Но это другое. dispatch_after работает с очередями отправки. performSelector:afterDelay: и NSTimer работают над циклами выполнения. - person user102008; 27.08.2014
comment
А ваша точка зрения? Здесь как нельзя лучше подходит НОД ... - person brandonscript; 27.08.2014
comment
Вы должны передать dispatch_time_t в качестве первого аргумента var dispatchTime: dispatch_time_t = dispatch_time(DISPATCH_TIME_NOW, Int64(2.0 * Double(NSEC_PER_SEC))) dispatch_after(dispatchTime, dispatch_get_main_queue(), { // your function here }) - person Vladimirs Matusevics; 19.12.2014
comment
так что если я хочу 3 секунды, я делаю 3.0 * Double (NSEC_PER_SEC)? - person Van Du Tran; 16.02.2015
comment
почему этот dispatch_after лучше, чем NSTimer.scheduledTimerWithTimeInterval? Помимо проблемы типобезопасности методов NSTimer, dispatch_after менее интуитивно понятен, и я не знаю, как обрабатывать область userInfo внутри dispatch_after, поскольку она не принимает аргумент данных. - person mobibob; 04.10.2015
comment
@mobibob вы можете просто вызвать свою функцию с помощью параметра userInfo в качестве параметра в блоке отправки - person Daniel; 17.05.2016
comment
В Swift 3 это делается так ... DispatchQueue.main.asyncAfter (deadline: .now () + 0.1) {// Stuff} - person 365SplendidSuns; 18.11.2016
comment
для последней версии swift это правильный способ создания dispatchTime: let dispatchTime = DispatchTime.now () + 0.1 - person Tung Fam; 12.01.2017
comment
Вот что я использую: DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) { // } - person Thomas Jeans; 05.11.2017
comment
хорошо, но cancelPreviousPerformRequestsWithTarget больше не работает. Есть ли способ отменить запланированную отправку до ее запуска? - person progrmr; 14.11.2017
comment
@progrmr открыть для этого новый вопрос - person brandonscript; 14.11.2017
comment
Селектор выполнения имел возможность отменить это запланированное задание - person Vyachaslav Gerchicov; 31.01.2019

Вы могли сделать это:

var timer = NSTimer.scheduledTimerWithTimeInterval(0.1, target: self, selector: Selector("someSelector"), userInfo: nil, repeats: false)

func someSelector() {
    // Something after a delay
}

SWIFT 3

let timer = Timer.scheduledTimer(timeInterval: 0.1, target: self, selector: #selector(someSelector), userInfo: nil, repeats: false)

func someSelector() {
    // Something after a delay
}
person StevenOjo    schedule 11.06.2014
comment
Хорошо спасибо. Я попробую это. - person Cody Winton; 11.06.2014
comment
Обратите внимание, что этот метод работает только в том случае, если ваш класс наследуется от NSObject или производного класса. Это не будет работать в чистом быстром классе. - person Jason Crump; 31.07.2014
comment
@JasonCrump: он будет работать, пока метод отмечен @objc или dynamic - person user102008; 27.08.2014
comment
Обратите внимание, что это напрямую переводится только для методов без аргументов. Если они принимают один аргумент, в этом случае им будет передан NSTimer, а не данный объект, как в performSelector:afterDelay:. Кроме того, метод ничего не может вернуть. - person user102008; 27.08.2014
comment
Также обратите внимание, что этот метод не будет работать с потоками без цикла выполнения, то есть фоновыми потоками GCD. - person Sean; 31.12.2014
comment
привет, я использовал ваш код в своем проекте, подумал, что вам может быть интересно: github.com/goktugyil/CozyLoadingActivity - person Esqarrouth; 04.06.2015
comment
Чтобы отменить работу потока таймера, я попробовал как timer.invalidate () в swift2. Здесь таймер - это переменная. Попробуйте выполнить следующее: func stopBackgroundTimer () {guard let timerIsAlive = timer else {return} timerIsAlive.invalidate () return} func applicationDidEnterBackground (application: UIApplication) {stopBackgroundTimer ()} - person Sakthimuthiah; 01.12.2015
comment
Когда я использовал этот метод, приложение вылетало, говоря неопознанный селектор. Он работал правильно, когда я напрямую вызвал метод (self. ‹Methodname›) - person sschunara; 17.03.2016

Swift имеет статическую типизацию, поэтому performSelector: методы останутся на второй план.

Вместо этого используйте GCD для отправки подходящего блока в соответствующую очередь - в этом случае, вероятно, это будет основная очередь, поскольку похоже, что вы выполняете работу UIKit.

РЕДАКТИРОВАТЬ: соответствующий performSelector: также заметно отсутствует в Swift версия NSRunLoop документации («1 символ Objective-C скрыт»), так что вы не можете сразу приступить к этому. С учетом этого и его отсутствия в Swiftified NSObject я бы сказал, что довольно ясно, о чем здесь думает Apple.

person Tommy    schedule 11.06.2014
comment
Это проблема. dispatch_get_current_queue устарел, и получить очередь для запуска в текущем потоке (с циклом выполнения) не так просто. У performSelector: методов есть свое место, и они никуда не денутся. - person Leo Natan; 11.06.2014
comment
Здесь это не похоже на проблему - он хочет, чтобы селектор работал с self.view. Так что это, наверное, работа UIKit. Итак, он попадает в основную очередь. В противном случае, я думаю, вам нужно было бы добавить атрибут @objc, чтобы принудительно использовать селектор, несмотря на Swift, и тогда, вероятно, было бы разумно использовать NSRunLoop напрямую, но вы могли бы унаследовать от NSObject, чтобы получить старые performSelectors. - person Tommy; 11.06.2014
comment
Мой комментарий больше касался вашего комментария, а не вопроса. Если в конце концов performSelector: будет отключен искусственно, подойдет простая оболочка категории Objective C. - person Leo Natan; 11.06.2014
comment
После этого он был исключен из Swift-версий документации NSRunLoop и из NSObject. Я действительно думаю, что Apple хочет, чтобы эта функция исчезла. Итак, да, обходной путь на данный момент довольно тривиален, но, основываясь на обычном поведении Apple, я бы сказал, что этот шаблон не стоит одобрять. - person Tommy; 11.06.2014
comment
Поддержка и необходимость - разные вещи. - person Leo Natan; 11.06.2014
comment
+1 от меня за это, но с оговоркой, что полагаясь на то, от чего Apple хочет избавиться, вы, вероятно, купите вам немного больше необходимой работы в будущем, когда эта функция в конечном итоге будет удалена. Если даже Adobe и Microsoft могут вытащить Carbon из-под них (ходили слухи, что 64-битная версия была готова, но Apple просто решила не выпускать ее после многих лет предупреждений), то нам, хоям, не следует принимать логику, которая, очевидно, является объективной. -C всегда будет внизу. - person Tommy; 11.06.2014
comment
@ Томми: от чего Apple хочет избавиться? PerformSelector? или петли? - person newacct; 13.06.2014
comment
@newacct Я размышляю, у меня нет никаких внутренних знаний, но сейчас, вероятно, можно с уверенностью сказать только performSelector; циклы выполнения связаны с планированием событий и особенно с доступом к сети. Но легко представить, что они станут сугубо внутренним делом. И я даю ему пять лет, прежде чем мы полностью попрощаемся с Objective-C. Мост Java просуществовал недолго, и, если шумиха по поводу того, что Swift подходит для системного программирования, верна, мы все чаще будем говорить о мосте, который позволяет Objective-C получать доступ к системе. Хотя, опять же, все домыслы, а не знания. - person Tommy; 13.06.2014
comment
Начиная с Xcode 7, в Swift доступно полное семейство методов performSelector, включая performSelectorOnMainThread() и performSelectorInBackground(). Наслаждаться! - person FizzBuzz; 21.07.2015
comment
@FizzBuzz с оговоркой, что они работают только с классами Objective-C (то есть с классами из подлинных Objective-C и Swift, которые наследуются по любому маршруту от NSObject) - иначе вы получите класс XXX, который не реализует methodSignatureForSelector: - person Tommy; 23.07.2015