开发者

How do I increment NSTimer for time in a label?

I'm a fledgling iPhone developer, so be easy on me.

I'm trying to develop a simple app that will show the time and then tick every second. I feel like I'm missing something here with memory management, but my skills are too fresh to really know what I'm missing.

I'm creating a label straight to the main window (really simple app) and trying to update the label through and NSTimer. Here is my bit of code, it's still a little messy.

@synthesize label, theDate;
@synthesize window;

- (void)tick 
{
    theDate = [[NSDateFormatter alloc] init];
    [theDate setDateFormat:@"hh:mm:ss"];
    NSString* currentTime = [theDate stringFromDate:[NSDate date]];
    开发者_开发技巧label.text = [[NSString alloc] initWithFormat:@"%d",currentTime];
    [currentTime release];
}

- (BOOL)application:(UIApplication *)application 
    didFinishLaunchingWithOptions:(NSDictionary *)launchOptions     
{
    CGRect rect = CGRectMake(10, 200, 300, 20);
    label = [[UILabel alloc] initWithFrame:rect];
    label.textAlignment = UITextAlignmentCenter;
    [self.window addSubview:label];
    [NSTimer scheduledTimerWithTimeInterval:1.0f 
                                     target:self 
                                   selector:@selector(tick) 
                                   userInfo:nil 
                                    repeats:YES];
    [self.window makeKeyAndVisible];

    return YES;
}

The @synthesize'd ivars are @propertys in the .h file and the ivars get released in dealloc.

Thanks!


You have a number of memory problems here:

  • You are alloc'ing theDate but not releasing it, so it's leaking.
  • You are releasing currentTime despite not having an owning reference, so you'll likely see crashes in the autorelease pool.
  • You are alloc'ing the value assigned to label.text but not releasing it; either label.text is a retaining property, in which case you are leaking that string by double-retaining it, or label.text is not retaining, in which case you are leaking the string by never releasing it (except for the very last one, in dealloc)

I'd strongly suggest you read Apple's memory management guide.

Also, unrelated to the memory issues, you are using %d to try to show a string instead of %@, so you'll get the numeric value of the pointer address rather than the contents of the string.


You shouldn't release currentTime. You didn't get hold of it through something with 'new', 'alloc', 'retain' or 'create' in the name, so you don't own it. What you are doing is allocating an unrelated string and giving it to label.text, then failing to release that. Suggest you replace those three lines with just:

NSString* currentTime = [theDate stringFromDate:[NSDate date]];
label.text = currentTime;

It's up to the UILabel to retain the string if it wants to keep it (I expect it will, but it's an implementation detail and none of our business either way), and you don't own it so can just leave it to expire on the autorelease pool.

In the same method you also create an NSFormatter called 'theDate' and fail to release it. Actually, you seem to be a bit confused about getters and setters, which isn't surprising since there's a bit of Objective-C heritage at play here. If you do something like:

theData = ...whatever...;

Then you'll directly copy the value specified into the variable, as per the normal C '=' operator. There's no Objective-C magic there. Whether and how you've declared your property is (largely, see foot note) irrelevant.

If you something like:

self.theData = ...whatever...;

Then the compiler will act exactly as if you'd written:

[self setTheData:...whatever...];

So you get a method call and your actual setter will be used. The setter will do whatever you told it to via the @property/@synthesize (ie, retain, copy or assign). Hence, at dealloc you tend to see either:

- (void)dealloc
{
    [property1 release];
    [property2 release];
    [super dealloc];
}

Or:

- (void)dealloc
{
    self.property1 = nil;
    self.property2 = nil;
    [super dealloc];
}

Which have the same overall effect with 'retain' properties (though the latter actually releases the original then retains 'nil', any message to 'nil' having no effect).

The same confusion possibly affects your use of label, but what you're doing at the minute is technically correct. If you'd used 'self.label =' instead of the direct assignment then you'd want to pass an autoreleased object or one that you know how to release later on.

Addition: it's well worth checking out NSZombies and the Leaks tool in Instruments; the former will help you find out when and how you're accessing deallocated objects, the latter will help you spot when you're leaking memory. Guard Malloc is also useful for the former but carries a much larger runtime overhead and I'm not sure how well it works with iOS at present.

(foot note: in the modern 64 bit and ARM runtimes, instance variables are dynamic with the practical effect that you can declare them purely via @property and @synthesize without otherwise putting them in the @interface declaration; if you're doing that then obviously the presence or absence of the @property will affect whether direct access works)


  1. Put this(theDate = [[NSDateFormatter alloc] init];) line in the applicationDidFinishLoading. So that theDate will be allocated once.
  2. Replace your tick function with this one:-

    • (void)tick { theDate = [[NSDateFormatter alloc] init]; [theDate setDateFormat:@"hh:mm:ss"]; NSString* currentTime = [theDate stringFromDate:[NSDate date]]; label.text = currentTime; }
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜