답변:
찾고 계신 것 같습니다 dispatch_after()
. 블록이 매개 변수를 허용하지 않아야하지만 블록이 대신 로컬 범위에서 해당 변수를 캡처하도록 할 수 있습니다.
int parameter1 = 12;
float parameter2 = 144.1;
// Delay execution of my block for 10 seconds.
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 10 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{
NSLog(@"parameter1: %d parameter2: %f", parameter1, parameter2);
});
더 : https://developer.apple.com/documentation/dispatch/1452876-dispatch_after
dispatch_time(DISPATCH_TIME_NOW, 10ull * NSEC_PER_SEC)
스 니펫은 불쾌합니다. 더 깨끗한 방법이 없습니까?
dispatch_get_current_queue()
항상 코드가 실행되는 큐를 반환합니다. 따라서이 코드가 메인 스레드에서 실행될 때 블록도 메인 스레드에서 실행됩니다.
dispatch_get_current_queue()
더 이상 사용되지 않습니다
dispatch_after
나중에 블록을 호출하는 데 사용할 수 있습니다 . Xcode에서 입력을 시작 하고 다음과 같이 자동 완성을 dispatch_after
누르십시오 Enter
.
다음은 "인수"로 두 개의 부동 소수점이있는 예입니다. 어떤 유형의 매크로에도 의존 할 필요가 없으며 코드의 의도는 분명합니다.
let time1 = 8.23
let time2 = 3.42
// Delay 2 seconds
DispatchQueue.main.asyncAfter(deadline: .now() + 2.0) {
print("Sum of times: \(time1 + time2)")
}
let time1 = 8.23
let time2 = 3.42
// Delay 2 seconds
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, Int64(2.0 * Double(NSEC_PER_SEC))), dispatch_get_main_queue()) { () -> Void in
println("Sum of times: \(time1 + time2)")
}
CGFloat time1 = 3.49;
CGFloat time2 = 8.13;
// Delay 2 seconds
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
CGFloat newTime = time1 + time2;
NSLog(@"New time: %f", newTime);
});
NSEC_PER_SEC * 0.5
와 동일하게 작동합니다 NSEC_PER_MSEC * 500
. dispatch_time
64 비트 정수 를 예상 한다는 것은 맞지만 , 예상되는 값은 나노초입니다. NSEC_PER_SEC
는로 정의되며 1000000000ull
부동 소수점 상수 0.5
를 사용하여 부동 소수점 산술을 암시 적으로 수행 500000000.0
하여 64 비트 정수로 명시 적으로 캐스팅하기 전에 부동 소수점 산술을 수행합니다 . 따라서 분수를 사용하는 것은 완벽하게 허용됩니다 NSEC_PER_SEC
.
Xcode 내장 코드 스 니펫 라이브러리를 사용하는 것은 어떻습니까?
스위프트 업데이트 :
많은 투표로이 답변을 업데이트 할 수있었습니다.
내장 Xcode 코드 스 니펫 라이브러리는 언어 dispatch_after
전용 objective-c
입니다. 사람들은에 대한 자신 만의 맞춤 코드 스 니펫 을 만들 수도 있습니다 Swift
.
이것을 Xcode로 작성하십시오.
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, Int64(<#delayInSeconds#> * Double(NSEC_PER_SEC))), dispatch_get_main_queue(), {
<#code to be executed after a specified delay#>
})
이 코드를 끌어서 코드 스 니펫 라이브러리 영역에 놓으십시오.
코드 스 니펫 목록의 맨 아래에라는 이름의 새 엔티티가 있습니다 My Code Snippet
. 제목을 편집하십시오. Xcode를 입력 할 때 제안 사항을 입력하십시오 Completion Shortcut
.
자세한 내용은 CustomCodeSnippet 만들기를 참조하십시오 .
이 코드를 끌어서 코드 스 니펫 라이브러리 영역에 놓으십시오.
DispatchQueue.main.asyncAfter(deadline: .now() + .seconds(<#delayInSeconds#>)) {
<#code to be executed after a specified delay#>
}
Jaime Cham의 답변을 확장하여 아래와 같이 NSObject + Blocks 범주를 만들었습니다. 이 방법이 기존 performSelector:
NSObject 방법 과 더 잘 일치한다고 느꼈습니다.
NSObject + Blocks.h
#import <Foundation/Foundation.h>
@interface NSObject (Blocks)
- (void)performBlock:(void (^)())block afterDelay:(NSTimeInterval)delay;
@end
NSObject + Blocks.m
#import "NSObject+Blocks.h"
@implementation NSObject (Blocks)
- (void)performBlock:(void (^)())block
{
block();
}
- (void)performBlock:(void (^)())block afterDelay:(NSTimeInterval)delay
{
void (^block_)() = [block copy]; // autorelease this if you're not using ARC
[self performSelector:@selector(performBlock:) withObject:block_ afterDelay:delay];
}
@end
다음과 같이 사용하십시오.
[anyObject performBlock:^{
[anotherObject doYourThings:stuff];
} afterDelay:0.15];
delay
이어야 NSTimeInterval
(a이다 double
). #import <UIKit/UIKit.h>
필요하지 않습니다. 그리고 왜 - (void)performBlock:(void (^)())block;
유용한 지 알 수 없으므로 헤더에서 제거 할 수 있습니다.
어딘가의 클래스 (예 : "Util") 또는 Object의 Category에서 GCD를 사용하는 것보다 간단 할 수 있습니다.
+ (void)runBlock:(void (^)())block
{
block();
}
+ (void)runAfterDelay:(CGFloat)delay block:(void (^)())block
{
void (^block_)() = [[block copy] autorelease];
[self performSelector:@selector(runBlock:) withObject:block_ afterDelay:delay];
}
그래서 사용하려면 :
[Util runAfterDelay:2 block:^{
NSLog(@"two seconds later!");
}];
스위프트의 경우 dispatch_after
메소드를 사용하여 전역 함수를 만들었습니다. 특별한 것은 없습니다 . 읽기 쉽고 사용하기 쉽기 때문에 이것을 더 좋아합니다.
func performBlock(block:() -> Void, afterDelay delay:NSTimeInterval){
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, Int64(delay * Double(NSEC_PER_SEC))), dispatch_get_main_queue(), block)
}
다음과 같이 사용할 수 있습니다.
performBlock({ () -> Void in
// Perform actions
}, afterDelay: 0.3)
after
. 다음과 같이 쓸 수 있습니다 :after(2.0){ print("do somthing") }
여기 내 2 센트 = 5 방법이 있습니다.)
나는 이러한 세부 사항을 캡슐화하고 AppCode가 문장을 완성하는 방법을 알려주도록합니다.
void dispatch_after_delay(float delayInSeconds, dispatch_queue_t queue, dispatch_block_t block) {
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, delayInSeconds * NSEC_PER_SEC);
dispatch_after(popTime, queue, block);
}
void dispatch_after_delay_on_main_queue(float delayInSeconds, dispatch_block_t block) {
dispatch_queue_t queue = dispatch_get_main_queue();
dispatch_after_delay(delayInSeconds, queue, block);
}
void dispatch_async_on_high_priority_queue(dispatch_block_t block) {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), block);
}
void dispatch_async_on_background_queue(dispatch_block_t block) {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), block);
}
void dispatch_async_on_main_queue(dispatch_block_t block) {
dispatch_async(dispatch_get_main_queue(), block);
}
PerformSelector : WithObject는 항상 객체를 취하므로 int / double / float 등과 같은 인수를 전달하기 위해 이와 같은 것을 사용할 수 있습니다.
// NSNumber는 객체입니다.
[self performSelector:@selector(setUserAlphaNumber:)
withObject: [NSNumber numberWithFloat: 1.0f]
afterDelay:1.5];
-(void) setUserAlphaNumber: (NSNumber*) number{
[txtUsername setAlpha: [number floatValue] ];
}
같은 방법으로 [NSNumber numberWithInt :] 등을 사용할 수 있으며 수신 방법에서 숫자를 [number int] 또는 [number double]과 같은 형식으로 변환 할 수 있습니다.
dispatch_after 함수는 주어진 시간이 지나면 블록 객체를 디스패치 큐로 디스패치합니다. 2.0 초 후에 UI 관련 탁을 수행하려면 아래 코드를 사용하십시오.
let delay = 2.0
let delayInNanoSeconds = dispatch_time(DISPATCH_TIME_NOW, Int64(delay * Double(NSEC_PER_SEC)))
let mainQueue = dispatch_get_main_queue()
dispatch_after(delayInNanoSeconds, mainQueue, {
print("Some UI related task after delay")
})
스위프트 3.0에서 :
let dispatchTime: DispatchTime = DispatchTime.now() + Double(Int64(2.0 * Double(NSEC_PER_SEC))) / Double(NSEC_PER_SEC)
DispatchQueue.main.asyncAfter(deadline: dispatchTime, execute: {
})
mainQueue,
대신mainQueue)
다음 은 성가신 GCD 호출이 반복 되는 것을 방지 하는 편리한 도우미입니다 .
public func delay(bySeconds seconds: Double, dispatchLevel: DispatchLevel = .main, closure: @escaping () -> Void) {
let dispatchTime = DispatchTime.now() + seconds
dispatchLevel.dispatchQueue.asyncAfter(deadline: dispatchTime, execute: closure)
}
public enum DispatchLevel {
case main, userInteractive, userInitiated, utility, background
var dispatchQueue: DispatchQueue {
switch self {
case .main: return DispatchQueue.main
case .userInteractive: return DispatchQueue.global(qos: .userInteractive)
case .userInitiated: return DispatchQueue.global(qos: .userInitiated)
case .utility: return DispatchQueue.global(qos: .utility)
case .background: return DispatchQueue.global(qos: .background)
}
}
}
이제 다음 과 같이 Main 스레드에서 코드를 지연시킵니다 .
delay(bySeconds: 1.5) {
// delayed code
}
다른 스레드로 코드 를 지연하려면 다음을 수행하십시오 .
delay(bySeconds: 1.5, dispatchLevel: .background) {
// delayed code that will run on background thread
}
좀 더 편리한 기능을 가진 프레임 워크 를 선호한다면 HandySwift 를 확인 하십시오 . Carthage 를 통해 프로젝트에 추가 한 다음 위의 예와 동일하게 사용할 수 있습니다.
import HandySwift
delay(bySeconds: 1.5) {
// delayed code
}
Swift에서 지연 후 블록을 트리거하는 방법은 다음과 같습니다.
runThisAfterDelay(seconds: 2) { () -> () in
print("Prints this 2 seconds later in main queue")
}
/// EZSwiftExtensions
func runThisAfterDelay(seconds seconds: Double, after: () -> ()) {
let time = dispatch_time(DISPATCH_TIME_NOW, Int64(seconds * Double(NSEC_PER_SEC)))
dispatch_after(time, dispatch_get_main_queue(), after)
}
그것은 내 repo 의 표준 기능으로 포함되어 있습니다 .
스위프트 3 및 Xcode 8.3.2
이 코드는 당신을 도울 것입니다, 나도 설명을 추가합니다
// Create custom class, this will make your life easier
class CustomDelay {
static let cd = CustomDelay()
// This is your custom delay function
func runAfterDelay(_ delay:Double, closure:@escaping ()->()) {
let when = DispatchTime.now() + delay
DispatchQueue.main.asyncAfter(deadline: when, execute: closure)
}
}
// here how to use it (Example 1)
class YourViewController: UIViewController {
// example delay time 2 second
let delayTime = 2.0
override func viewDidLoad() {
super.viewDidLoad()
CustomDelay.cd.runAfterDelay(delayTime) {
// This func will run after 2 second
// Update your UI here, u don't need to worry to bring this to the main thread because your CustomDelay already make this to main thread automatically :)
self.runFunc()
}
}
// example function 1
func runFunc() {
// do your method 1 here
}
}
// here how to use it (Example 2)
class YourSecondViewController: UIViewController {
// let say you want to user run function shoot after 3 second they tap a button
// Create a button (This is programatically, you can create with storyboard too)
let shootButton: UIButton = {
let button = UIButton(type: .system)
button.frame = CGRect(x: 15, y: 15, width: 40, height: 40) // Customize where do you want to put your button inside your ui
button.setTitle("Shoot", for: .normal)
button.translatesAutoresizingMaskIntoConstraints = false
return button
}()
override func viewDidLoad() {
super.viewDidLoad()
// create an action selector when user tap shoot button
shootButton.addTarget(self, action: #selector(shoot), for: .touchUpInside)
}
// example shoot function
func shoot() {
// example delay time 3 second then shoot
let delayTime = 3.0
// delay a shoot after 3 second
CustomDelay.cd.runAfterDelay(delayTime) {
// your shoot method here
// Update your UI here, u don't need to worry to bring this to the main thread because your CustomDelay already make this to main thread automatically :)
}
}
}