Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
385 views
in Technique[技术] by (71.8m points)

objective c - Obj-C -> Incrementing a number (and showing steps on a Cocoa label)

I'm new with Objective-C, so there probably is a simple solution to this.

I want a number to increment, but each iteration to be show on a label. (for example, it shows 1, 2, 3, 4, 5... displayed apart by an amount of time).

I tried:

#import "testNums.h"

@implementation testNums
- (IBAction)start:(id)sender {
    int i;
    for(i = 0; i < 10; ++i)
    {
        [outputNum setIntValue:i];
        sleep(1);
    }
}
@end

and all it did was wait for 9 seconds (apparently frozen) and then displayed 9 in the text box.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

To allow the run loop to run between messages, use an NSTimer or delayed perform. Here's the latter:

- (IBAction) start:(id)sender {
    [self performSelector:@selector(updateTextFieldWithNumber:) withObject:[NSNumber numberWithInt:0] afterDelay:1.0];
}

- (void) updateTextFieldWithNumber:(NSNumber *)num {
    int i = [num intValue];
    [outputField setIntValue:i];
    if (i < 10)
        [self performSelector:@selector(updateTextFieldWithNumber:) withObject:[NSNumber numberWithInt:++i] afterDelay:1.0];
}

Here's one timer-based solution. You may find it easier to follow. You could set the text field's value from the text field:

@interface TestNums: NSObject
{
    IBOutlet NSTextField *outputField;
    NSTimer *timer;
    int currentNumber;
}

@end

@implementation TestNums

- (IBAction) start:(id)sender {
    timer = [[NSTimer scheduledTimerWithTimeInterval:1.0
        target:self
        selector:@selector(updateTextField:)
        userInfo:nil
        repeats:YES] retain];

    //Set the field's value immediately to 0
    currentNumber = 0;
    [outputField setIntValue:currentNumber];
}

- (void) updateTextField:(NSTimer *)timer {
    [outputField setIntValue:++currentNumber];
}

@end

Here's an even better (cleaner) timer-based solution, using a property. You'll need to bind the text field to the property in Interface Builder (select the field, press ?4, choose your object, and enter currentNumber as the key to bind to).

@interface TestNums: NSObject
{
    //NOTE: No outlet this time.
    NSTimer *timer;
    int currentNumber;
}

@property int currentNumber;

@end

@implementation TestNums

@synthesize currentNumber;

- (IBAction) start:(id)sender {
    timer = [[NSTimer scheduledTimerWithTimeInterval:1.0
        target:self
        selector:@selector(updateTextField:)
        userInfo:nil
        repeats:YES] retain];

    //Set the field's value immediately to 0
    self.currentNumber = 0;
}

- (void) updateTextField:(NSTimer *)timer {
    self.currentNumber = ++currentNumber;
}

@end

The property-based solution has at least two advantages:

  1. Your object doesn't need to know about the text field. (It is a model object, separate from the view object that is the text field.)
  2. To add more text fields, you simply create and bind them in IB. You don't have to add any code to the TestNums class.

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...