Как я могу отложить вызов метода на 1 секунду?


164

Есть ли простой способ отложить вызов метода на 1 секунду?

У меня есть, UIImageViewчто реагирует на событие касания. При обнаружении касания в приложении происходят некоторые анимации. Через одну секунду я хочу вызвать другой метод. В этом случае я не могу использовать animationDidStopселектор.


Конечно, есть несколько способов сделать это, один из них может заключаться в простом использовании sleep () для приостановки программы / потока на несколько миллисекунд, однако я думаю, что вы, возможно, захотите рассказать нам, чего именно вы пытаетесь достичь делая это? Я имею в виду, в чем ваша проблема? Идея отсрочки вызова метода кажется «решением», которое звучит не слишком хорошо, чтобы быть честным. Итак, просто расскажите нам больше о сценарии, который вы имеете в виду.
нет

Ответы:


254
performSelector:withObject:afterDelay:

Ссылка на документ


7
Это правильный ответ. Пожалуйста, смотрите developer.apple.com/DOCUMENTATION/Cocoa/Reference/Foundation/… :
наносит вред

Есть ли способ что-то с возвращаемым значением метода, который вызывается? Или мне нужно настроить его для изменения параметра, если я хочу получить от него некоторую информацию?
Гордон Густафсон

если кому-то интересно, как отменить запланированный вызов: [NSObject cancelPreviousPerformRequestsWithTarget: ваш селектор цели: объект aSelector: anArgument];
Вир с нами

192

Вы также можете использовать блок

dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 1 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{
    [object method]; 
});

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

Редактировать:

Версия Swift 3:

DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
    object.method()
}

Точно так же DispatchQueue.global().asyncAfter(...может быть хорошим вариантом.


Обнаружил, что это решение проще, чем executeSelector, при смешивании прямых C и ObjC
Пол Слокум

1
К сожалению, dispatch_get_current_queue устарела с iOS6
chrisben

3
Обновлен для использования dispatch_get_main_queue вместо dispatch_get_current_queue
mcfedr

2
Xcode теперь автоматически завершит это, просто начните печатать dispatch_afterи нажмите enter
mcfedr

1
Особенно теперь, когда XCode автоматически завершает это при наборе текста dispatch_after, это действительно очень простой способ сделать это, плюс вы можете передать свойства вызываемому методу, и это здорово.
Эрик ван дер Нойт

128

Лучший способ сделать это:

[self performSelector:@selector(YourFunctionName) 
           withObject:(can be Self or Object from other Classes) 
           afterDelay:(Time Of Delay)];

Вы также можете передать nil как параметр withObject.

пример :

[self performSelector:@selector(subscribe) withObject:self afterDelay:3.0 ];

3
Почему вы передаете себя себе?
Эрик

2
И почему вы передаете переменную методам, которые принимают нулевые аргументы?
hellozimi

23

Ответов уже много, и все они правильные. Если вы хотите использовать его, dispatch_afterвы должны искать фрагмент, который находится внутри Code Snippet Libraryсправа внизу (где вы можете выбрать UIэлементы).

введите описание изображения здесь

Так что вам просто нужно вызвать этот фрагмент, написав dispatch в коде:

введите описание изображения здесь


16

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

[self performSelector:@selector(InsertView)  withObject:nil afterDelay:0.1]; 

9

Вы также можете:

[UIView animateWithDuration:1.0
                 animations:^{ self.view.alpha = 1.1; /* Some fake chages */ }
                 completion:^(BOOL finished)
{
    NSLog(@"A second lapsed.");
}];

В этом случае вы должны подделать некоторые изменения в некоторых видах, чтобы получить анимацию. Это действительно хакерство, но мне нравятся блочные вещи. Или оберните ответ @mcfedr ниже.


waitFor(1.0, ^
{
    NSLog(@"A second lapsed");
});

typedef void (^WaitCompletionBlock)();
void waitFor(NSTimeInterval duration, WaitCompletionBlock completion)
{
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, duration * NSEC_PER_SEC),
                   dispatch_get_main_queue(), ^
    { completion(); });
}

Не уверен, но я думаю, что первый вариант, который вы предлагаете, может иметь побочные эффекты, о которых должны знать пользователи, например, блокирование взаимодействия пользователя с частями пользовательского интерфейса. Мой инстинкт заключается в том, что это также может привести к некоторой ненужной загрузке процессора или других ресурсов, но я не проверял.
Бьорн Рош

8

Ты можешь сделать это

[self performSelector:@selector(MethodToExecute) withObject:nil afterDelay:1.0 ];

4

Swift 2.x

let delayTime = dispatch_time(DISPATCH_TIME_NOW, Int64(1 * Double(NSEC_PER_SEC)))
 dispatch_after(delayTime, dispatch_get_main_queue()) {
 print("do some work")
}

Swift 3.x - & - Swift 4

DispatchQueue.main.asyncAfter(deadline: .now() + 1.0) {
    print("do some work")
}

или передать escaping closure

func delay(seconds: Double, completion: @escaping()-> Void) {
    DispatchQueue.main.asyncAfter(deadline: .now() + seconds, execute: completion)
}

1

Существует решение Swift 3 из проверенного решения:

self.perform(#selector(self.targetMethod), with: self, afterDelay: 1.0)

И есть метод

@objc fileprivate func targetMethod(){

}


-34

ПРИМЕЧАНИЕ: это приостановит всю цепочку, а не только один метод.
Сделать вызов в режим сна / ожидания / остановки на 1000 мс перед вызовом вашего метода?

Sleep(1000); // does nothing the next 1000 mSek

Methodcall(params); // now do the real thing

Изменить: приведенный выше ответ относится к общему вопросу «Как я могу отложить вызов метода на 1 секунду?», Который был задан во время ответа (фактически ответ был дан в течение 7 минут после исходного вопроса: - )). В то время не было предоставлено никакой информации о языке, поэтому, пожалуйста, прекратите ссориться о правильном способе использования сна в коде отсутствия классов ...


Только в текущем потоке другие потоки будут продолжать работать.
Марк Шарбонно

4
Geez. Я понимаю, почему за это проголосовали несколько раз, но кто, черт возьми, видел это в -27 и решил, что нужен еще один? -3 или что-то не так. Почему бы просто не отредактировать ответ, чтобы сказать «это приостановит всю вашу тему» ​​или что-то вместо того, чтобы понизить голосование, люди?
Альберт Реншоу

Так что, если вы просто хотите приостановить всю цепочку? Похоже, правильный вариант, если он идет с достойным предупреждением.
Departamento B

@AlbertRenshaw Я полностью согласен с тобой. Я здесь и у меня 35 падений, и я бросил его. Мне кажется, что я так сильно нападаю на пользователей с низкой репутацией. Никто не будет редактировать или указывать что-либо. Я видел один ответ сегодня, что он действительно утонул. Единственная ошибка, которую совершил этот человек, это то, что он / она ответил на быстрый вопрос с объективным языком c. Если это огромная ошибка, я хочу показать так много быстрых ответов на поставленные объективные вопросы.
soorej babu
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.