我正在玩NSOperationQueue
以便在后台运行一些代码并让它更新UILabel
。这是viewDidLoad
。
- (void)viewDidLoad
{
[super viewDidLoad];
queue = [[NSOperationQueue alloc] init];
NSInvocationOperation *operation = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(counterTask) object:nil];
[queue addOperation:operation];
}
这是调用调用操作的方法:
- (void)counterTask {
for (int i=0; i<5000000; i++) {
if (i % 100 == 0) {
[self.firstLabel performSelectorOnMainThread:@selector(setText:)
withObject:[NSString stringWithFormat:@"%d", i]
waitUntilDone:YES];
}
}
[self.firstLabel performSelectorOnMainThread:@selector(setText:) withObject:@"finished." waitUntilDone:NO];
}
随着循环数量的增加,越来越多的@"%d"
NSString
被创建,内存使用率自然会上升。然而,一旦循环结束,内存似乎没有解除分配。由于setText:
消息使用NSString
的新实例并释放旧实例,我预计内存会下降。
如果我将循环条件更改为i<5000000*2
,则内存使用量在结束时大约是两倍 - 所以它肯定会在每次迭代时发生,从而导致泄漏。
为什么内存泄漏?
编辑:忘记提及我正在使用ARC。
答案 0 :(得分:2)
ARC不会删除retain / release / autorelease ,它只是控制这些方法的调用。您可以将自己的自动释放池添加到循环中以强制清理:
for (int i=0; i<5000000; i++) {
if (i % 100 == 0) {
@autoreleasepool {
[self.firstLabel performSelectorOnMainThread:@selector(setText:)
withObject:[NSString stringWithFormat:@"%d", i]
waitUntilDone:YES];
}
}
}
答案 1 :(得分:0)
试试吧:
- (void)counterTask {
@autoreleasepool {
for (int i=0; i<5000000; i++) {
if (i % 100 == 0) {
[self.firstLabel performSelectorOnMainThread:@selector(setText:)
withObject:[NSString stringWithFormat:@"%d", i]
waitUntilDone:YES];
}
}
}
[self.firstLabel performSelectorOnMainThread:@selector(setText:) withObject:@"finished." waitUntilDone:NO];
}
答案 2 :(得分:0)
您正在循环中创建NSString并将ARC添加到自动发布池中。
不立即释放内存(NSString *),稍后会释放。
还有一件事是,实际上performSelectorOnMainThread保留了目标和对象。
所以最好的方法是在将它发送到选择器之后创建nsstring实例,将其设置为nil,这样ARC就会释放它。
NSString* strText=[[NSString alloc]initWithFormat:@"%d",i ];
[self.firstLabel performSelectorOnMainThread:@selector(setText:)
withObject:strText
waitUntilDone:YES];
strText=nil;
答案 3 :(得分:0)
IMO,建议的@Wain方法应该解决这个问题。
但你也可以用这个:
- (void)counterTask {
assert([NSThread currentThread] != [NSThread mainThread]);
for (int i=0; i<5000000; i++) {
if (i % 100 == 0) {
dispatch_sync(dispatch_get_main_queue(), ^{
@autoreleasepool {
self.firstLabel.text = [NSString stringWithFormat:@"%d", i];
}
});
}
}
dispatch_async(dispatch_get_main_queue, ^{
self.firstLabel.text = @"finished";
});
}
答案 4 :(得分:0)
试试这个
(void)counterTask {
__弱NSString * str;
for(int i = 0; i&lt; 50000; i ++){ if(i%100 == 0){
str = [NSString stringWithFormat:@"%d", i];
[self.logInTxtField performSelectorOnMainThread:@selector(setText:)
withObject:str
waitUntilDone:YES];
}
}
[self.logInTxtField performSelectorOnMainThread:@selector(setText :) withObject:@“finished”。 waitUntilDone:NO]; }