Сбой при прокрутке в UITableView - объект неожиданно освобождается - PullRequest
0 голосов
/ 16 апреля 2011

** Примечание: я обновил код на основе предложений aroth - однако он все еще не работает. Код в посте ниже является обновленным кодом.

Я пытаюсь создать приложение для iPhone на основе шаблона XCode табличного представления (XCode 4). Табличное представление заполняется правильными данными в правильном порядке - однако, когда я иду, чтобы прокрутить таблицу, приложение вылетает (иногда я могу прокрутить еще 5 или 10 ячеек, иногда он сразу же зависает). Представление таблицы подается из объектов Artist внутри NSArray, который является IVAR другого объекта iPodLibraryParser. Я полагаю, что проблема в том, что объект 'iPodLibraryParser' был выпущен преждевременно - но я не понимаю, почему.

Я создал объект iPodLibraryParser со следующим заголовочным файлом:

#import <Foundation/Foundation.h>
#import <MediaPlayer/MediaPlayer.h>
#import <CoreLocation/CoreLocation.h>
#import "ArtistClass.h"

@interface iPodLibraryParser : NSObject {

    //Location stuff
    CLLocationManager *locationManager;
    IBOutlet UITextField *latitudeTextField;
    IBOutlet UITextField *longitudeTextField;
    IBOutlet UILabel *latitudeLabel;
    IBOutlet UILabel *longitudeLabel;

    //Music Library Stuff
    NSString *currentArtist;
    NSString *currentAlbum;
    NSMutableArray *artistArray;
    NSMutableArray *sortedArtistArray;       
}

@property (nonatomic, retain) NSMutableArray *sortedArtistArray;

-(void)parseiPodLibrary;
-(id) initializeiPodLibraryParser;

@end

Соответствующий код в файле .m этого класса:

@implementation iPodLibraryParser

@synthesize sortedArtistArray;

-(id) initializeiPodLibraryParser{

    [super init];

    sortedArtistArray = [[NSMutableArray alloc] initWithObjects:nil];

    return self;

}

    -(void)parseiPodLibrary{

    .....

NSArray *sortingArray = [[NSArray alloc] initWithObjects:artistTrackCountSorter,nil];
NSArray *tempSortedArray = [artistArray sortedArrayUsingDescriptors:sortingArray];
[sortedArtistArray removeAllObjects];
[sortedArtistArray addObjectsFromArray:tempSortedArray];

    }

Заголовок объекта Artist:

#import <UIKit/UIKit.h>
#import "iPodLibraryParser.h"

@interface ArtistClass : NSObject {

    NSString *artistName;
    int numberOfTracks;

    id artistClassViewController;
}

-(id) initializeArtistObjectWithDocument:(id)myDocument withArtist:(NSString*) artist;

@property (nonatomic, retain) NSString *artistName;
@property (nonatomic, assign) int numberOfTracks;

@end

Контроллер табличного представления (называемый RootViewController из используемого шаблона)

Заголовок:

#import <UIKit/UIKit.h>
#import "iPodLibraryParser.h"
#import "ArtistClass.h"

@interface RootViewController : UITableViewController {

    iPodLibraryParser *iPodLibrary;
}

@property (nonatomic, retain) iPodLibraryParser *iPodLibrary;

@end

Соответствующий код

- (void)viewDidAppear:(BOOL)animated
{
    [super viewDidAppear:animated];

    NSLog(@"In viewDidAppear");

    iPodLibrary = [[iPodLibraryParser alloc] initializeiPodLibraryParser];
    [iPodLibrary parseiPodLibrary]; 

}

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
    return 1;
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{

    NSLog(@"there are %i artists in the array", [[iPodLibrary sortedArtistArray] count]);
    return [[iPodLibrary sortedArtistArray] count];

}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    NSLog(@"in tableView blah");

    static NSString *CellIdentifier = @"Cell";

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

    // Configure the cell.

    NSLog(@"getting row: %i",indexPath.row);

    cell.textLabel.text = [[[iPodLibrary sortedArtistArray] objectAtIndex:indexPath.row] artistName];

    return cell;
}

Ошибка в этой строке:

cell.textLabel.text = [[[iPodLibrary sortedArtistArray] objectAtIndex:indexPath.row] artistName];

Я попытался создать массив с объектами Artist, которые я создал в RootViewController - и он работает отлично (можно прокручивать всю таблицу без сбоев)

Еще раз спасибо!

- Edit:

Интересно отметить, что я получаю разные ошибки в разное время:

В большинстве случаев это просто EXC_BAD_ACCESS в строке:

cell.textLabel.text = [[[iPodLibrary sortedArtistArray] objectAtIndex:indexPath.row] artistName];

Иногда это:

-[UIAutoRotatingWindow isEqualToString:]: unrecognized selector sent to instance 0x1baa80

А другой был связан с нераспознанным селектором RGB (очень странно).

Ответы [ 2 ]

0 голосов
/ 17 апреля 2011

Я думаю, что более вероятно, что ваша переменная iPodLibrary перевыпущена, чем массив. Вы должны устранить неполадки, разбив свой код на несколько строк и увидев, где он выходит из строя:

NSArray *artistArray = [iPodLibrary sortedArtistArray];
Artist *artist = [artistArray objectAtIndex:indexPath.row];
NSString *name = [artist artistName];
cell.textLabel.text = name;

Возможно ли, что ваша реализация initializeiPodLibraryParser возвращает объект с автоматическим освобождением? Не должно, так как это нарушает соглашение. Но было бы понятно, что это приведет к этой проблеме.

Когда вы звоните это:

iPodLibrary = [[iPodLibraryParser alloc] initializeiPodLibraryParser];

вы непосредственно присваиваете iPodLibrary ivar, поэтому его мутатор не вызывается и не имеет значения, что свойство помечено как сохраняемое. Если вы думаете, что это неявно сохраняется, скорее всего, вы переиздаете его где-то еще. Я обнаружил, что вы поймете свое собственное управление памятью, если будете использовать этот стиль для назначения свойств:

iPodLibraryParser *parser = [[iPodLibraryParser alloc] initializeiPodLibraryParser]; // retain count should be 1 if not autoreleased
[self setIpodLibrary:parser]; // retain count is now 2
[parser release]; // retain count is now 1, will go to zero when you release it in dealloc or viewDidUnload

Наконец, я бы переместил вашу iPodLibrary инициализацию с viewDidAppear на viewDidLoad:. Вот где вы должны инициализировать свою точку зрения. И вы должны очистить все, что инициализируете там в viewDidUnload, что будет вызвано в ситуации нехватки памяти.

0 голосов
/ 16 апреля 2011

Ваша проблема в том, что вы делаете это:

sortedArtistArray = [artistArray sortedArrayUsingDescriptors:sortingArray];

Метод sortedArrayUsingDescriptors возвращает объект с автоматическим освобождением, поэтому вы не должны удивляться, когда он будет выпущен на васбез предупреждения.

Более того, поскольку ваш init делает:

sortedArtistArray = [[NSArray alloc] init];

... и поскольку вы не освобождаете его до назначения, ваш кодтекущие экземпляры NSArray.Я хотел бы предложить следующие изменения:

  1. Сделать sortedArtistArray NSMutableArray*, например:

    NSMutableArray* sortedArtistArray;

  2. Не перезаписывайте ссылку на массив в parseiPodLibrary.Вместо этого просто скопируйте отсортированный набор данных в изменяемый массив, например:

    -(void)parseiPodLibrary{
    
        //.....
    
        NSArray* temp = [artistArray sortedArrayUsingDescriptors:sortingArray];
        [sortedArtistArray removeAllObjects];
        [sortedArtistArray addObjectsFromArray:temp];
    
    }
    
  3. Не вызывайте [iPodLibrary retain]; в viewDidAppear.Вы уже вызывали alloc / init для него, поэтому нет необходимости сохранять его снова.

  4. Убедитесь, что вы вызываете [iPodLibrary release]; в viewWillDisappear и [sortedArtistArray release]; вdealloc чтобы не допустить утечки памяти.

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