我是一个初出茅庐的iPhone开发者,所以对我来说很容易。
我正在尝试开发一个简单应用程序,它会显示时间,然后每秒打勾。我觉得我在这里缺少记忆管理的东西,但我的技能太新鲜了,不知道我错过了什么。
我正在直接创建主窗口标签(非常简单的应用程序)并尝试通过NSTimer
更新标签。这是我的一些代码,它仍然有点凌乱。
@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;
}
。@synthesize
'd。在.h文件中为@property
,而ivars在dealloc中释放。
谢谢!
答案 0 :(得分:1)
这里有许多内存问题:
theDate
但没有释放它,所以它正在泄漏。currentTime
,因此您可能会在自动发布池中看到崩溃。label.text
但未释放的值; label.text是一个保留属性,在这种情况下,你通过双重保留它来泄漏该字符串,或者label.text没有保留,在这种情况下你通过永远不释放它来泄漏字符串(除了最后一个,在dealloc)我强烈建议你阅读Apple's memory management guide。
此外,与内存问题无关,您使用%d
尝试显示字符串而不是%@
,因此您将获得指针地址的数值而不是内容字符串。
答案 1 :(得分:1)
您不应该发布currentTime。您没有通过名称中的“new”,“alloc”,“retain”或“create”来获取它,因此您不拥有它。你正在做的是分配一个不相关的字符串并将其提供给label.text,然后无法释放它。建议你用以下代码替换这三行:
NSString* currentTime = [theDate stringFromDate:[NSDate date]];
label.text = currentTime;
UILabel要保留字符串,如果它想保留它(我希望它会,但它是一个实现细节而不管我们的业务),你不拥有它所以可以保留它在自动释放池上过期。
在同一方法中,您还创建了一个名为“theDate”的NSFormatter,但无法释放它。实际上,你似乎对吸气剂和制定者有点困惑,这并不奇怪,因为这里有一些Objective-C遗产。如果您执行以下操作:
theData = ...whatever...;
然后,您将直接将指定的值复制到变量中,按照正常的C'='运算符。那里没有Objective-C魔法。你是否以及如何申报你的财产(主要是看脚注)是无关紧要的。
如果您喜欢:
self.theData = ...whatever...;
然后编译器的行为就像你写的那样:
[self setTheData:...whatever...];
因此,您将获得一个方法调用,并且将使用您的实际setter。 setter将通过@ property / @ synthesize(即,保留,复制或赋值)执行您告诉它的任何操作。因此,在dealloc你倾向于看到:
- (void)dealloc
{
[property1 release];
[property2 release];
[super dealloc];
}
或者:
- (void)dealloc
{
self.property1 = nil;
self.property2 = nil;
[super dealloc];
}
与“保留”属性具有相同的整体效果(虽然后者实际上释放原始然后保留'nil',任何消息'nil'都没有效果。)
同样的混淆可能会影响您对标签的使用,但您现在所做的事情在技术上是正确的。如果您使用'self.label ='而不是直接赋值,那么您需要传递一个自动释放的对象或者您知道如何稍后释放的对象。
另外:非常值得查看仪器中的NSZombies和Leaks工具;前者将帮助您了解何时以及如何访问解除分配的对象,后者将帮助您发现泄漏的内存。 Guard Malloc对前者也很有用,但是它带来了更大的运行时开销,我不确定它目前在iOS上的效果如何。
(脚注:在现代的64位和ARM运行时,实例变量是动态的,具有实际效果,您可以纯粹通过@property和@synthesize声明它们,而无需将它们放在@interface声明中;如果您是这样做显然@property的存在与否将影响直接访问是否有效)
答案 2 :(得分:0)
用这个替换你的滴答功能: -