ฉันจะใช้ NSTimer ได้อย่างไร


344

ฉันจะใช้อย่างไรNSTimer? ทุกคนสามารถให้คำแนะนำทีละขั้นตอนกับฉันได้ไหม


1
ฉันได้ข้อมูลตามพารามิเตอร์บนpravinmagdum.wordpress.com/2010/12/30/how-to-use-nstimerได้ดูมัน .. อาจเป็นประโยชน์สำหรับคุณ

คำตอบ:


616

ก่อนอื่นฉันต้องการดึงความสนใจของคุณไปที่เอกสาร Cocoa / CF (ซึ่งเป็นพอร์ตแรกที่ยอดเยี่ยมสำหรับการโทร) เอกสาร Apple มีส่วนที่ด้านบนของบทความอ้างอิงแต่ละบทความที่เรียกว่า "คู่มือการใช้งานร่วม" ซึ่งจะแสดงรายการคู่มือสำหรับหัวข้อที่มีการบันทึกไว้ (ถ้ามี) ตัวอย่างเช่นกับNSTimer, เอกสารรายการสองคำแนะนำสหาย:

สำหรับสถานการณ์ของคุณบทความตัวตั้งเวลาหัวข้อการเขียนโปรแกรมน่าจะมีประโยชน์มากที่สุดในขณะที่หัวข้อเธรดเกี่ยวข้อง แต่ไม่เกี่ยวข้องโดยตรงกับคลาสที่มีการจัดทำเอกสาร หากคุณดูที่หัวข้อหัวข้อการเขียนโปรแกรมตั้งเวลามันจะแบ่งออกเป็นสองส่วน:

  • จับเวลา
  • ใช้ตัวจับเวลา

สำหรับบทความที่ใช้รูปแบบนี้มักจะมีภาพรวมของชั้นเรียนและสิ่งที่ใช้สำหรับและจากนั้นตัวอย่างโค้ดบางส่วนเกี่ยวกับวิธีการใช้งานในกรณีนี้ในส่วน "การใช้ตัวจับเวลา" มีส่วนต่าง ๆ เกี่ยวกับ "การสร้างและการตั้งเวลา", "การหยุดตัวจับเวลา" และ "การจัดการหน่วยความจำ" จากบทความการสร้างตัวจับเวลาที่กำหนดเวลาและไม่ทำซ้ำสามารถทำได้ดังนี้:

[NSTimer scheduledTimerWithTimeInterval:2.0
    target:self
    selector:@selector(targetMethod:)
    userInfo:nil
    repeats:NO];

สิ่งนี้จะสร้างตัวจับเวลาที่ใช้งานหลังจาก 2.0 วินาทีและเรียกtargetMethod:ใช้selfด้วยอาร์กิวเมนต์หนึ่งตัวซึ่งเป็นตัวชี้ไปยังNSTimerอินสแตนซ์

หากคุณต้องการดูรายละเอียดเพิ่มเติมเกี่ยวกับวิธีการที่คุณสามารถอ้างถึงเอกสารสำหรับข้อมูลเพิ่มเติม แต่มีคำอธิบายรอบรหัสด้วย

หากคุณต้องการหยุดตัวจับเวลาที่ซ้ำ (หรือหยุดตัวจับเวลาที่ไม่ซ้ำกันก่อนที่จะเกิดไฟไหม้) คุณต้องเก็บตัวชี้ไปยังNSTimerอินสแตนซ์ที่สร้างขึ้น บ่อยครั้งสิ่งนี้จะต้องเป็นตัวแปรอินสแตนซ์เพื่อให้คุณสามารถอ้างอิงได้ในวิธีอื่น จากนั้นคุณสามารถโทรinvalidateบนNSTimerเช่น:

[myTimer invalidate];
myTimer = nil;

เป็นวิธีปฏิบัติที่ดีที่จะnilใช้ตัวแปรอินสแตนซ์ (ตัวอย่างเช่นหากวิธีการของคุณที่ทำให้ตัวจับเวลาใช้ไม่ได้ถูกเรียกมากกว่าหนึ่งครั้งและตัวแปรอินสแตนซ์ไม่ได้ถูกตั้งค่าเป็นnilและNSTimerอินสแตนซ์ถูกยกเลิกการจัดสรรแล้ว

หมายเหตุถึงประเด็นการจัดการหน่วยความจำที่ด้านล่างของบทความ:

เพราะห่วงวิ่งรักษาจับเวลาจากมุมมองของการจัดการหน่วยความจำมีมักจะไม่จำเป็นต้องให้มีการอ้างอิงถึงการจับเวลาหลังจากที่คุณได้กำหนดไว้มัน เนื่องจากตัวจับเวลาถูกส่งผ่านเป็นอาร์กิวเมนต์เมื่อคุณระบุวิธีการเป็นตัวเลือกคุณสามารถทำให้ตัวจับเวลาทำซ้ำได้ตามความเหมาะสมภายในวิธีการนั้น อย่างไรก็ตามในหลาย ๆ สถานการณ์คุณต้องการตัวเลือกในการทำให้ตัวจับเวลาใช้ไม่ได้ - แม้กระทั่งก่อนที่จะเริ่ม ในกรณีนี้คุณจำเป็นต้องอ้างอิงถึงตัวจับเวลาเพื่อให้คุณสามารถส่งข้อความที่ไม่ถูกต้องตามความเหมาะสม. หากคุณสร้างตัวจับเวลาที่ไม่ได้กำหนดไว้ (ดู“ ตัวจับเวลาที่ไม่ได้จัดตารางเวลา”) คุณต้องรักษาการอ้างอิงที่รัดกุมเกี่ยวกับตัวจับเวลา (ในสภาพแวดล้อมที่นับการอ้างอิงคุณเก็บไว้) เพื่อที่จะไม่ได้ถูกจัดสรรคืน


ตกลงคำถามหนึ่งข้อฉันจะใส่อะไรในโค้ดของฉันที่จะถูกเรียกใช้งานทุกสองวินาที
lab12

คุณจะผ่านYESสำหรับเมื่อคุณเรียกrepeats: scheduledTimerWithTimeInterval:target:selector:userInfo:repeats:ถ้าคุณทำเช่นนั้นให้แน่ใจว่าได้อ้างอิงถึงNSTimerอินสแตนซ์ (มันจะถูกส่งกลับโดยวิธีการ) และทำตามจุดในการจัดการหน่วยความจำตามที่ฉันอธิบายไว้ข้างต้น
Alex Rozanski

ไม่ฉันจะวางรหัสของฉันที่จะเริ่มต้นทุก 2 วินาทีที่ไหน ตัวอย่างเช่นสมมติว่าฉันต้องการให้ส่งเสียงบี๊บทุก 2 วินาที ฉันจะใส่รหัสเสียงบี๊บที่ไหน
lab12

ในวิธีการที่คุณระบุด้วยและtarget selectorตัวอย่างเช่นถ้าเป้าหมายของคุณselfและเลือกเป็นtimerMethod:วิธีการที่เรียกว่าเมื่อเกิดเพลิงไหม้ตัวจับเวลาที่กำหนดไว้ในtimerMethod: selfจากนั้นคุณสามารถใส่รหัสใดก็ได้ที่คุณต้องการในวิธีการนั้นและวิธีการนั้นจะถูกเรียกเมื่อใดก็ตามที่ตัวจับเวลายิง โปรดทราบว่าวิธีการที่เรียกเมื่อตัวจับเวลายิง (ที่คุณผ่านเป็นselector:) สามารถใช้อาร์กิวเมนต์เดียวเท่านั้น (ซึ่งเมื่อเรียกว่าเป็นตัวชี้ไปยังNSTimerอินสแตนซ์)
Alex Rozanski

ขออภัยแปลว่า "define on self"
Alex Rozanski

331

มีสองวิธีในการใช้ตัวจับเวลา:

1) ตั้งเวลาและใช้ตัวเลือก

NSTimer *t = [NSTimer scheduledTimerWithTimeInterval: 2.0
                      target: self
                      selector:@selector(onTick:)
                      userInfo: nil repeats:NO];
  • หากคุณตั้งค่าซ้ำเป็น NO ตัวจับเวลาจะรอ 2 วินาทีก่อนเรียกใช้ตัวเลือกและหลังจากนั้นจะหยุด
  • หากทำซ้ำ: ใช่ตัวจับเวลาจะเริ่มทันทีและจะเรียกตัวเลือกซ้ำทุกๆ 2 วินาที
  • เพื่อหยุดตัวจับเวลาที่คุณเรียกใช้เมธอด -invalidate: [t ทำให้ใช้งานไม่ได้];

ในฐานะที่เป็นบันทึกด้านข้างแทนที่จะใช้ตัวจับเวลาที่ไม่ซ้ำและเรียกตัวเลือกหลังจากช่วงเวลาที่ระบุคุณสามารถใช้คำสั่งแบบง่าย ๆ ดังนี้:

[self performSelector:@selector(onTick:) withObject:nil afterDelay:2.0];

สิ่งนี้จะมีผลเช่นเดียวกับโค้ดตัวอย่างด้านบน แต่ถ้าคุณต้องการโทรหาตัวเลือกทุกครั้งที่ n คุณจะใช้ตัวจับเวลาซ้ำ: YES;

2) ตัวจับเวลาที่กำหนดเอง

NSDate *d = [NSDate dateWithTimeIntervalSinceNow: 60.0];
NSTimer *t = [[NSTimer alloc] initWithFireDate: d
                              interval: 1
                              target: self
                              selector:@selector(onTick:)
                              userInfo:nil repeats:YES];

NSRunLoop *runner = [NSRunLoop currentRunLoop];
[runner addTimer:t forMode: NSDefaultRunLoopMode];
[t release];
  • สิ่งนี้จะสร้างตัวจับเวลาที่จะเริ่มตัวเองในวันที่กำหนดเองที่คุณระบุ (ในกรณีนี้หลังจากผ่านไปหนึ่งนาที) และทำซ้ำตัวเองทุกหนึ่งวินาที

3) ตัวจับเวลาที่ไม่ได้กำหนดไว้และใช้การร้องขอ

NSMethodSignature *sgn = [self methodSignatureForSelector:@selector(onTick:)];
NSInvocation *inv = [NSInvocation invocationWithMethodSignature: sgn];
[inv setTarget: self];
[inv setSelector:@selector(onTick:)];

NSTimer *t = [NSTimer timerWithTimeInterval: 1.0
                      invocation:inv 
                      repeats:YES];

และหลังจากนั้นคุณเริ่มจับเวลาด้วยตนเองเมื่อใดก็ตามที่คุณต้องการเช่นนี้

NSRunLoop *runner = [NSRunLoop currentRunLoop];
[runner addTimer: t forMode: NSDefaultRunLoopMode];



และเป็นทราบวิธี onTick: มีลักษณะเช่นนี้:

-(void)onTick:(NSTimer *)timer {
   //do smth
}

ตกลง แต่คุณเห็นว่าฉันต้องการลดความโปร่งใสของแอพของฉันดังนั้นฉันจึงไม่รู้ว่าจะใช้กับ NSTimer ได้อย่างไร
ปฏิบัติการ 12

24
jeez, คนเหล่านี้วันนี้ .. โหวตจากฉันเพราะคุณไม่ได้ระบุไว้ตั้งแต่ต้นและให้พวกเราเขียนอย่างไร้ประโยชน์!
Woofy

28
คุณไม่ได้เขียนไร้สาระ นี่คือข้อมูลที่ดี!
willc2

ในวิธีที่ 2 "ตัวจับเวลาที่กำหนดเอง" ฉันจะหยุดตัวจับเวลาได้อย่างไรเมื่อฉันต้องการ
Satyam

1
@Satyamsvv คุณสามารถหยุดตัวจับเวลาโดยเรียกใช้พูดวิธีอื่นที่มี: [ตัวจับเวลาทำให้ใช้ไม่ได้]; จับเวลา = ศูนย์;
Kimpoy

59

บางสิ่งเช่นนี้

NSTimer *timer;

    timer = [NSTimer scheduledTimerWithTimeInterval: 0.5
                     target: self
                     selector: @selector(handleTimer:)
                     userInfo: nil
                     repeats: YES];

14
ยังคงแข็งแกร่ง ... 2557 เช่นกัน!
Muruganandham K

5
#import "MyViewController.h"

@interface MyViewController ()

@property (strong, nonatomic) NSTimer *timer;

@end

@implementation MyViewController

double timerInterval = 1.0f;

- (NSTimer *) timer {
    if (!_timer) {
        _timer = [NSTimer timerWithTimeInterval:timerInterval target:self selector:@selector(onTick:) userInfo:nil repeats:YES];
    }
    return _timer;
}

- (void)viewDidLoad
{
    [super viewDidLoad];

    [[NSRunLoop mainRunLoop] addTimer:self.timer forMode:NSRunLoopCommonModes];
}

-(void)onTick:(NSTimer*)timer
{
    NSLog(@"Tick...");
}

@end

ยังไงก็เถอะมันจะสร้างวงจรการเก็บรักษาดังนั้นจึงMyViewControllerไม่เคยได้รับการจัดสรรคืน
Darrarski

5
NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:60 target:self selector:@selector(timerCalled) userInfo:nil repeats:NO];

-(void)timerCalled
{
     NSLog(@"Timer Called");
     // Your Code
}

คุณเขียนนี่ที่ไหน
Mohit

1
@JigneshB คำตอบนี้เป็นเพียงเรื่องเกี่ยวกับวิธีการใช้ NSTimer ไม่เกี่ยวกับการใช้งานในพื้นหลัง
Mohit

ฉันเขียนในวิธีพื้นหลังเช่น - (void) applicationDidEnterBackground: (UIApplication *) แอปพลิเคชัน {}
Jignesh B

ด้วยโหมดซ้ำซ้อนใช่
Jignesh B

เอกสารของ Apple นั้นเฉพาะเจาะจงมากเกี่ยวกับลายเซ็นของวิธีการติดต่อกลับ คุณเป็นคนผิด
Nikolai Ruhe

2

คำตอบจะหายไปเวลาที่กำหนดเวลาของวันที่นี่คือในชั่วโมงถัดไป:

NSCalendarUnit allUnits = NSCalendarUnitYear   | NSCalendarUnitMonth |
                          NSCalendarUnitDay    | NSCalendarUnitHour  |
                          NSCalendarUnitMinute | NSCalendarUnitSecond;

NSCalendar *calendar = [[ NSCalendar alloc]  
                          initWithCalendarIdentifier:NSGregorianCalendar];

NSDateComponents *weekdayComponents = [calendar components: allUnits 
                                                  fromDate: [ NSDate date ] ];

[ weekdayComponents setHour: weekdayComponents.hour + 1 ];
[ weekdayComponents setMinute: 0 ];
[ weekdayComponents setSecond: 0 ];

NSDate *nextTime = [ calendar dateFromComponents: weekdayComponents ];

refreshTimer = [[ NSTimer alloc ] initWithFireDate: nextTime
                                          interval: 0.0
                                            target: self
                                          selector: @selector( doRefresh )
                                          userInfo: nil repeats: NO ];

[[NSRunLoop currentRunLoop] addTimer: refreshTimer forMode: NSDefaultRunLoopMode];

แน่นอนแทนที่ "doRefresh" ด้วยวิธีการที่ต้องการในชั้นเรียนของคุณ

พยายามสร้างวัตถุปฏิทินหนึ่งครั้งและทำให้หน่วยทั้งหมดเป็นแบบสแตติกเพื่อประสิทธิภาพ

การเพิ่มคอมโพเนนต์หนึ่งชั่วโมงทำงานได้ดีไม่จำเป็นต้องทดสอบเที่ยงคืน ( ลิงก์ )

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.