自定义单元格创建250次后应用程序崩溃

时间:2011-12-07 07:05:22

标签: iphone ios

我在我的应用中使用自定义单元格。当用户点击表格行时,会出现一个自定义单元格:

#import "SonaraamatuKontroller.h"
#import "TolkegaLahter.h"

//Lahtris kasutatava teksti fondi suurus 
#define FONT_SIZE 14.0f
//Tabelilahtri laius
#define CELL_CONTENT_WIDTH 320.0f
//Tabeli sisu äärise kaugus lahtri servadest
#define CELL_CONTENT_MARGIN 5.0f

@implementation SonaraamatuKontroller 
@synthesize sonaraamatuSisukord=sonaraamatuSisukord;
@synthesize sonaraamatuTabel;
@synthesize valitudLahtriIndexPath;
@synthesize tolkegaLahter;
@synthesize audioPleier;
@synthesize sonaraamatuFailinimi;
@synthesize sonaraamatuNavribaNimi;


- (void)viewDidLoad {
[super viewDidLoad];

NSString *error;
NSPropertyListFormat format;

NSString *localizedPath = [[NSBundle mainBundle] pathForResource:sonaraamatuFailinimi ofType:@"plist"];
NSData *plistData = [NSData dataWithContentsOfFile:localizedPath];

NSArray *sisukordData = [NSPropertyListSerialization propertyListFromData:plistData
                                                         mutabilityOption:NSPropertyListImmutable
                                                                   format:&format
                                                         errorDescription:&error];


if (sisukordData)   {
    self.sonaraamatuSisukord = [NSMutableArray arrayWithCapacity:[sonaraamatuSisukord count]];
    for (NSDictionary *sisukordDictionary in sisukordData) {
        [self.sonaraamatuSisukord addObject:sisukordDictionary];
    }
} 

self.navigationItem.title=sonaraamatuNavribaNimi;
}



- (void)didReceiveMemoryWarning {
// Releases the view if it doesn't have a superview.
[super didReceiveMemoryWarning];

// Release any cached data, images, etc that aren't in use.
}

- (void)viewDidUnload {
//Teise vaatesse liikumisel pannakse audiopleier seisma
[audioPleier stop];
// Release anything that can be recreated in viewDidLoad or on demand.
// e.g. self.myOutlet = nil;
}


#pragma mark -
#pragma mark UITableViewDataSource

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {   
    //Loeme tabeli sektsioonide arvu - kuna praegusel juhul on sisukorras ainult üks liige (sõnaraamat "Item 0"), siis on ka sektsioone üks
    return [sonaraamatuSisukord count];
}



- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    //Loeme vastavas sektsioonis asuvate ridade arvu
    NSMutableArray *sisukordItems = [[sonaraamatuSisukord objectAtIndex:section] objectForKey:@"Items"];
    return [sisukordItems count];       
}


- (CGFloat) tableView : (UITableView *) tableView 
heightForRowAtIndexPath: (NSIndexPath *) indexPath {
if(valitudLahtriIndexPath != nil
   && [valitudLahtriIndexPath isEqual:indexPath] )
    return 95; 


    NSMutableArray *sisukordItems = [[sonaraamatuSisukord objectAtIndex:indexPath.section] objectForKey:@"Items"];

    NSDictionary *sisukordItem = [sisukordItems objectAtIndex:indexPath.row];

    NSString *text = [sisukordItem objectForKey:@"Valjend"];    

    CGSize constraint = CGSizeMake(CELL_CONTENT_WIDTH - (CELL_CONTENT_MARGIN * 2), 20000.0f);


    CGSize size = [text sizeWithFont:[UIFont systemFontOfSize:FONT_SIZE] constrainedToSize:constraint lineBreakMode:UILineBreakModeWordWrap];

    CGFloat height = MAX(size.height, 25.0f);
    return height + (CELL_CONTENT_MARGIN * 2);
}


#pragma mark -
#pragma mark UITableViewDelegate

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {

if((valitudLahtriIndexPath != nil)
   && [valitudLahtriIndexPath isEqual:indexPath] 
   ) 

{   //NSLog (@"ValitudPath: %@", valitudLahtriIndexPath);
    static NSString *TolkegaLahtriTunnus = @"TolkegaLahter";

    TolkegaLahter *cell = (TolkegaLahter *)[tableView dequeueReusableCellWithIdentifier:TolkegaLahtriTunnus];

    if (cell == nil) {      
        [[NSBundle mainBundle] loadNibNamed:@"TolkegaLahter" owner:self options:nil];
        cell = tolkegaLahter;   


    [cell setSelectionStyle:UITableViewCellSelectionStyleNone];

    //Lisame gradiendi:
    CAGradientLayer *gradient = [CAGradientLayer layer];
    [gradient setCornerRadius:9.0f];
    //[gradient setMasksToBounds:YES];
    //[gradient setBorderWidth:0.8f];
    //[gradient setBorderColor:[[UIColor darkGrayColor] CGColor]];
    gradient.frame = cell.bounds;
    gradient.colors = [NSArray arrayWithObjects:(id)[[UIColor colorWithRed:0.122 green:0.2 blue:1 alpha:0.95] CGColor], (id)[[UIColor colorWithRed:0.041 green:0.1 blue:0.33 alpha:0.95] CGColor],(id)[[UIColor colorWithRed:0.122 green:0.2 blue:1 alpha:0.95] CGColor], nil];
    gradient.locations = [NSArray arrayWithObjects:[NSNumber numberWithFloat:0.0],[NSNumber numberWithFloat:0.48],[NSNumber numberWithFloat:1.0], nil];
    [cell.layer insertSublayer:gradient atIndex:0];
    }

    NSMutableArray *sisukordItems = [[sonaraamatuSisukord objectAtIndex:indexPath.section] objectForKey:@"Items"];
    NSDictionary *sisukordItem = [sisukordItems objectAtIndex:indexPath.row];

    cell.valjend.text=[sisukordItem objectForKey:@"Valjend"];
    cell.tolge.text=[sisukordItem objectForKey:@"Tolge"];


    [sonaraamatuTabel scrollToRowAtIndexPath:indexPath atScrollPosition:UITableViewScrollPositionNone animated:YES];

    self.tolkegaLahter = nil;

    return cell;

} 

static NSString *CellIdentifier = @"Cell";

//Loome lahtrisse labeli
UILabel *label = nil;    

UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];


if (cell == nil) {
    cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];

    //Esialgu on label tühi (asub punktis 0,0 ning on suurusega 0,0)
    label = [[UILabel alloc] initWithFrame:CGRectZero];
    //Määrame reavahetuse stiili
    [label setLineBreakMode:UILineBreakModeWordWrap];
    //Minimaalne fondi suurus on ülal defineeritud konstant
    [label setMinimumFontSize:FONT_SIZE];
    //Esialgu on ridade arv 0
    [label setNumberOfLines:0];
    //Määrame fondi. Selle suuruseks on ülal defineeritud konstant
    [label setFont:[UIFont systemFontOfSize:FONT_SIZE]];
    [label setTag:1];

    //Lisame labelile piirid, et programmeerimise käigus oleks paremini näha, kuhu see lahtris paigutub
    //[[label layer] setBorderWidth:2.0f];

    [[cell contentView] addSubview:label]; 

    [label release];
}

    cell.selectionStyle = UITableViewCellSelectionStyleBlue;
    cell.selectedBackgroundView=[[[UIView alloc] init] autorelease];
    cell.selectedBackgroundView.backgroundColor=[UIColor colorWithRed:0.537 green:0.18 blue:0.122 alpha:1.0];


    //Loome andmemassiivi sisukord objektidest (tuntakse ära võtme "Items" abil) andmemassiivi sisukordItems
    NSMutableArray *sisukordItems = [[sonaraamatuSisukord objectAtIndex:indexPath.section] objectForKey:@"Items"];

    //Loome andmemassiivi sisukordItems objektidest sõnaraamatud sisukordItem
    NSDictionary *sisukordItem = [sisukordItems objectAtIndex:indexPath.row];

    //Igas lahtris kuvatakse sellele vastavas sõnaraamatus sisalduva objekti "Valjend" väärtus
    NSString *text = [sisukordItem objectForKey:@"Valjend"];


    //Sarnaselt lahtri kõrguse arvutamisele heightForRowAtIndexPath meetodis arvutame ka labeli 
    //kõrguse (sellele ei liideta ääriste kaugusi)
    CGSize constraint = CGSizeMake(CELL_CONTENT_WIDTH - (CELL_CONTENT_MARGIN * 2), 20000.0f);
    CGSize size = [text sizeWithFont:[UIFont systemFontOfSize:FONT_SIZE] constrainedToSize:constraint lineBreakMode:UILineBreakModeWordWrap];

    //Hangime labeli juhul kui see on nil (ja tegu ei ole vaate esialgse initsieerimisega ehk lahter ei ole nil)
    if (!label)
        label = (UILabel*)[cell viewWithTag:1];

    //Seame labeli teksti
    [label setText:text];
    //Seame labeli piirjooned
    [label setFrame:CGRectMake(CELL_CONTENT_MARGIN, CELL_CONTENT_MARGIN, CELL_CONTENT_WIDTH - (CELL_CONTENT_MARGIN * 2), MAX(size.height, 25.0f))];


    label.textColor=[UIColor blackColor];
    label.font=[UIFont systemFontOfSize:14];
    label.backgroundColor=[UIColor clearColor];    


return cell;
}



- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {    


    self.valitudLahtriIndexPath = indexPath; 
    if(valitudLahtriIndexPath != nil //Kui see väärtus on tõene, 
       && [valitudLahtriIndexPath isEqual:indexPath]) {

        [self.sonaraamatuTabel reloadData];


        NSMutableArray *sisukordItems = [[sonaraamatuSisukord objectAtIndex:indexPath.section] objectForKey:@"Items"];

        NSDictionary *sisukordItem = [sisukordItems objectAtIndex:indexPath.row];

        NSString*heliFailinimi=[sisukordItem objectForKey:@"HeliFailinimi"];

        NSError *setCategoryError = nil;
        [[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback error:&setCategoryError];

        NSString *taustaHeliPath = [[NSBundle mainBundle] pathForResource:heliFailinimi ofType:@"m4a"];

        [audioPleier stop];

        NSURL *taustaHeliURL = [NSURL fileURLWithPath:taustaHeliPath];
        NSError *error;
        audioPleier = [[AVAudioPlayer alloc] initWithContentsOfURL:taustaHeliURL error:&error];
        [audioPleier setDelegate:self];  // We need this so we can restart after interruptions 

        [audioPleier play];            
    }

}


- (void)viewWillAppear:(BOOL)animated
{
NSIndexPath*selection = [self.sonaraamatuTabel indexPathForSelectedRow];
if (selection)
    [self.sonaraamatuTabel deselectRowAtIndexPath:selection animated:YES];

[self.sonaraamatuTabel reloadData];
}



- (void)dealloc {
[valitudLahtriIndexPath release];    
[sonaraamatuSisukord release], sonaraamatuSisukord=nil; 
[audioPleier release];
[sonaraamatuFailinimi release];
[sonaraamatuNavribaNimi release];
[super dealloc];
}


@end

点按250次后,应用程序崩溃,我收到消息:

由于未捕获的异常'NSInternalInconsistencyException'而终止应用程序,原因:'无法在包中加载NIB:'NSBundle(已加载)',名称为“TolkegaLahter”

这种行为可能是什么原因?某处有内存泄漏?

修改

这是关于AVAudioPlayer,它一次又一次地创建,但没有发布。 所以,我换了

audioPleier = [[AVAudioPlayer alloc] initWithContentsOfURL:taustaHeliURL error:&error];

        AVAudioPlayer*ajutineAudioPleier = [[AVAudioPlayer alloc] initWithContentsOfURL:taustaHeliURL error:&error];
        self.audioPleier=ajutineAudioPleier;
        [ajutineAudioPleier release];

2 个答案:

答案 0 :(得分:1)

尝试替换

 [[NSBundle mainBundle] loadNibNamed:@"TolkegaLahter" owner:self options:nil];
 cell = tolkegaLahter;

cell = [[[TolkegaLahter alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier: TolkegaLahtriTunnus] autorelease];
self.tolkegaLahter = [[[NSBundle mainBundle] loadNibNamed:@"TolkegaLahter" owner:self options:nil] lastObject];
cell = self.tolkegaLahter;

答案 1 :(得分:1)

你问题中的代码是cellForRowAtIndexPath方法吗?从您的问题中不清楚此代码的行踪或执行时间。

如果是(或者,对于其中一些,即使它不是),它有几个问题:

  • 如果出列方法为您带回了某些内容,则不会返回单元格
  • 如果出列方法为您提供了某些内容,则您没有配置单元格
  • 这使我预计您没有在界面构建器
  • 中的自定义单元子类中设置重用标识符
  • 这意味着您每次创建一个新单元格,如果您有足够数量的单元格,可能会导致崩溃
  • 滚动调用看起来很奇怪(如果 你的cellForRowAtIndexPath方法,这只会很奇怪)

如果您反复从笔尖加载,您可能还想查看UINib

修改

在查看完整代码之后,我认为问题出在你的音频播放器上,每次选择单元格时都会创建并配置一个新的代码,这就是泄漏。

您应该只在viewDidLoad上设置音频播放器,并在选择单元格时告诉它播放特定的声音。