encountering numerous leaks on iphone device when using NSOperationQueue and trying to change sliders / pickers etc.
I am able to change labels without an issue, but if I try to change a slider or picker both created on interface builder I get these leaks.
Leaked Object # Address Size Responsible Library Responsible Frame
GeneralBlock-16 0x1b00a0 16 GraphicsServices GetFontNames
Gener开发者_如何转开发alBlock-16 0x1aea90 16 WebCore WebThreadCurrentContext
GeneralBlock-16 0x1aea80 16 GraphicsServices GSFontGetFamilyName
GeneralBlock-64 0x1a7370 64 UIKit GetContextStack
code below
- (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];
}
}
I'm assuming you're doing something else before setSliders
for which you created the NSOperation, and you just omitted that code.
UIKit is not guaranteed to be thread safe, and you should only access your interface elements on the main thread. This is mentioned in a few places in the docs, but the most telling is in the Cocoa Fundamentals Guide:
All UIKit objects should be used on the main thread only.
So firstRun
should look more like this:
- (void)firstRun {
NSAutoreleasePool *pool = [NSAutoreleasePool new];
// Do something important here...
[self performSelectorOnMainThread:@selector(setSliders) withObject:nil waitUntilDone:NO];
NSLog(@"firstRun method end");
[pool drain];
}
Why are you using an NSMutableArray
in setSliders
? You're never actually changing the array, and mutable data structures can wreak havoc in threaded programming.
Also, I'd rename the setSliders
method to something like updateSliders
. It's a Cocoa style issue. Methods that start with "set" should be used for mutating a single instance variable/property.
You are releasing each label and slider in your for loop, even though you have not retained them. This is not correct. You only need to release memory that you have allocated, copied or retained. See the memory management programming guide for more details.
I would also change the way you initialize your temporary array. The designated initializer for NSMutableArray
is -initWithCapacity:
, not -init
. There is also a class method designed to return an autoreleased instance for convenience:
NSMutableArray *tempArray = [NSMutableArray arrayWithCapcity:0];
精彩评论