开发者

NSMutableArray vs NSArray Round 2

开发者 https://www.devze.com 2023-03-18 09:52 出处:网络
my question depends on my other question NSMutableArray vs NSArray i have created a navigationController and load a TableView inside with data from the other question. Now a get a detailview and get

my question depends on my other question

NSMutableArray vs NSArray

i have created a navigationController and load a TableView inside with data from the other question. Now a get a detailview and get new data from xml, so i copy my methods and modifide them.

but it is the same stucture, i does not change a lot.

But now i get the same error.

i have in detailview.h

 NSMutableArray *seminareArray;

and

@property (nonatomic, retain) NSMutableArray *seminareArray;

in detailview.m

@synthesize SeminareListeTabelle, selectedSeminar, seminareArray, receivedData;

i add this code

seminareArray = [[NSMutableArray alloc] init];
self.seminareArray = [NSMutableArray arrayWithCapacity:10];

before i add the data. and i get the error here

cell.textLabel.text = [seminareArray objectAtIndex:row];

EXC_BAD_ACCESS again some type problem

i add data to array like this

if([elementName isEqualToString:@"seminar"])   
    {
        //NSLog(@"%@", [attributeDict objectForKey:@"name"]);
        NSString *seminarName = [NSString stringWithFormat:@"%@", [attributeDict objectForKey:@"name"]];
        [seminareArray addObject:seminarName];
        [seminarName release];
    }

the array is filled with data, but after tableView reload, i get this error.

//
//  SeminareListingView.m
//  Seminar App2
//
//  Created by Alexander Frischbutter on 05.07.11.
//  Copyright 2011 __MyCompanyName__. All rights reserved.
//

#import "SeminareListingView.h"
//#import "SeminareView.h"

@implementation SeminareListingView
@synthesize SeminareListeTabelle, selectedSeminar, seminareArray, receivedData;

- (void) parseData:(NSString *)url   
{
    if(receivedData)   
    {
        receivedData = nil;
    }

    NSLog(@"Parsing... url: %@", url);

    NSURLRequest *theRequest = [NSURLRequest requestWithURL:[NSURL URLWithString:[NSString stringWithFormat:@"%@", url]] cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:60.0];

    NSURLConnection *theConnection = [[NSURLConnection alloc] initWithRequest:theRequest delegate:self];

    if(theConnection)
    {
        receivedData = [[NSMutableData data] retain];
    }
    else
    {
        //label.text = @"XML nicht geladen";
        NSLog(@"XML nicht gefunden");
    }
}

- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
    self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
    if (self) {
        // Custom initialization
    }
    return self;
}

- (void)dealloc
{
    [super dealloc];
}

- (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.
}

#pragma mark - View lifecycle

- (void)viewDidLoad
{
    [super viewDidLoad];

    SeminareListeTabelle = [[UITableView alloc] initWithFrame:[[UIScreen mainScreen] applicationFrame] style:UITableViewStylePlain];
    SeminareListeTabelle.delegate = self;
    SeminareListeTabelle.dataSource = self;
    SeminareListeTabelle.autoresizesSubviews = YES;

    seminareArray = [[NSMutableArray alloc] init];
    self.seminareArray = [NSMutableArray arrayWithCapacity:10];

    [self parseData:[NSString stringWithFormat:@"http://akademie.kunden.fincha.com/semapp/sem_kat_arbtechnik.xml", selectedSeminar]];

    self.navigationItem.title = [NSString stringWithFormat:@"%@", selectedSeminar];
    self.view = SeminareListeTabelle;

    // Do any additional setup after loading the view from its nib.
}


- (void)startParsingData    
{
    NSLog(@"Parsing started");

    NSXMLParser *dataParser = [[NSXMLParser alloc] initWithData:receivedData];
    dataParser.delegate = self;

    [dataParser parse];
    [dataParser release];
    [receivedData release];

    NSLog(@"Received Data in seminareArray");
    /*
    for(int i = 0; i < [seminareArray count]; i++)
    {
        NSLog(@"%d is %@", i, [seminareArray objectAtIndex:i]);
        //NSLog(@"Count %d", [kategorienArray count]);
    }
    */
    //[seminareArray release];
    NSLog(@"Reload data in TableView");
    [self.SeminareListeTabelle reloadData];    
    NSLog(@"Data reloaded");    
}

- (void)viewDidUnload
{
    //[seminareArray release];
    //[SeminareListeTabelle release];

    NSLog(@"Vew unloaded");

    [super viewDidUnload];
    // Release any retained subviews of the main view.
    // e.g. self.myOutlet = nil;
}

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

    static NSString *SimpleTableIdentifier = @"SimpleTableIdentifier";
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier: SimpleTableIdentifier];

    if (cell == nil) { cell = [[[UITableViewCell alloc]
                                initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:SimpleTableIdentifier] autorelease];
    }

    if([seminareArray count] != 0)
    { 
        NSLog(@"Adding data to cell");

        NSUInteger row = [indexPath row]; 
        //cell.textLabel.text = [NSString stringWithFormat:@"bla, %d", row]; //[seminareArray objectAtIndex:row];
        cell.textLabel.text = [seminareArray objectAtIndex:row];

        NSLog(@"Added data to cell");
    }
    return cell;
}

- (NSInteger)tableView:(开发者_运维百科UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    //NSLog(@"Count %d", [self.seminareArray count]);
    return [seminareArray count];
}

-(NSInteger) tableView:(UITableView *)tableView indentationLevelForRowAtIndexPath:(NSIndexPath *)indexPath
{
    return 0;
}

//Anzeige mit Seminaren öffnen bei Click auf die Zeile
-(void) tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
    //gehe zurück zum ersten View
    //NSLog(@"Received Data in seminareArray");

    [[self navigationController] popViewControllerAnimated:YES];
}

- (void)connection:(NSURLConnection *)connection didReceiveResonse:(NSURLResponse *)response
{
    [receivedData setLength:0];
}

- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
    if(receivedData)
    {
        [receivedData appendData:data];
    }
}

- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
    [connection release];
    [receivedData release];

    //label.text = @"Connection failed";
    NSLog(@"Verbindung fehlgeschlagen!");
    //[[self navigationController] popViewControllerAnimated:YES];
}

- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
    [self startParsingData];
    [connection release];
}

- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict
{
    //NSLog(@"Parser was called. Element: %@", elementName);

    if([elementName isEqualToString:@"seminar"])   
    {
        //NSLog(@"%@", [attributeDict objectForKey:@"name"]);
        NSString *seminarName = [NSString stringWithFormat:@"%@", [attributeDict objectForKey:@"name"]];
        [seminareArray addObject:seminarName];
        [seminarName release];
    }
}

- (void)parser:(NSXMLParser *)parser parseErrorOccurred:(NSError *)parseError
{
    NSLog(@"Parse Error %@", parseError);
}

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
    // Return YES for supported orientations
    return (interfaceOrientation == UIInterfaceOrientationPortrait);
}

@end


The problem stems from this code:

seminareArray = [[NSMutableArray alloc] init]; // owned
seminareArray = [NSMutableArray arrayWithCapacity:10]; // autoreleased

You're first initializing the semiareArray as an owned object, but then are re-setting it as an autoreleased object.

Meaning, it will be released after the run-loop terminates. Remove the second (autoreleased) statement but keep the first, and everything should work fine.

The reason why you're getting the EXC_BAD_ACCESS error is because the seminareArray object is released at some point before it being used again.

Additionally, try to debug your

cell.textLabel.text = [seminareArray objectAtIndex:row];

Try setting it as id var = [seminareArray objectAtIndex:row]; and then setting cell.textLabel.text = var; This will tell you if the error occurs due to array being dealloc'd too early, or improper cell/textLabel.


Updated:

There's an additional problem is with the code:

NSString *seminarName = [NSString stringWithFormat:@"%@", [attributeDict objectForKey:@"name"]];
[seminareArray addObject:seminarName];
[seminarName release]; // <--

You're creating an auto-released object seminarName, which technically has retain count 0. You're adding it to the semiareArray, which ups the object retain count to 1. Then you're releasing it again. Which causes it to be dealloc'd at runtime. The problem is that when you're assigning the value to the textLabel, the object no longer exists.

Solution: remove the [seminarName release]; Don't worry about releasing the seminarName, since it's auto-released, it will be released when the array is dealloc'd, or when the object it removed from the array.


David's answer is correct but I would advice reading up on your memory management.

If you are synthesizing properties then it is a lot easier to use the getters and setters and let them do the memory management for you. The exception being in your init/dealloc methods where you should try to directly use the ivars to avoid any potential side effects of using the getters/setters.

With the two lines david highlighted

seminareArray = [[NSMutableArray alloc] init]; // owned
seminareArray = [NSMutableArray arrayWithCapacity:10]; // autoreleased

You could potentially use either if the memory management was done correctly.

The first line on its own is correct as it creates an instance of NSMutableArray with a retain count of +1 then assigns it straight to the ivar.

Then as David pointed out the second line replaces this with an autoreleased NSMutableArray so this line is superflous and crashes your program. The method arrayWithCapacity: is not simply setting the capacity of the array it is giving you a new autoreleased array.

If you wanted to use an autoreleased NSMutableArray then you would need to use the setter either with dot notation of passing a message:

self.seminareArray = [NSMutableArray arrayWithCapactiy:10];
OR
[self setSeminareArray:[NSMutableArray arrayWithCapcity:10]];

By simply referencing things straight to seminareArray you are avoiding the getters/setters you synthesized and therefore are responsible for all of your memory management.


A hint at a memory leak:

 self.seminareArray = [[NSMutableArray alloc] init];

this will leak memory because seminare is declared as retained property:

 @property (nonatomic, retain) NSMutableArray *seminareArray;

This is not, anyway, the cause of your other issue.

The error you are having is caused by row being greater that the count of your array. So either you don't add sufficient objects to the array, or you try to use an incorrect value for row. Inspect that line with a debugger and ensure that row never goes beyond [seminare count]; you will find out easily why it happens.

0

精彩评论

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

关注公众号