Як я можу затримати виклик методу на 1 секунду?


164

Чи є простий спосіб затримати виклик методу на 1 секунду?

У мене є UIImageViewреакція на дотик. Коли дотик виявлено, у додатку трапляються деякі анімації. Через одну секунду я хочу викликати інший метод. У цьому випадку я не можу використовувати animationDidStopселектор.


Звичайно, є кілька способів зробити це, одним із них може бути просто використання сну () для призупинення програми / потоку на кілька мілісекунд, однак я думаю, ви можете сказати нам, що саме ви намагаєтеся досягти, робити це? Я маю на увазі, яка ваша реальна проблема? Ідея затримати виклик методу здається "рішенням", яке не дуже добре, щоб бути чесним. Отже, просто розкажіть нам більше про сценарій, який ви маєте на увазі.
жоден

Відповіді:


254
performSelector:withObject:afterDelay:

Довідка на документ


7
Це правильна відповідь. Перегляньте сторінку developer.apple.com/DOCUMENTATION/Cocoa/Reference/Foundation/… :
шкодить

Чи є якийсь спосіб із зворотним значенням методу, який викликається? Або мені потрібно налаштувати його, щоб змінити параметр, якщо я хочу отримати від нього якусь інформацію?
Гордон Густафсон

якщо когось цікавить, як відмінити запланований дзвінок: [NSObject cancelPreviousPerformRequestsWithTarget: yourTarget Selector: aSelector object: anArgument];
vir us

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(...може бути хорошим варіантом.


Виявив, що це рішення легше, ніж виконувати Selector при змішуванні прямих 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)];

Ви також можете передавати нуль як параметрObject.

приклад:

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

3
Навіщо ти передати себе до себе?
Ерік

2
І навіщо ви передавати змінну методам, який бере нульові аргументи?
hellozimi

23

Відповідей уже багато, і всі вони правильні. У разі, якщо ви хочете скористатися, dispatch_afterвам слід шукати фрагмент, який міститься Code Snippet Libraryв правій нижній частині (де ви можете вибрати UIелементи).

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

Тому вам просто потрібно зателефонувати в цей фрагмент, написавши відправлення в коді:

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


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

Швидкий 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 хвилин після початкового запитання: - )). Жодної інформації про мову в той час не було, тому люб'язно перестаньте судити про правильний спосіб використання сну i XCode і про відсутність класів ...


Тільки в поточному потоці інші потоки продовжуватимуть працювати.
Марк Шарбонно,

4
Гез. Я розумію, чому це було кілька разів проголосовано, але хто, до біса, побачив це в -27 і вирішив, що потрібно інше? Чи не відповідає -3, чи щось, не вдається. Чому б просто не відредагувати відповідь, щоб сказати "це призупинить всю вашу нитку" чи щось замість того, щоб прихильнити це людям?
Альберт Реншо

Що робити, якщо ви просто хочете призупинити всю нитку? Здається, що це дійсний варіант, якщо він має гідне попередження.
Департамент Б

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