NSMutableArray против NSArray Раунд 2 - PullRequest
0 голосов
/ 06 июля 2011

мой вопрос зависит от моего другого вопроса

NSMutableArray против NSArray

Я создал navigationController и загрузил TableView внутри с данными из другого вопроса. Теперь получите подробный вид и получите новые данные из XML, поэтому я копирую свои методы и модифицирую их.

но это та же самая структура, я не сильно меняюсь.

Но теперь я получаю ту же ошибку.

У меня есть detailview.h

 NSMutableArray *seminareArray;

и

@property (nonatomic, retain) NSMutableArray *seminareArray;

детально view.m.

@synthesize SeminareListeTabelle, selectedSeminar, seminareArray, receivedData;

я добавляю этот код

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

прежде чем я добавлю данные. и я получаю ошибку здесь

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

EXC_BAD_ACCESS снова проблема типа

я добавляю данные в массив следующим образом

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

массив заполнен данными, но после перезагрузки tableView я получаю эту ошибку.

//
//  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

Ответы [ 3 ]

2 голосов
/ 06 июля 2011

Проблема связана с этим кодом:

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

Сначала вы инициализируете массив semiareArray как принадлежащий объекту, но затем повторно устанавливаете его как объект с автоматическим выпуском.

Значение, он будет освобожден после завершения цикла выполнения.Удалите второй (автоматически освобожденный) оператор, но оставьте первый, и все должно работать нормально.

Причина, по которой вы получаете ошибку EXC_BAD_ACCESS, заключается в том, что объект seminareArray освобождается в какой-то момент перед его использованием.снова.

Кроме того, попробуйте отладить

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

Попробуйте установить его как id var = [seminareArray objectAtIndex:row];, а затем установить cell.textLabel.text = var; Это скажет вам, если ошибка происходит из-за массива, являющегося dealloc 'd слишком рано или неправильная ячейка / textLabel.


Обновлено:

Существует дополнительная проблема с кодом:

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

Вы создаете автоматически выпущенный объект seminName, который технически имеет счет сохранения 0. Вы добавляете его в массив semiareArray, который увеличивает счет сохранения объекта до 1. Затем вы освобождаете его снова.Что приводит к тому, что он вызывается во время выполнения.Проблема в том, что когда вы присваиваете значение textLabel, объект больше не существует.

Решение : удалите [seminarName release]; Не беспокойтесь о выпуске seminName, так какон автоматически высвобождается, он будет освобожден, когда массив будет освобожден или когда объект удален из массива.

2 голосов
/ 06 июля 2011

Ответ Дэвида верен, но я бы посоветовал вам прочитать об управлении вашей памятью.

Если вы синтезируете свойства, тогда гораздо проще использовать геттеры и сеттеры и позволять им управлять памятью за вас.Исключение составляют методы init / dealloc, в которых вы должны пытаться напрямую использовать ивары, чтобы избежать возможных побочных эффектов использования геттеров / сеттеров.

С выделением двух строк Дэвидом

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

Вы могли бы потенциально использовать любой из них, если управление памятью было выполнено правильно.

Первая строка сама по себе верна, поскольку она создает экземпляр NSMutableArray с счетом сохранения +1, а затем назначает его прямо наivar.

Затем, как указал Дэвид, вторая строка заменяет ее на автоматически выпущенную NSMutableArray, так что эта строка является излишней и приводит к сбою вашей программы.Метод arrayWithCapacity: не просто устанавливает емкость массива, который он дает вам новый автоматически выпущенный массив.

Если вы хотите использовать автоматически освобожденный NSMutableArray, тогда вам нужно будет использовать установщик либо с точкойзапись о передаче сообщения:

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

Просто ссылаясь на вещи прямо на seminareArray, вы избегаете синтезаторов / получателей, которые вы синтезировали, и, следовательно, отвечаете за все управление вашей памятью.

1 голос
/ 06 июля 2011

Подсказка при утечке памяти:

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

это приведет к утечке памяти, поскольку seminare объявлено как сохраняемое свойство:

 @property (nonatomic, retain) NSMutableArray *seminareArray;

В любом случае, это не является причиной вашей другой проблемы.

Ошибка, которую вы получаете, вызвана тем, что row больше, чем count вашего массива. Поэтому вы либо не добавляете достаточное количество объектов в массив, либо пытаетесь использовать неправильное значение для row. Проверьте эту строку с помощью отладчика и убедитесь, что row никогда не выходит за пределы [seminare count]; Вы легко узнаете, почему это происходит.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...