5

使用 NSOperationQueue 并尝试更改滑块/选择器等时,在 iphone 设备上遇到大量泄漏。

我可以毫无问题地更改标签,但是如果我尝试更改在界面构建器上创建的滑块或选择器,我会得到这些泄漏。

Leaked Object   #   Address Size    Responsible Library         Responsible Frame
GeneralBlock-16     0x1b00a0    16  GraphicsServices    GetFontNames
GeneralBlock-16     0x1aea90    16  WebCore                WebThreadCurrentContext
GeneralBlock-16     0x1aea80    16  GraphicsServices    GSFontGetFamilyName
GeneralBlock-64     0x1a7370    64  UIKit                  GetContextStack

下面的代码

- (void)loadData {

    NSInvocationOperation *operation = [[NSInvocationOperation alloc] initWithTarget:self
                                                                            selector:@selector(firstRun)
                                                                              object:nil];

    [queue_ addOperation:operation];
    [operation release];
}

- (void)firstRun {

    NSAutoreleasePool *pool = [NSAutoreleasePool new];

    [self setSliders];

    NSLog(@"firstRun method end");

    [pool drain];

}

- (void)setSliders {  

    NSMutableArray *tempArray = [[[NSMutableArray alloc]init] autorelease];
    aquaplannerAppDelegate *appDelegate = (aquaplannerAppDelegate *)[[UIApplication sharedApplication] delegate];
    tempArray = appDelegate.settingsValuesArray;

    freshMarineSegment.selectedSegmentIndex = [[tempArray objectAtIndex:0]intValue];

    for (int i = 1; i <= 20; i++ ) {
        UILabel *label = (UILabel *)[self.view viewWithTag:200+i];  // gets label based on tag  
        UISlider *slider = (UISlider *)[self.view viewWithTag:100+i];  // gets slider based on tag

        slider.value = [[tempArray objectAtIndex:i]intValue];
        label.text = [[[NSString alloc] initWithFormat:@"%@",[tempArray objectAtIndex:i]] autorelease];

        [label release];
        [slider release];
    }
}
4

2 回答 2

7

我假设您在setSliders创建 NSOperation 之前正在做其他事情,而您只是省略了该代码。

UIKit 不保证是线程安全的,你应该只在主线程上访问你的界面元素。文档中的一些地方提到了这一点,但最能说明问题的是 Cocoa Fundamentals Guide:

所有 UIKit 对象都应该只在主线程上使用。

所以firstRun应该看起来更像这样:

- (void)firstRun {

  NSAutoreleasePool *pool = [NSAutoreleasePool new];

  // Do something important here...

  [self performSelectorOnMainThread:@selector(setSliders) withObject:nil waitUntilDone:NO];

  NSLog(@"firstRun method end");

  [pool drain];

}

你为什么使用NSMutableArrayin setSliders?你永远不会真正改变数组,可变数据结构会在线程编程中造成严重破坏。

另外,我会将setSliders方法重命名为updateSliders. 这是可可风格的问题。以“set”开头的方法应该用于改变单个实例变量/属性。

于 2011-01-07T16:54:54.450 回答
0

您正在释放 for 循环中的每个标签和滑块,即使您没有保留它们。这是不正确的。您只需释放已分配、复制或保留的内存。有关详细信息,请参阅内存管理编程指南

我还将更改您初始化临时数组的方式。的指定初始化程序NSMutableArray-initWithCapacity:,不是-init。为了方便起见,还有一个类方法旨在返回一个自动释放的实例:

NSMutableArray *tempArray = [NSMutableArray arrayWithCapcity:0];
于 2011-01-07T15:42:35.840 回答