开发者

Weird leaks in UIPickerView methods

Building a custom UIPickerView for so I can let my users select time as 24 hours without having to go into the Settings app and turn on 24 hour time for the entire phone. Got some stubborn leaks of a couple strings and an array, and I could really use some help.

There are only three places where the arrays I'm creating with the strings are used. hours and minutes are both NSArray synthesized properties as well as ivars.

a) In viewWillAppear:animated, where the strings and arrays are actuall开发者_StackOverflowy created:

if (TwentyFourHourMode) {
    //set up arrays for 24 hour picker

    NSMutableArray *hoursMutable = [[NSMutableArray alloc] init];
    NSString *hourString;
    for (int i = 0; i < 24; i++) {
        if (i < 10) {
            hourString = [NSString stringWithFormat:@"0%i", i];
        } else {
            hourString = [NSString stringWithFormat:@"%i", i];
        }
        [hoursMutable addObject:hourString];
    }
    self.hours = [[NSArray alloc] initWithArray:hoursMutable];
    [hoursMutable release];

    NSMutableArray *minutesMutable = [[NSMutableArray alloc] init];
    NSString *minuteString;
    for (int i = 0; i < 60; i++) {
        if (i < 10) {
            minuteString = [NSString stringWithFormat:@"0%i", i];
        } else {
            minuteString= [NSString stringWithFormat:@"%i", i];
        }
        [minutesMutable addObject:minuteString];
    }
    self.minutes = [[NSArray alloc] initWithArray:minutesMutable];
    [minutesMutable release];
    //more stuff which does not leak or reference the arrays/strings in question
} else {
    //unrelated crap
}

b) in my UIPickerView delegate methods - everything that uses these two arrays:

-(NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView {
    return 2;
}

-(NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component {
    if (component == 0) {
        return self.hours.count;
    } else if (component == 1) {
        return self.minutes.count;
    } else {
        return 0;
    }    
}

- (NSString *)pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component
{
    if (component == 0) {
        return [self.hours objectAtIndex:row];
    } else if (component == 1) {
        return [self.minutes objectAtIndex:row];
    } else {
        return nil;
    }
}

- (CGFloat)pickerView:(UIPickerView *)pickerView widthForComponent:(NSInteger)component {
    switch(component) {
        case 0: return 44;
        case 1: return 50;
        default: return 44;
    }

}

- (void) pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component
{
    if (component == 0) {
        [hour24 release];
        hour24 = [self.hours objectAtIndex:row];
        [hour24 retain];
    } else if (component == 1) {
        [minute24 release];
        minute24 = [self.minutes objectAtIndex:row];
        [minute24 retain];
    }

c) and last but not least, in dealloc:

//set arrays to nil
self.hours = nil;
self.minutes = nil;

//release arrays
[hours release];
[minutes release];

Analyze is coming up clean, but Instruments is telling me hourString, minuteString, and self.hours are all being leaked. What really drives me nuts is that self.minutes isn't being leaked and it appears to be the same format of code as self.hours - I even copy-pasted and still get the same leak/no leak combo.

I'll be damned if I can figure out where this is coming from. Any ideas? Any further code y'all might need to help? Thanks, guys!

Edit: EmptyStack's suggestion stopped self.hours and minuteString from being leaked, but hourString is still leaking and there's now a new leak in this code just below the stuff above in viewWillAppear:animated (self.incomingTime is a synthesized NSString property, all arrays here are initialized locally):

NSArray *splitStrings = [self.incomingTime componentsSeparatedByString:@":"];
NSString *hourToDisplay = [splitStrings objectAtIndex:0];
//set this here so it doesn't give a null value
hour24 = [[NSString alloc] initWithString:hourToDisplay];
NSString *minuteSplitter = [splitStrings objectAtIndex:1];
NSArray *splitMinutes = [minuteSplitter componentsSeparatedByString:@" "]; 
NSString *minuteToDisplay = [splitMinutes objectAtIndex:0];
minute24 = [[NSString alloc] initWithString:minuteToDisplay];

Edit 2: Oh, for crying out loud, now minuteString is leaking again. I'm going to bed before my head explodes. Any suggestions overnight would be most welcome.


The problems are in the following lines,

self.hours = [[NSArray alloc] initWithArray:hoursMutable];
self.minutes = [[NSArray alloc] initWithArray:minutesMutable];

It seems hours and minutes are "retained properties" and you are allocating objects while assigning it to the properties. For example on the first line, [NSArray alloc] increases the retainCount by 1 and the setter self.hours in turn increases the retainCount by 1. Finally the retainCount becomes 2, which causes the leak even after you release those objects. You can use convenience constructors in these cases.

self.hours = [NSArray arrayWithArray:hoursMutable];
self.minutes = [NSArray arrayWithArray:minutesMutable];

And even a simpler way is to directly assign those arrays like this,

self.hours = hoursMutable;
self.minutes = minutesMutable;


Okay, finally found it, for anyone stumbling across this in the future: hour24 and minute24 were not being properly released in dealloc, so it was leaking strings and arrays all over the place. I found it by commenting out the code posted in the 2nd edit and putting it back in line by line until the leak sprang up. Thanks for the suggestions!

0

上一篇:

下一篇:

精彩评论

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

最新问答

问答排行榜