Класс работает не правильно.Как сделать это лучше? - PullRequest
2 голосов
/ 27 апреля 2011

Я написал класс и хочу показать его вам ...

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

Articles.h

#import <Foundation/Foundation.h>

@interface Article : NSObject {
    BOOL favorite;
    NSMutableString * title;  
    NSMutableString * summary;  
    NSMutableString * mainLink;  
    NSMutableString * pubDate;  
    NSMutableString * author;  
    NSMutableString * imageLink;  
}

@property (nonatomic, assign) BOOL favorite;  
@property (nonatomic, retain) NSMutableString * title;  
@property (nonatomic, retain) NSMutableString * summary;  
@property (nonatomic, retain) NSMutableString * mainLink;   
@property (nonatomic, retain) NSMutableString * pubDate;  
@property (nonatomic, retain) NSMutableString * author;  
@property (nonatomic, retain) NSMutableString * imageLink;  

- (id)initWithValues:(NSString *) inTitle mainLink:(NSString *) inMainLink summary:(NSString *) inSummary
             pubDate:(NSString *) inPubDate author:(NSString *) inAuthor imageLink:(NSString *) inImageLink;


//Setter methods
- (void)setTheTitle:(NSString *) inTitle;
- (void)setTheMainLink:(NSString *) inMainLink;
- (void)setTheSummary:(NSString *) inSummary;
- (void)setThePubDate:(NSString *) inPubDate;
- (void)setTheAuthor:(NSString *) inAuthor;
- (void)setTheImageLink:(NSString *)inImageLink;

@end

Articles.m

#import "Articles.h"

@implementation Article

@synthesize favorite;  
@synthesize title;  
@synthesize summary;  
@synthesize mainLink;
@synthesize pubDate;  
@synthesize author;  
@synthesize imageLink;  

- (void)dealloc {
    NSLog(@"article dealloc \n");
    [self.title release];
    [self.mainLink release];
    [self.summary release];
    [self.pubDate release];
    [self.author release];
    [self.imageLink release];

    [super dealloc];
}



- (id)init {

    self = [super init];
    if(self) {
      // set your properties...
      self.title     = [[[NSMutableString alloc] init] autorelease];
      self.mainLink  = [[[NSMutableString alloc] init] autorelease];
      self.summary   = [[[NSMutableString alloc] init] autorelease];
      self.pubDate   = [[[NSMutableString alloc] init] autorelease];
      self.author    = [[[NSMutableString alloc] init] autorelease];
      self.imageLink = [[[NSMutableString alloc] init] autorelease];
      self.favorite = NO;
    }
    return self;
}

- (id)initWithValues:(NSString *) inTitle mainLink:(NSString *) inMainLink summary:(NSString *) inSummary
            pubDate:(NSString *) inPubDate author:(NSString *) inAuthor imageLink:(NSString *) inImageLink
{
    self = [super init];
    if(self) {
        // set your properties ...
        if (inTitle != nil) {
            self.title = inTitle;
        }

        if (inMainLink != nil) {
            self.mainLink = inMainLink ;
        }

        if (inSummary != nil) {
            self.summary = inSummary;
        }

        if (inPubDate != nil) {
            self.pubDate = inPubDate;
        }

        if (inAuthor != nil) {
            self.author = inAuthor ;
        }

        if (inImageLink != nil) {
            self.imageLink = inImageLink ;
        }

        self.favorite = NO;
    }

    return self;
}


@end

ДОБАВЛЕНО:

Смотри, у меня есть NSXMLParser в моем основном классе. В основном файле .h я пишу:

Article * currentArticle;

Теперь в .m файле, когда синтаксический анализатор didStartElement выделяю и инициализирую Article, в синтаксическом анализаторе didEndElement я отпускаю его [self.currentArticle release]; но деллок не звонит.

- (void) parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI 
                                        qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict {
    // Copy current Xml Element name.
    currentElement = [elementName copy];
    if ([elementName isEqualToString:@"item"]) {
        // Clear out our story item caches...
        self.currentArticle = [[Article alloc] init];
    }
    [currentElement release];

}

ДОБАВЛЕННЫЙ РЕЛИЗ ДЛЯ ТЕСТА

- (void) parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI 
                                        qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict {
    // Copy current Xml Element name.
    currentElement = [elementName copy];
    if ([elementName isEqualToString:@"item"]) {
        // Clear out our story item caches...
        self.currentArticle = [[Article alloc] init];
        [self.currentArticle release];
    }
    [currentElement release];

}

посмотрите, я добавил [self.currentArticle release]; сразу после инициализации и поставил здесь точку останова ... Когда мое приложение в первый раз входит в эту часть кода, оно вызывает init, но не вызывает release, а во второй раз вызывает release? Но почему ? Это не правильно

ПОЧЕМУ Я НЕ ИСПОЛЬЗУЮ AUTORELEASE !!!

 self.title     = [[[NSMutableString alloc] init] autorelease];
    self.mainLink  = [[[NSMutableString alloc] init] autorelease];
    self.summary   = [[[NSMutableString alloc] init] autorelease];
    self.pubDate   = [[[NSMutableString alloc] init] autorelease];
    self.author    = [[[NSMutableString alloc] init] autorelease];
    self.imageLink = [[[NSMutableString alloc] init] autorelease];

Я не использую autorelease в этой части кода, потому что я прочитал, что это приводит к пореям, потому что когда я пишу autorelease, выпуски объектов в конце работы приложения! Я пишу ???

Спасибо !!!

Ответы [ 3 ]

2 голосов
/ 27 апреля 2011

Вы можете удалить каждый сеттер, как

- (void)setTheSummary:(NSString *) inSummary
{

    if (self.summary != nil) {
        [self.summary release];
    }

    self.summary = [[NSMutableString alloc] initWithString:inSummary];
}

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

self.title = newTitle;

Это приведет к повторному вводу newTitle, назначению его заголовку и освобождению предыдущего (если оно есть) значения.

EDIT

Если вы установите свойства, такие как

self.title = [[NSMutableString alloc] init];

экземпляр изменяемой строки будет сохранен, поэтому будут утечки.

Параметр «Сохранить» увеличивает количество сохраняемых данных на 1, это происходит через объявление свойства, и оно увеличивается на единицу, вызывая init.

Измените его на:

self.title = [[[NSMutableString alloc] init] autorelease];

РЕДАКТИРОВАТЬ 2

Измените вашу инициализацию этих конструкций:

if (inTitle == nil) {
    self.title = [[NSMutableString alloc] init];
}
else
{
    [self.title release];
    self.title = [[NSMutableString alloc] initWithString:inTitle];
}

Кому:

if (inTitle != nil) {
    self.title = inTitle;
}

Теперь добавьте

self = [self init];

и удалить

[super init];

в начале вашего метода init initWithValues; Это сначала инициализирует свойства для вас, уменьшает дублирование кода и уменьшает ваш класс. Удаление [super init] необходимо вызвать инициализатор NSObject только один раз, вы делаете это, вызывая self = [self init];.

Вы создали с этим шаблоном так называемый назначенный инициализатор. Вы можете прочитать больше об инициализаторах здесь .

РЕДАКТИРОВАТЬ 3

Чтобы сделать ваши инициализаторы идеальными, вы должны написать их так:

- (id)init 
{
    self = [super init];
    if(self) {
       // set your properties...
    }
    return self;
}

и

- (id)initWithValues:(NSString *) inTitle mainLink:(NSString *) inMainLink summary:(NSString *) inSummary
            pubDate:(NSString *) inPubDate author:(NSString *) inAuthor imageLink:(NSString *) inImageLink
{
    self = [self init];
    if(self) {
       // set properties with parameters ...
    }
    return self;
}

Этот шаблон позволит вам реагировать на ошибки, которые могут возникнуть в назначенном вами инициализаторе и / или в инициализаторах, вызывающих иерархию наследования. Это обеспечит возврат nil, если что-то пойдет не так, и вы не установите свойства для ошибочного экземпляра.

2 голосов
/ 27 апреля 2011

Для начала я бы заменил каждый

   if (self.imageLink !=nil) {
        [self.imageLink release];
        self.imageLink = nil;
    }

в dealloc с

[imageLink release];

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

Редактировать

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

Где-то в вашем коде у вас есть что-то вроде этого:

Article *article = [[Article alloc] init];

Вы говорите, что называете выпуск статьи, поэтому у вас также будет

[article release];

где-то еще в вашем коде.

Теперь, почему не вызывается dealloc, даже если вы вызываете release? Я думаю, что вы делаете что-то вроде этого между:

NSMutableArray *array = [NSMutableArray arrayWithCapacity: 0];
[array addObject: article];

Это на самом деле сохраняет статью и может быть причиной того, что она никогда не будет выпущена. Как исправить? Как это:

[array removeObject: article];

Надеюсь, это поможет.

1 голос
/ 27 апреля 2011

Несмотря на то, что с вашим кодом происходит множество проблем, эта часть вызывает утечки памяти:

self.title = [[NSMutableString alloc] init];

Почему? Свойство title определяется как:

@property (nonatomic, retain) NSMutableString * title;

Следовательно, установщик увеличивает счет удержания до 2.

В dealloc счет сохранения для title уменьшается только на единицу, поэтому объект остается живым после освобождения article.

Быстрое исправление:

self.title = [[[NSMutableString alloc] init] autorelease];

Редактировать: вот почему dealloc никогда не вызывают:

self.currentArticle = [[Article alloc] init];

Опять же, взгляните на счет удержания: alloc устанавливает счет удержания на 1. Затем - я предполагаю, что currentArticle определен как (nonatomic, retain) - он сохраняется снова, счетчик сохранения теперь равен 2. В методе dealloc - я полагаю снова - вы отпускаете currentArticle, поэтому оставьте счет 1. Объект не будет освобожден, если счет не равен 0!

Быстрое исправление: то же, что и выше

self.currentArticle = [[[Article alloc] init] autorelease];
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...