Видимо, я не знаю, как написать сеттер - PullRequest
2 голосов
/ 19 февраля 2011

У меня есть хороший объект, который описывает относительно большой набор данных. Я решил реализовать некоторые вспомогательные функции в объекте.

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

Например:

-(void) setNumber:(NSString *)number_in
{
    number = [number_in copy];
    title = @"Invoice ";
    title = [title stringByAppendingString:number];
}

Я знаю, что мне понадобится "title" как свойство в определенном формате. Название основано на числе, поэтому я создал сеттер для установки номера и заголовка одним ударом. (заголовок имеет синтезатор по умолчанию ... я не определяю его где-либо еще)

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

Здесь указано мое свойство:

@property (nonatomic, copy) NSString *number;
@property (nonatomic, copy) NSString *title;

Я пытался сохранить, но безрезультатно. Я настроил ведение журнала стека malloc и зарегистрировал это:

Alloc: Block address: 0x06054520 length: 32
Stack - pthread: 0xa003f540 number of frames: 30
    0: 0x903ba1dc in malloc_zone_malloc
    1: 0x102b80d in _CFRuntimeCreateInstance
    2: 0x102d745 in __CFStringCreateImmutableFunnel3
    3: 0x10824dd in _CFStringCreateWithBytesNoCopy
    4: 0xae222e in -[NSPlaceholderString initWithCStringNoCopy:length:freeWhenDone:]
    5: 0xaf9e8e in _NSNewStringByAppendingStrings
    6: 0xaf9a76 in -[NSString stringByAppendingString:]
    7: 0x112ba in -[Invoice setNumber:] at Invoice.m:25
    8: 0x11901 in -[Invoice copyWithZone:] at Invoice.m:47
    9: 0x107c7ca in -[NSObject(NSObject) copy]
   10: 0x1117632 in -[NSArray initWithArray:range:copyItems:]
   11: 0x107f833 in -[NSArray initWithArray:copyItems:]
   12: 0x5595 in -[InvoicesTableViewController wrapper:didRetrieveData:] at InvoicesTableViewController.m:96
   13: 0x4037 in -[Wrapper connectionDidFinishLoading:] at Wrapper.m:288
   14: 0xb17172 in -[NSURLConnection(NSURLConnectionReallyInternal) sendDidFinishLoading]
   15: 0xb170cb in _NSURLConnectionDidFinishLoading
   16: 0x18ca606 in _ZN19URLConnectionClient23_clientDidFinishLoadingEPNS_26ClientConnectionEventQueueE
   17: 0x1995821 in _ZN19URLConnectionClient26ClientConnectionEventQueue33processAllEventsAndConsumePayloadEP20XConnectionEventInfoI12XClientEvent18XClientEventParamsEl
   18: 0x18c0e3c in _ZN19URLConnectionClient13processEventsEv
   19: 0x18c0cb7 in _ZN17MultiplexerSource7performEv
   20: 0x10fd01f in __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__
   21: 0x105b28b in __CFRunLoopDoSources0
   22: 0x105a786 in __CFRunLoopRun
   23: 0x105a240 in CFRunLoopRunSpecific
   24: 0x105a161 in CFRunLoopRunInMode
   25: 0x1c29268 in GSEventRunModal
   26: 0x1c2932d in GSEventRun
   27: 0x39542e in UIApplicationMain
   28: 0x2199 in main at main.m:14
   29: 0x2115 in start

В итоге я получаю эту ошибку:

-[CFString release]: message sent to deallocated instance 0x4b5aee0

Заранее спасибо миллион:)

Ответы [ 2 ]

7 голосов
/ 19 февраля 2011

Используйте self.title, чтобы вызвать ваш синтезированный сеттер, а также сбросить старое значение для number.

- (void)setNumber:(NSString *)number_in
{
    [number release];
    number = [number_in copy];
    self.title = [NSString stringWithFormat:@"Invoice %@", number];
}
5 голосов
/ 19 февраля 2011

title автоматически освобождается, а number просачивается в программу.Чтобы написать полный установщик, вы должны сначала скопировать переданный объект, а затем сделать релиз.

-(void) setNumber:(NSString *)number_in {
    if (number == number_in) {
        return;
    }

    NSString *oldValue = number;
    number = [number_in copy];
    [oldValue release];

    self.title = [title stringByAppendingString:number];
}

Причина, по которой сначала выполняется копирование, а затем освобождение, заключается в том, что вызов copy неизменного объекта может вернуть тот же объект обратно вместо создания новой копии.Таким образом, если setNumber вызывается дважды с одним и тем же объектом, а number был сначала освобожден, он становится недействительным, а затем вызов copy для этого недействительного объекта может вызвать проблемы.

Проверка ifэто шаг оптимизации, который вы можете удалить, если хотите.

Кроме того, вы можете проверить эту статью о написании пользовательских сеттеров.

Как @tia и @Пометить отправили, если заголовок всегда зависит от значения числа, тогда заголовок должен быть readonly свойством.Модифицированный setNumber может выглядеть следующим образом:

- (void) setNumber:(NSString *)number_in {
    if (number == number_in) {
        return;
    }

    NSString *oldNumber = number;
    number = [number_in copy];
    [oldNumber release];

    NSString *oldTitle = title;
    title = [title stringByAppendingString:number];
    [oldTitle release];
}

Дополнительные проверки могут потребоваться для передачи nil number_in, например, когда nil передается stringByAppendingString, NSInvalidArgumentException Поднялся.Итак, вот финальная версия этого сеттера с этой проверкой,

- (void) setNumber:(NSString *)number_in {
    if (number == number_in) {
        return;
    }

    NSString *oldNumber = number;
    number = [number_in copy];
    [oldNumber release];

    if (number) {
        NSString *oldTitle = title;
        title = [title stringByAppendingString:number];
        [oldTitle release];
    }
}
...